diff -ruN postgresql-7.4.13-old/INSTALL_PGCLUSTER postgresql-7.4.13/INSTALL_PGCLUSTER
--- postgresql-7.4.13-old/INSTALL_PGCLUSTER	1970-01-01 01:00:00.000000000 +0100
+++ postgresql-7.4.13/INSTALL_PGCLUSTER	2006-08-05 16:53:43.000000000 +0200
@@ -0,0 +1,276 @@
+PGCluster Installation Instructions
+
+=============================================================
+1. Installation
+=============================================================
+
+1-1. Install Cluster DB Server, Replication Server & Load Balancer
+----------------------------------------------------------------
+$ cd $source_dir 
+$ ./configure
+$ gmake
+$ su
+# gmake install
+# chown -R postgres /usr/local/pgsql
+----------------------------------------------------------------
+
+=============================================================
+2. Initialize DB
+=============================================================
+$ su
+# adduser postgres
+# mkdir /usr/local/pgsql/data
+# chown postgres /usr/local/pgsql/data
+# su - postgres
+$ /usr/local/pgsql/bin/initdb -D /usr/local/pgsql/data
+
+
+=============================================================
+3. Configuration
+=============================================================
+(EX.System Composition)
+
+                        |
+             ((Load Balance Server))
+             ( hostname: lb.hoo.com)
+             ( receive port:5432   )
+             ( recovery port:6001  )
+                        |
+----------+-------------+------------+----------
+          |                          |
+ ((  Cluster DB 1    ))    ((  Cluster DB 2    ))
+ ( hostname:c1.hoo.com)    ( hostname:c2.hoo.com)
+ ( receive port: 5432 )    ( receive port:5432  )
+ ( recovery port:7001 )    ( recovery port 7002 )
+          |                          |
+----------+-------------+------------+----------
+                        |
+             ((Replication Server))
+             ( hostname:pgr.hoo.com)
+             ( receive port:8001   )
+             ( recovery port:8101  )
+
+
+3-1. Load Balance Server
+
+The setup file of load balance server is copied from the sample file and edited.
+(the sample file is installed '/usr/local/pgsql/etc' in default)
+----------------------------------------------------------------
+$cd /usr/local/pgsql/etc
+$cp pglb.conf.sample pglb.conf
+----------------------------------------------------------------
+
+In the case of the above system composition example,
+the setup example of pglb.conf file is as the following 
+
+#============================================================
+#          Load Balance Server configuration file
+#-------------------------------------------------------------
+# file: pglb.conf
+#-------------------------------------------------------------
+# This file controls:
+#       o which hosts are db cluster server
+#       o which port  use connect to db cluster server
+#       o how many connections are allowed on each DB server
+#============================================================
+#-------------------------------------------------------------
+# set cluster DB server information
+#		o Host_Name : hostname
+#		o Port : connection for postmaster
+#		o Max_Connection : maximun number of connection to postmaster
+#-------------------------------------------------------------
+<Cluster_Server_Info>
+    <Host_Name>   c1.hoo.com  </Host_Name>
+    <Port>        5432                </Port>
+    <Max_Connect> 32                   </Max_Connect>
+</Cluster_Server_Info>
+<Cluster_Server_Info>
+    <Host_Name>   c2.hoo.com  </Host_Name>
+    <Port>        5432                </Port>
+    <Max_Connect> 32                   </Max_Connect>
+</Cluster_Server_Info>
+#-------------------------------------------------------------
+# set Load Balance server information
+#		o Receive_Port : connection from client
+#		o Recovery_Port : connection for recovery process
+#		o Max_Cluster_Num : maximun number of cluster DB servers
+#		o Use_Connection_Pooling : use connection pool [yes/no] 
+#		o Max_Pool_Each_Server : number of pool connections/DB server
+#-------------------------------------------------------------
+<Receive_Port>    5432                </Receive_Port>
+<Recovery_Port>   6001                </Recovery_Port>
+<Max_Cluster_Num> 128                 </Max_Cluster_Num>
+<Use_Connection_Pooling> yes          </Use_Connection_Pooling>
+<Max_Pool_Each_Server> 1              </Max_Pool_Each_Server>
+
+3-2. Cluster DB Server
+
+The Cluster DB server need edit two configuration files
+('pg_hba.conf' and 'cluster.conf').
+These files are create under the $PG_DATA directory after 'initdb'.
+
+A. pg_hba.conf
+Permission to connect DB via IP connectoins is need for this system.
+
+B. cluster.conf
+In the case of the above system composition example,
+the setup example of cluster.conf file is as the following 
+
+#============================================================
+#          Cluster DB Server configuration file
+#-------------------------------------------------------------
+# file: cluster.conf
+#-------------------------------------------------------------
+# This file controls:
+#       o which hosts & port are replication server
+#       o which port use for replication request to replication server
+#       o which command use for recovery function
+#
+#============================================================
+#-------------------------------------------------------------
+# set cluster DB server information
+#		o Host_Name : hostname
+#		o Port : connection for postmaster
+#		o Recovery_Port : connection for recovery process
+#-------------------------------------------------------------
+<Replicate_Server_Info>
+	<Host_Name> pgr.hoo.com </Host_Name>
+	<Port> 8001 </Port>
+	<Recovery_Port> 8101 </Recovery_Port>
+</Replicate_Server_Info>
+#-------------------------------------------------------------
+# set Cluster DB Server information
+#		o Recovery_Port : connection for recovery
+#		o Rsync_Path : path of rsync command 
+#		o Rsync_Option : file transfer option for rsync
+#       o When_Stand_Alone : When all replication servers fell,
+#                            you can set up two kinds of permittion,
+#                            "real_only" or "read_write".
+#-------------------------------------------------------------
+<Recovery_Port>    7001           </Recovery_Port>
+<Rsync_Path>       /usr/bin/rsync </Rsync_Path>
+<Rsync_Option>     ssh -1         </Rsync_Option>
+<When_Stand_Alone> read_only      </When_Stand_Alone>
+#-------------------------------------------------------------
+# set partitional replicate control information
+#     set DB name and Table name to stop reprication
+#       o DB_Name : DB name
+#       o Table_Name : table name
+#-------------------------------------------------------------
+#<Not_Replicate_Info>
+#    <DB_Name>     test_db      </DB_Name>
+#    <Table_Name>  log_table    </Table_Name>
+#</Not_Replicate_Info>
+
+3-3. Replication Server
+
+The setup file of replication server is copied from the sample file and edited.
+(the sample file is installed '/usr/local/pgsql/etc' in default)
+----------------------------------------------------------------
+$cd /usr/local/pgsql/etc
+$cp pgreplicate.conf.sample pgreplicate.conf
+----------------------------------------------------------------
+In the case of the above system composition example,
+the setup example of pgreplicate.conf file is as the following 
+
+#============================================================
+#                 PGReplicate configuration file
+#-------------------------------------------------------------
+# file: pgreplicate.conf
+#-------------------------------------------------------------
+# This file controls:
+#       o which hosts & port are cluster server
+#       o which port use for replication request from cluster server
+#============================================================
+#-------------------------------------------------------------
+# set cluster DB server information
+#		o Host_Name : hostname
+#		o Port : connection for postmaster
+#		o Recovery_Port : connection for recovery
+#-------------------------------------------------------------
+<Cluster_Server_Info>
+    <Host_Name>      c1.hoo.com    </Host_Name>
+    <Port>           5432          </Port>
+    <Recovery_Port>  7001          </Recovery_Port>
+</Cluster_Server_Info>
+<Cluster_Server_Info>
+    <Host_Name>      c2.hoo.com    </Host_Name>
+    <Port>           5432          </Port>
+    <Recovery_Port>  7001          </Recovery_Port>
+</Cluster_Server_Info>
+#-------------------------------------------------------------
+# set Load Balance server information
+#		o Host_Name : hostname
+#		o Recovery_Port : connection for recovery
+#-------------------------------------------------------------
+<LoadBalance_Server_Info>
+    <Host_Name>       lb.hoo.com   </Host_Name>
+    <Recovery_Port>   6001         </Recovery_Port>
+</LoadBalance_Server_Info>
+#-------------------------------------------------------------
+# set PGReplicate server information
+#		o Replicate_Port : connection for reprication
+#		o Recovery_Port : connection for recovery
+#-------------------------------------------------------------
+<Replication_Port>    8001         </Replication_Port>
+<Recovery_Port>       8101         </Recovery_Port>
+
+
+=============================================================
+4. Start Up / Stop
+=============================================================
+
+4-1. replication server
+
+A. Start replication server
+----------------------------------------------------------------
+$ /usr/local/pgsql/bin/pgreplicate -D /usr/local/pgsql/etc
+----------------------------------------------------------------
+
+B. Stop replication server
+----------------------------------------------------------------
+$ /usr/local/pgsql/bin/pgreplicate -D /usr/local/pgsql/etc stop
+----------------------------------------------------------------
+
+usage: pgreplicate [-D path_of_config_file] [-W path_of_work_files] [-U login us
+er][-l][-n][-v][-h][stop]
+    -l: print error logs in the log file.
+    -n: don't run in daemon mode.
+    -v: debug mode. need '-n' flag
+    -h: print this help
+    stop: stop pgreplicate
+(config file default path: ./pgreplicate.conf)
+
+4-2. cluster DB server
+$PG_HOME = /usr/local/pgsql
+$PG_DATA = /usr/local/pgsql/data
+
+A. Start cluster DB server
+----------------------------------------------------------------
+$ /usr/local/pgsql/bin/pg_ctl -D /usr/local/pgsql/data -o "-i" start
+----------------------------------------------------------------
+
+B. Stop cluster DB server
+----------------------------------------------------------------
+$ /usr/local/pgsql/bin/pg_ctl -D /usr/local/pgsql/data stop
+----------------------------------------------------------------
+
+4-3. load balance server
+
+A. Start load balance server
+----------------------------------------------------------------
+$ /usr/local/pgsql/bin/pglb -D /usr/local/pgsql/etc
+----------------------------------------------------------------
+
+B. Stop load balance server
+----------------------------------------------------------------
+$ /usr/local/pgsql/bin/pglb -D /usr/local/pgsql/etc stop
+----------------------------------------------------------------
+
+usage: pglb [-D path_of_config_file] [-W path_of_work_files] [-n][-v][-h][stop]
+    -l: print error logs in the log file.
+    -n: don't run in daemon mode.
+    -v: debug mode. need '-n' flag
+    -h: print this help
+    stop: stop pglb
+    (config file default path: ./pglb.conf)
diff -ruN postgresql-7.4.13-old/README_PGCLUSTER postgresql-7.4.13/README_PGCLUSTER
--- postgresql-7.4.13-old/README_PGCLUSTER	1970-01-01 01:00:00.000000000 +0100
+++ postgresql-7.4.13/README_PGCLUSTER	2006-08-05 16:53:43.000000000 +0200
@@ -0,0 +1,46 @@
+PGCluster: Multi-Master Synchronous Replication System for PostgreSQL
+===========================================================
+
+PGCluster is a multi-master and synchronous replication system that supports load balancing of PostgreSQL.
+
+Changed:
+	src/Makefile.global.in
+	src/backend/Makefile
+	src/backend/libpq/Makefile
+	src/backend/access/transam/clog.c
+	src/backend/access/transam/xact.c
+	src/backend/commands/analyze.c
+	src/backend/commands/copy.c
+	src/backend/commands/sequence.c
+	src/backend/executor/functions.c
+	src/backend/postmaster/postmaster.c
+	src/backend/storage/lmgr/lock.c
+	src/backend/tcop/postgres.c
+	src/backend/utils/adt/float.c
+	src/backend/utils/adt/misc.c
+	src/backend/utils/adt/nabstime.c
+	src/backend/utils/error/assert.c
+	src/backend/utils/error/elog.c
+	src/backend/utils/fmgr/dfmgr.c
+	src/backend/utils/mb/mbutils.c
+	src/bin/initdb/initdb.sh
+
+Added:
+	src/include/replicate.h
+	src/include/replicate_com.h
+	src/backend/libpq/pgcluster.c
+	src/backend/libpq/watch_dog.c
+	src/backend/libpq/cluster.conf.sample
+	src/backend/utils/pgcluster/*
+	src/pgcluster/*
+
+The latest version of this software may be obtained at
+http://hiroshima.sraw.co.jp/people/mitani/jpug/pgcluster/en/current/last_night.html
+<for Japanese>
+http://hiroshima.sraw.co.jp/people/mitani/jpug/pgcluster/current/last_night.html
+
+For more information look at my web
+site located at 
+http://hiroshima.sraw.co.jp/people/mitani/jpug/pgcluster/en/
+<for Japanese>
+http://hiroshima.sraw.co.jp/people/mitani/jpug/pgcluster/
diff -ruN postgresql-7.4.13-old/configure postgresql-7.4.13/configure
--- postgresql-7.4.13-old/configure	2006-05-21 23:54:01.000000000 +0200
+++ postgresql-7.4.13/configure	2006-08-05 16:53:43.000000000 +0200
@@ -872,6 +872,7 @@
   --without-readline      do not use Readline
   --without-zlib          do not use Zlib
   --with-gnu-ld           assume the C compiler uses GNU ld default=no
+  --with-pgcluster        build with PGCluster support
 
 Some influential environment variables:
   CC          C compiler command
@@ -3572,7 +3573,35 @@
 fi
 
 
+#
+# Replication
+#
+# Check whether --with-pgcluster was given.
+if test "${with_pgcluster+set}" = set; then
+  withval="$with_pgcluster"
+
+  case $withval in
+    yes)
+      :
+      ;;
+    no)
+      :
+      ;;
+    *)
+      { { echo "$as_me:$LINENO: error: no argument expected for --with-pgcluster option" >&5
+echo "$as_me: error: no argument expected for --with-pgcluster option" >&2;}
+   { (exit 1); exit 1; }; }
+      ;;
+  esac
+
+else
+  with_pgcluster=yes
 
+cat >>confdefs.h <<\_ACEOF
+#define USE_REPLICATION 1
+_ACEOF
+
+fi;
 
 
 #
diff -ruN postgresql-7.4.13-old/src/Makefile postgresql-7.4.13/src/Makefile
--- postgresql-7.4.13-old/src/Makefile	2002-09-05 20:28:45.000000000 +0200
+++ postgresql-7.4.13/src/Makefile	2006-08-05 16:53:43.000000000 +0200
@@ -21,11 +21,13 @@
 	$(MAKE) -C interfaces $@
 	$(MAKE) -C bin $@
 	$(MAKE) -C pl $@
+	$(MAKE) -C pgcluster $@
 
 install-all-headers:
 	$(MAKE) -C include $@
 
 clean:
+	$(MAKE) -C pgcluster $@
 	$(MAKE) -C port $@
 	$(MAKE) -C backend $@
 	$(MAKE) -C include $@
@@ -37,6 +39,7 @@
 	$(MAKE) -C utils $@
 
 distclean maintainer-clean:
+	-$(MAKE) -C pgcluster $@
 	-$(MAKE) -C port $@
 	-$(MAKE) -C backend $@
 	-$(MAKE) -C include $@
diff -ruN postgresql-7.4.13-old/src/Makefile.global.in postgresql-7.4.13/src/Makefile.global.in
--- postgresql-7.4.13-old/src/Makefile.global.in	2003-12-20 00:29:29.000000000 +0100
+++ postgresql-7.4.13/src/Makefile.global.in	2006-08-05 16:53:43.000000000 +0200
@@ -178,6 +178,7 @@
 ifeq ($(GCC), yes)
   CFLAGS += -Wall -Wmissing-prototypes -Wmissing-declarations
 endif
+CFLAGS += -DUSE_REPLICATION
 
 # Kind-of compilers
 
diff -ruN postgresql-7.4.13-old/src/backend/Makefile postgresql-7.4.13/src/backend/Makefile
--- postgresql-7.4.13-old/src/backend/Makefile	2003-03-21 18:18:34.000000000 +0100
+++ postgresql-7.4.13/src/backend/Makefile	2006-08-05 16:53:43.000000000 +0200
@@ -135,6 +135,7 @@
 	$(INSTALL_DATA) $(srcdir)/libpq/pg_hba.conf.sample $(DESTDIR)$(datadir)/pg_hba.conf.sample
 	$(INSTALL_DATA) $(srcdir)/libpq/pg_ident.conf.sample $(DESTDIR)$(datadir)/pg_ident.conf.sample
 	$(INSTALL_DATA) $(srcdir)/utils/misc/postgresql.conf.sample $(DESTDIR)$(datadir)/postgresql.conf.sample
+	$(INSTALL_DATA) $(srcdir)/utils/pgcluster/cluster.conf.sample $(DESTDIR)$(datadir)/cluster.conf.sample
 
 install-bin: postgres $(POSTGRES_IMP) installdirs
 	$(INSTALL_PROGRAM) postgres$(X) $(DESTDIR)$(bindir)/postgres$(X)
@@ -174,7 +175,8 @@
 	rm -f $(DESTDIR)$(datadir)/pg_hba.conf.sample \
 	      $(DESTDIR)$(datadir)/pg_service.conf.sample \
 	      $(DESTDIR)$(datadir)/pg_ident.conf.sample \
-              $(DESTDIR)$(datadir)/postgresql.conf.sample
+              $(DESTDIR)$(datadir)/postgresql.conf.sample \
+              $(DESTDIR)$(datadir)/cluster.conf.sample
 
 
 ##########################################################################
diff -ruN postgresql-7.4.13-old/src/backend/access/transam/clog.c postgresql-7.4.13/src/backend/access/transam/clog.c
--- postgresql-7.4.13-old/src/backend/access/transam/clog.c	2003-08-04 04:39:57.000000000 +0200
+++ postgresql-7.4.13/src/backend/access/transam/clog.c	2006-08-05 16:53:43.000000000 +0200
@@ -30,6 +30,9 @@
 #include "storage/lwlock.h"
 #include "miscadmin.h"
 
+#ifdef USE_REPLICATION
+#include "replicate.h"
+#endif /* USE_REPLICATION */
 
 /*
  * Defines for CLOG page and segment sizes.  A page is the same BLCKSZ
@@ -290,6 +293,10 @@
 	 */
 	cutoffPage = TransactionIdToPage(oldestXact);
 	SimpleLruTruncate(ClogCtl, cutoffPage);
+#ifdef USE_REPLICATION
+	/* Perform a forced CHECKPOINT */
+	CreateCheckPoint(false, true);
+#endif  /* USE_REPLICATION */
 }
 
 
diff -ruN postgresql-7.4.13-old/src/backend/access/transam/xact.c postgresql-7.4.13/src/backend/access/transam/xact.c
--- postgresql-7.4.13-old/src/backend/access/transam/xact.c	2006-05-21 22:06:43.000000000 +0200
+++ postgresql-7.4.13/src/backend/access/transam/xact.c	2006-08-05 16:53:43.000000000 +0200
@@ -170,6 +170,9 @@
 #include "utils/relcache.h"
 #include "pgstat.h"
 
+#ifdef USE_REPLICATION
+#include "replicate.h"
+#endif /* USE_REPLICATION */
 
 static void AbortTransaction(void);
 static void AtAbort_Cache(void);
@@ -1877,3 +1880,14 @@
 {
 	_RollbackFunc = NULL;
 }
+
+#ifdef USE_REPLICATION
+void
+PGR_Reload_Start_Time(void)
+{
+	TransactionState s = CurrentTransactionState;
+	if (s == NULL)
+		return;
+	s->startTime = GetCurrentAbsoluteTimeUsec(&(s->startTimeUsec));
+}
+#endif /* USE_REPLICATION */
diff -ruN postgresql-7.4.13-old/src/backend/commands/analyze.c postgresql-7.4.13/src/backend/commands/analyze.c
--- postgresql-7.4.13-old/src/backend/commands/analyze.c	2003-10-18 17:38:06.000000000 +0200
+++ postgresql-7.4.13/src/backend/commands/analyze.c	2006-08-05 16:53:43.000000000 +0200
@@ -37,6 +37,9 @@
 #include "utils/syscache.h"
 #include "utils/tuplesort.h"
 
+#ifdef USE_REPLICATION
+#include "replicate.h"
+#endif /* USE_REPLICATION */
 
 /*
  * Analysis algorithms supported
@@ -713,7 +716,11 @@
 	/* random() can produce endpoint values, try again if so */
 	do
 	{
+#ifdef USE_REPLICATION
+		z = (long) PGR_Random();
+#else
 		z = random();
+#endif /* USE_REPLICATION */
 	} while (z <= 0 || z >= MAX_RANDOM_VALUE);
 	return (double) z / (double) MAX_RANDOM_VALUE;
 }
diff -ruN postgresql-7.4.13-old/src/backend/commands/copy.c postgresql-7.4.13/src/backend/commands/copy.c
--- postgresql-7.4.13-old/src/backend/commands/copy.c	2006-05-21 22:06:43.000000000 +0200
+++ postgresql-7.4.13/src/backend/commands/copy.c	2006-08-05 16:53:43.000000000 +0200
@@ -48,6 +48,9 @@
 #include "utils/lsyscache.h"
 #include "utils/syscache.h"
 
+#ifdef USE_REPLICATION
+#include "replicate.h"
+#endif /* USE_REPLICATION */
 
 #define ISOCTAL(c) (((c) >= '0') && ((c) <= '7'))
 #define OCTVALUE(c) ((c) - '0')
@@ -383,6 +386,12 @@
 			fread(databuf, datasize, 1, copy_file);
 			if (feof(copy_file))
 				fe_eof = true;
+#ifdef USE_REPLICATION
+			if ((PGCluster_Info != NULL) && (!fe_eof))
+			{
+				PGR_Set_Copy_Data(PGCluster_Info->PGRCopyData,databuf,datasize,0);
+			}
+#endif /* USE_REPLICATION */
 			break;
 		case COPY_OLD_FE:
 			if (pq_getbytes((char *) databuf, datasize))
@@ -392,6 +401,12 @@
 						(errcode(ERRCODE_CONNECTION_FAILURE),
 						 errmsg("unexpected EOF on client connection")));
 			}
+#ifdef USE_REPLICATION
+			if (PGCluster_Info != NULL)
+			{
+				PGR_Set_Copy_Data(PGCluster_Info->PGRCopyData,databuf,datasize,0);
+			}
+#endif /* USE_REPLICATION */
 			break;
 		case COPY_NEW_FE:
 			while (datasize > 0 && !fe_eof)
@@ -416,6 +431,12 @@
 					switch (mtype)
 					{
 						case 'd':		/* CopyData */
+#ifdef USE_REPLICATION
+							if ((PGCluster_Info != NULL) && (!fe_eof))
+							{
+								PGR_Set_Copy_Data(PGCluster_Info->PGRCopyData,copy_msgbuf->data,copy_msgbuf->len,0);
+							}
+#endif /* USE_REPLICATION */
 							break;
 						case 'c':		/* CopyDone */
 							/* COPY IN correctly terminated by frontend */
@@ -453,6 +474,21 @@
 			}
 			break;
 	}
+#if 0
+#ifdef USE_REPLICATION
+	if ((PGCluster_Info != NULL) &&
+		(copy_dest == COPY_NEW_FE))
+	{
+		PGR_Set_Copy_Data(PGCluster_Info->PGRCopyData,copy_msgbuf->data,copy_msgbuf->len,0);
+	}
+#endif /* USE_REPLICATION */
+#ifdef USE_REPLICATION
+	if ((PGCluster_Info != NULL) && (fe_eof))
+	{
+		PGR_Set_Copy_Data(PGCluster_Info->PGRCopyData,NULL,0,1);
+	}
+#endif /* USE_REPLICATION */
+#endif
 }
 
 static int
@@ -464,6 +500,9 @@
 	{
 		case COPY_FILE:
 			ch = getc(copy_file);
+#ifdef USE_REPLICATION
+			PGR_Set_Copy_Char(ch);
+#endif /* USE_REPLICATION */
 			break;
 		case COPY_OLD_FE:
 			ch = pq_getbyte();
@@ -474,6 +513,9 @@
 						(errcode(ERRCODE_CONNECTION_FAILURE),
 						 errmsg("unexpected EOF on client connection")));
 			}
+#ifdef USE_REPLICATION
+			PGR_Set_Copy_Char(ch);
+#endif /* USE_REPLICATION */
 			break;
 		case COPY_NEW_FE:
 			{
@@ -513,6 +555,9 @@
 	{
 		case COPY_FILE:
 			ch = getc(copy_file);
+#ifdef USE_REPLICATION
+			PGR_Set_Copy_Char(ch);
+#endif /* USE_REPLICATION */
 			break;
 		case COPY_OLD_FE:
 			ch = pq_peekbyte();
@@ -523,6 +568,9 @@
 						(errcode(ERRCODE_CONNECTION_FAILURE),
 						 errmsg("unexpected EOF on client connection")));
 			}
+#ifdef USE_REPLICATION
+			PGR_Set_Copy_Char(ch);
+#endif /* USE_REPLICATION */
 			break;
 		case COPY_NEW_FE:
 			{
@@ -1848,13 +1896,13 @@
 					if (c != '\r')
 						ereport(ERROR,
 								(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-								 errmsg("end-of-copy marker corrupt")));
+								 errmsg("end-of-copy marker corrupt1")));
 				}
 				c = CopyGetChar();
 				if (c != '\r' && c != '\n')
 					ereport(ERROR,
 							(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-							 errmsg("end-of-copy marker corrupt")));
+							 errmsg("end-of-copy marker corrupt2")));
 				if ((eol_type == EOL_NL && c != '\n') ||
 					(eol_type == EOL_CRNL && c != '\n') ||
 					(eol_type == EOL_CR && c != '\r'))
@@ -1906,6 +1954,12 @@
 				break;			/* out of outer loop */
 		}
 	} /* end of outer loop */
+#ifdef USE_REPLICATION
+	if ((PGCluster_Info != NULL) && (result == true))
+	{
+		PGR_Set_Copy_Data(PGCluster_Info->PGRCopyData,NULL,0,1);
+	}
+#endif /* USE_REPLICATION */
 
 	/*
 	 * Done reading the line.  Convert it to server encoding.
@@ -1930,7 +1984,6 @@
 			appendBinaryStringInfo(&line_buf, cvt, strlen(cvt));
 		}
 	}
-
 	return result;
 }
 
diff -ruN postgresql-7.4.13-old/src/backend/commands/sequence.c postgresql-7.4.13/src/backend/commands/sequence.c
--- postgresql-7.4.13-old/src/backend/commands/sequence.c	2004-04-06 18:39:40.000000000 +0200
+++ postgresql-7.4.13/src/backend/commands/sequence.c	2006-08-05 16:53:43.000000000 +0200
@@ -24,6 +24,9 @@
 #include "utils/acl.h"
 #include "utils/builtins.h"
 
+#ifdef USE_REPLICATION
+#include "replicate.h"
+#endif /* USE_REPLICATION */
 /*
  * We don't want to log each fetching of a value from a sequence,
  * so we pre-log a few fetches in advance. In the event of
@@ -388,6 +391,9 @@
 				rescnt = 0;
 	bool		logit = false;
 
+#ifdef USE_REPLICATION
+	Xlog_Check_Replicate(CMD_UTILITY);
+#endif /* USE_REPLICATION */
 	sequence = makeRangeVarFromNameList(textToQualifiedNameList(seqin,
 															 "nextval"));
 
@@ -626,6 +632,10 @@
 	Buffer		buf;
 	Form_pg_sequence seq;
 
+#ifdef USE_REPLICATION
+	Xlog_Check_Replicate(CMD_UTILITY);
+#endif /* USE_REPLICATION */
+
 	/* open and AccessShareLock sequence */
 	init_sequence(sequence, &elm, &seqrel);
 
diff -ruN postgresql-7.4.13-old/src/backend/executor/functions.c postgresql-7.4.13/src/backend/executor/functions.c
--- postgresql-7.4.13-old/src/backend/executor/functions.c	2004-09-06 20:23:09.000000000 +0200
+++ postgresql-7.4.13/src/backend/executor/functions.c	2006-08-05 16:53:43.000000000 +0200
@@ -27,6 +27,9 @@
 #include "utils/lsyscache.h"
 #include "utils/syscache.h"
 
+#ifdef USE_REPLICATION
+#include "replicate.h"
+#endif /* USE_REPLICATION */
 
 /*
  * We have an execution_state record for each query in a function.	Each
@@ -412,6 +415,12 @@
 	TupleTableSlot *slot;
 	Datum		value;
 
+#ifdef USE_REPLICATION
+	if ((es != NULL) && (es->qd != NULL))
+	{
+		Xlog_Check_Replicate(es->qd->operation);
+	}
+#endif /* USE_REPLICATION */
 	if (es->status == F_EXEC_START)
 		postquel_start(es, fcache);
 
diff -ruN postgresql-7.4.13-old/src/backend/libpq/Makefile postgresql-7.4.13/src/backend/libpq/Makefile
--- postgresql-7.4.13-old/src/backend/libpq/Makefile	2003-01-06 04:18:26.000000000 +0100
+++ postgresql-7.4.13/src/backend/libpq/Makefile	2006-08-05 16:53:43.000000000 +0200
@@ -15,7 +15,7 @@
 # be-fsstubs is here for historical reasons, probably belongs elsewhere
 
 OBJS = be-fsstubs.o be-secure.o auth.o crypt.o hba.o ip.o md5.o pqcomm.o \
-       pqformat.o pqsignal.o
+       pqformat.o pqsignal.o pgcluster.o
 
 
 all: SUBSYS.o
diff -ruN postgresql-7.4.13-old/src/backend/libpq/be-fsstubs.c postgresql-7.4.13/src/backend/libpq/be-fsstubs.c
--- postgresql-7.4.13-old/src/backend/libpq/be-fsstubs.c	2003-08-04 04:39:59.000000000 +0200
+++ postgresql-7.4.13/src/backend/libpq/be-fsstubs.c	2006-08-05 16:53:43.000000000 +0200
@@ -44,6 +44,9 @@
 #include "storage/large_object.h"
 #include "utils/memutils.h"
 
+#ifdef USE_REPLICATION
+#include "replicate.h"
+#endif /* USE_REPLICATION */
 
 /* [PA] is Pascal Andr <andre@via.ecp.fr> */
 
@@ -80,6 +83,19 @@
 	int			fd;
 	MemoryContext currentContext;
 
+#ifdef USE_REPLICATION
+	if ((PGCluster_Info != NULL) &&
+		(PGR_lo_open(lobjId,mode) != STATUS_OK))
+	{
+		if ((mode & INV_WRITE) &&
+			(PGR_Is_Stand_Alone() == true) &&
+			(PGCluster_Info->PGR_Stand_Alone->permit == PERMIT_READ_ONLY) )
+		{
+			elog(WARNING, "This query is not permitted when all replication servers fell down ");
+			PG_RETURN_INT32(-1);
+		}
+	}
+#endif /* USE_REPLICATION */
 #if FSDB
 	elog(DEBUG4, "lo_open(%u,%d)", lobjId, mode);
 #endif
@@ -124,6 +140,9 @@
 				 errmsg("invalid large-object descriptor: %d", fd)));
 		PG_RETURN_INT32(-1);
 	}
+#ifdef USE_REPLICATION
+	PGR_lo_close(fd);
+#endif
 #if FSDB
 	elog(DEBUG4, "lo_close(%d)", fd);
 #endif
@@ -187,6 +206,17 @@
 		return -1;
 	}
 
+#ifdef USE_REPLICATION
+	if (PGR_lo_write(fd, buf, len) != STATUS_OK)
+	{
+		if ((PGR_Is_Stand_Alone() == true) &&
+			(PGCluster_Info->PGR_Stand_Alone->permit == PERMIT_READ_ONLY) )
+		{
+			elog(WARNING, "This query is not permitted when all replication servers fell down ");
+			return -1;
+		}
+	}
+#endif
 	Assert(fscxt != NULL);
 	currentContext = MemoryContextSwitchTo(fscxt);
 
@@ -215,6 +245,9 @@
 		PG_RETURN_INT32(-1);
 	}
 
+#ifdef USE_REPLICATION
+	PGR_lo_lseek(fd, offset, whence);
+#endif
 	Assert(fscxt != NULL);
 	currentContext = MemoryContextSwitchTo(fscxt);
 
@@ -242,6 +275,18 @@
 
 	currentContext = MemoryContextSwitchTo(fscxt);
 
+#ifdef USE_REPLICATION
+	if ((PGCluster_Info != NULL) &&
+		(PGR_lo_create(mode) != STATUS_OK))
+	{
+		if ((PGR_Is_Stand_Alone() == true) &&
+			(PGCluster_Info->PGR_Stand_Alone->permit == PERMIT_READ_ONLY) )
+		{
+			elog(WARNING, "This query is not permitted when all replication servers fell down ");
+			PG_RETURN_INT32(-1);
+		}
+	}
+#endif /* USE_REPLICATION */
 	lobjDesc = inv_create(mode);
 
 	if (lobjDesc == NULL)
@@ -285,6 +330,18 @@
 {
 	Oid			lobjId = PG_GETARG_OID(0);
 
+#ifdef USE_REPLICATION
+	if ((PGCluster_Info != NULL)  &&
+		(PGR_lo_unlink(lobjId) != STATUS_OK))
+	{
+		if ((PGR_Is_Stand_Alone() == true) &&
+			(PGCluster_Info->PGR_Stand_Alone->permit == PERMIT_READ_ONLY) )
+		{
+			elog(WARNING, "This query is not permitted when all replication servers fell down ");
+			return -1;
+		}
+	}
+#endif
 	/*
 	 * If there are any open LO FDs referencing that ID, close 'em.
 	 */
diff -ruN postgresql-7.4.13-old/src/backend/libpq/pgcluster.c postgresql-7.4.13/src/backend/libpq/pgcluster.c
--- postgresql-7.4.13-old/src/backend/libpq/pgcluster.c	1970-01-01 01:00:00.000000000 +0100
+++ postgresql-7.4.13/src/backend/libpq/pgcluster.c	2006-08-05 16:53:43.000000000 +0200
@@ -0,0 +1,1537 @@
+/*--------------------------------------------------------------------
+ * FILE:
+ *     pgcluster.c
+ *
+ * NOTE:
+ *     This file is composed of the functions to call with the source
+ *     at backend for the replication.
+ *     Low level I/O functions that called by in these functions are 
+ *     contained in 'replicate_com.c'.
+ *
+ *--------------------------------------------------------------------
+ */
+
+/*--------------------------------------
+ * INTERFACE ROUTINES
+ *
+ * setup/teardown:
+ *      PGR_Close_Sock
+ *      PGR_Free_Conf_Data
+ * I/O call:
+ *      PGR_Create_Socket_Connect
+ *      PGR_Create_Socket_Bind
+ *      PGR_Create_Acception
+ * table handling:
+ *      PGR_Get_Conf_Data
+ *-------------------------------------
+ */
+#ifdef USE_REPLICATION
+
+#include "postgres.h"
+
+#include <signal.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <grp.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/ipc.h>
+#include <sys/sem.h>
+#include <sys/shm.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#ifdef HAVE_NETINET_TCP_H
+#include <netinet/tcp.h>
+#endif
+#include <arpa/inet.h>
+#include <sys/file.h>
+#include <netdb.h>
+
+#include "libpq/libpq.h"
+#include "libpq/pqsignal.h"
+#include "miscadmin.h"
+#include "nodes/print.h"
+#include "utils/guc.h"
+#include "parser/parser.h"
+#include "access/xact.h"
+#include "replicate_com.h"
+
+#ifdef HAVE_SIGPROCMASK
+sigset_t	UnBlockSig,
+			BlockSig,
+			AuthBlockSig;
+
+#else
+int			UnBlockSig,
+			BlockSig,
+			AuthBlockSig;
+#endif
+
+static PGR_ConfData_Info * ConfData_Info;
+static PGR_Log_Info * Log_Info;
+static PGR_WatchDog_Info WatchDog_Info;
+
+int PGR_Create_Socket_Connect(int * fdP, char * hostName , unsigned short portNumber);
+void PGR_Close_Sock(int * sock);
+int PGR_Create_Socket_Bind(int * fdP, char * hostName , unsigned short portNumber);
+int PGR_Create_Acception(int fd, int * sockP, char * hostName , unsigned short portNumber);
+int PGR_Free_Conf_Data(void);
+int PGR_Get_Conf_Data(char * dir , char * fname);
+void PGRset_recovery_packet_no(RecoveryPacket * packet, int packet_no);
+unsigned int PGRget_ip_by_name(char * host);
+void PGRsem_unlock( int semid, int sem_num );
+void PGRsem_lock( int semid, int sem_num );
+void PGRwrite_log_file(FILE * fp, const char * fmt,...);
+
+void show_debug(const char * fmt,...);
+void show_error(const char * fmt,...);
+
+void PGR_Init_Com_Info(PGR_Com_Info * com_info);
+/* watch dog */
+void PGRsyn_quit(void);
+int PGRmap_to_cluster_tbl(HostTbl * ptr);
+int PGRmap_to_replication_server_tbl(ReplicateServerInfo * ptr);
+int PGRmap_to_load_balancer_tbl(RecoveryTbl * ptr);
+pid_t PGR_ACK_Main(uint16_t port);
+pid_t PGR_SYN_Main(int syn_target, void * status_tbl);
+void PGRset_start_life_check(void);
+void PGRexit_life_check(int sig);
+void PGRquit_lifecheck_child(int sig);
+void PGRchild_wait(int sig);
+int PGRsyn_init(void);
+
+static char * get_string(char * buf);
+static bool is_start_tag(char * ptr);
+static bool is_end_tag(char * ptr);
+static void init_conf_data(ConfDataType *conf);
+static int get_key(char * key, char * str);
+static int get_conf_key_value(char * key, char * value , char * str);
+static int add_conf_data(char *table,int rec_no, char *key,char * value);
+static int get_table_data(FILE * fp,char * table, int rec_no);
+static int get_single_data(char * str);
+static int get_conf_file(char * fname);
+/* static function for watch dog */
+static MapTable * get_map_by_pid(pid_t pid);
+static pid_t do_life_check(MapTable * map, int timeout);
+static int send_life_check(int sock, int send_timeout);
+static int read_life_check(int sock, int recv_timeout);
+static void set_map_status(MapTable *map,int status);
+static void write_status_file(MapTable * map);
+static void set_life_check_status( MapTable *map,int status);
+static pid_t ack_loop(int fd, uint16_t port);
+static void wait_start_life_check(int timeout);
+char * Function;
+/*--------------------------------------------------------------------
+ * SYMBOL
+ *     PGR_Create_Socket_Connect()
+ * NOTES
+ *     create new socket
+ * ARGS
+ *    int * fdP:
+ *    char * hostName:
+ *    unsigned short portNumber:
+ * RETURN
+ *    OK: STATUS_OK
+ *    NG: STATUS_ERROR
+ *--------------------------------------------------------------------
+ */
+int
+PGR_Create_Socket_Connect(int * fdP, char * hostName , unsigned short portNumber)
+{
+
+	int sock;
+	size_t	len = 0;
+	struct sockaddr_in addr;
+	int one = 1;
+
+	if ((*hostName == '\0') || (portNumber < 1000))
+	{
+		* fdP = -1;
+		return STATUS_ERROR;
+	}
+	if ((*fdP = socket(AF_INET, SOCK_STREAM, 0)) < 0)
+	{
+		* fdP = -1;
+		return STATUS_ERROR;
+	}
+	if ((setsockopt(*fdP, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one))) == -1)
+	{
+		PGR_Close_Sock(fdP);
+		return STATUS_ERROR;
+	}
+	if (setsockopt(*fdP, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) < 0)
+	{
+		PGR_Close_Sock(fdP);
+		return STATUS_ERROR;
+	}
+	
+	addr.sin_family = AF_INET;
+	if (hostName[0] == '\0')
+   		addr.sin_addr.s_addr = htonl(INADDR_ANY);
+	else
+	{
+		struct hostent *hp;
+
+		hp = gethostbyname(hostName);
+		if ((hp == NULL) || (hp->h_addrtype != AF_INET))
+		{
+			PGR_Close_Sock(fdP);
+			return STATUS_ERROR;
+		}
+		memmove((char *) &(addr.sin_addr), (char *) hp->h_addr, hp->h_length);
+	}
+
+	addr.sin_port = htons(portNumber);
+	len = sizeof(struct sockaddr_in);
+	
+	if ((sock = connect(*fdP,(struct sockaddr*)&addr,len)) < 0)
+	{
+		PGR_Close_Sock(fdP);
+		return STATUS_ERROR;
+	}
+	
+	return	STATUS_OK;
+}
+
+int
+PGR_Create_Socket_Bind(int * fdP, char * hostName , unsigned short portNumber)
+{
+
+	int err;
+	size_t	len = 0;
+	struct sockaddr_in addr;
+	int one = 1;
+
+	if ((*fdP = socket(AF_INET, SOCK_STREAM, 0)) < 0)
+	{
+		return STATUS_ERROR;
+	}
+	if ((setsockopt(*fdP, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one))) == -1)
+	{
+		PGR_Close_Sock(fdP);
+		return STATUS_ERROR;
+	}
+	addr.sin_family = AF_INET;
+	if (hostName[0] == '\0')
+		addr.sin_addr.s_addr = htonl(INADDR_ANY);
+	else
+	{
+		struct hostent *hp;
+
+		hp = gethostbyname(hostName);
+		if ((hp == NULL) || (hp->h_addrtype != AF_INET))
+		{
+			PGR_Close_Sock(fdP);
+			return STATUS_ERROR;
+		}
+		memmove((char *) &(addr.sin_addr), (char *) hp->h_addr, hp->h_length);
+	}
+
+	addr.sin_port = htons(portNumber);
+	len = sizeof(struct sockaddr_in);
+	
+	err = bind(*fdP, (struct sockaddr *) & addr, len);
+	if (err < 0)
+	{
+		PGR_Close_Sock(fdP);
+		return STATUS_ERROR;
+	}
+	err = listen(*fdP, MAX_SOCKET_QUEUE );
+	if (err < 0)
+	{
+		PGR_Close_Sock(fdP);
+		return STATUS_ERROR;
+	}
+	return	STATUS_OK;
+}
+
+int
+PGR_Create_Acception(int fd, int * sockP, char * hostName , unsigned short portNumber)
+{
+	int sock;
+	struct sockaddr  addr;
+	size_t	len = 0;
+	int one = 1;
+
+	len = sizeof(struct sockaddr);
+	while ((sock = accept(fd,&addr,&len)) < 0)
+	{
+		PGR_Close_Sock(&fd);
+		PGR_Create_Socket_Bind(&fd, hostName , portNumber);
+	}
+	
+	if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) < 0)
+	{
+		return STATUS_ERROR;
+	}
+	if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one)) < 0)
+	{
+		return STATUS_ERROR;
+	}
+	*sockP = sock;
+
+	return	STATUS_OK;
+}
+
+void
+PGR_Close_Sock(int * sock)
+{
+	close( (int)*sock);
+	*sock = -1;
+}
+
+static char *
+get_string(char * buf)
+{
+	int i,len1,len2,start_flag;
+	char *readp, *writep; 
+
+	writep = readp = buf;
+	i = len1 = 0;
+	while (*(readp +i) != '\0')
+	{
+		if (!isspace(*(readp+ i)))
+		{
+			len1 ++;
+		}
+		i++;
+	}
+	start_flag = len2 = 0;
+	while (*readp != '\0')
+	{
+		if (*readp == '#') 
+		{
+			*writep = '\0';
+			break;
+		}
+		if (isspace(*readp))
+		{
+			if ((len2 >= len1) || (!start_flag))
+			{
+				readp++;
+				continue;
+			}
+			*writep = *readp;
+		}
+		else
+		{
+			start_flag = 1;
+			*writep = *readp;
+			len2 ++;
+		}
+		readp ++;
+		writep ++;
+	}
+	*writep = '\0';
+	return buf;
+}
+
+static bool
+is_start_tag(char * ptr)
+{
+	if ((*ptr == '<') && (*(ptr+1) != '/'))
+	{
+		return true;
+	}
+	return false;
+}
+
+static bool
+is_end_tag(char * ptr)
+{
+	if ((*ptr == '<') && (*(ptr+1) == '/'))
+	{
+		return true;
+	}
+	return false;
+}
+
+static void
+init_conf_data(ConfDataType *conf)
+{
+	memset(conf->table,0,sizeof(conf->table));
+	memset(conf->key,0,sizeof(conf->key));
+	memset(conf->value,0,sizeof(conf->value));
+	conf->rec_no = 0;
+	conf->last = NULL;
+	conf->next = NULL;
+}
+
+static int
+get_key(char * key, char * str)
+{
+	int offset = 1;
+	char * ptr_s,*ptr_e;
+
+	ptr_s = strchr(str,'<');
+	if (ptr_s == NULL)
+	{
+		return STATUS_ERROR;
+	}
+	if (*(ptr_s+1) == '/')
+	{
+		offset = 2;
+	}
+	ptr_e = strchr(str,'>');
+	if (ptr_e == NULL)
+	{
+		return STATUS_ERROR;
+	}
+	*ptr_e = '\0';
+	strcpy(key,ptr_s + offset);
+	*ptr_e = '>';
+	return STATUS_OK;
+}
+
+static int
+get_conf_key_value(char * key, char * value , char * str)
+{
+	int i;
+	int len1,len2,start_flag;
+	char * ptr_s,*ptr_e;
+
+	if(get_key(key,str) == STATUS_ERROR)
+	{
+		return STATUS_ERROR;
+	}
+	ptr_e = strchr(str,'>');
+	if (ptr_e == NULL)
+	{
+		return STATUS_ERROR;
+	}
+	ptr_s = ptr_e + 1;
+
+	len1 = 0;
+	while ((*ptr_s != '<') && (*ptr_s != '\0'))
+	{
+			if (! isspace(*ptr_s))
+			{
+				len1 ++;
+			}
+			ptr_s ++;
+	}
+	ptr_s = ptr_e + 1;
+	i = len2 = start_flag = 0;
+	while ((*ptr_s != '<') && (*ptr_s != '\0'))
+	{
+		if (isspace(*ptr_s))
+		{
+			if ((len2 >= len1) || (!start_flag))
+			{
+				ptr_s ++;
+				continue;
+			}
+			*(value + i) = *ptr_s;
+		}
+		else
+		{
+			start_flag = 1;
+			*(value + i) = *ptr_s;
+			len2 ++;
+		}
+		i++;
+		ptr_s ++;
+	}
+	*(value + i) = '\0';
+	return STATUS_OK;
+}
+
+static int
+add_conf_data(char *table,int rec_no, char *key,char * value)
+{
+	ConfDataType * conf_data;
+
+	conf_data = (ConfDataType *)malloc(sizeof(ConfDataType));
+	if (conf_data == NULL)
+	{
+		return STATUS_ERROR;
+	}
+	init_conf_data(conf_data);
+	if (table != NULL)
+	{
+		memcpy(conf_data->table,table,sizeof(conf_data->table));
+	}
+	else
+	{
+		memset(conf_data->table,0,sizeof(conf_data->table));
+	}
+	strncpy(conf_data->key,key,sizeof(conf_data->key));
+	strncpy(conf_data->value,value,sizeof(conf_data->value));
+	conf_data->rec_no = rec_no;
+	if (ConfData_Info->ConfData_Top == (ConfDataType *)NULL)
+	{
+		ConfData_Info->ConfData_Top = conf_data;
+		conf_data->last = (char *)NULL;
+	}
+	if (ConfData_Info->ConfData_End == (ConfDataType *)NULL)
+	{
+		conf_data->last = (char *)NULL;
+	}
+	else
+	{
+		conf_data->last = (char *)ConfData_Info->ConfData_End;
+		ConfData_Info->ConfData_End->next = (char *)conf_data;
+	}
+	ConfData_Info->ConfData_End = conf_data;
+	conf_data->next = (char *)NULL;
+	return STATUS_OK;
+}
+
+static int
+get_table_data(FILE * fp,char * table, int rec_no)
+{
+	char buf[1024];
+	char key_buf[1024];
+	char value_buf[1024];
+	int len = 0;
+	char * ptr;
+
+	while (fgets(buf,sizeof(buf),fp) != NULL)
+	{
+		/*
+		 * pic up a data string
+		 */
+		ptr = get_string(buf);
+		len = strlen(ptr);
+		if (len == 0)
+		{
+			continue;
+		}
+		if (is_end_tag(ptr))
+		{
+			if(get_key(key_buf,ptr) == STATUS_ERROR)
+			{
+				return STATUS_ERROR;
+			}
+			if (!strcmp(key_buf,table))
+			{
+				return STATUS_OK;
+			}
+		}
+		if (is_start_tag(ptr))
+		{
+			if(get_conf_key_value(key_buf,value_buf,ptr) == STATUS_ERROR)
+			{
+				return STATUS_ERROR;
+			}
+			add_conf_data(table,rec_no,key_buf,value_buf);
+		}
+	}
+	return STATUS_ERROR;
+}
+
+static int
+get_single_data(char * str)
+{
+	char key_buf[1024];
+	char value_buf[1024];
+	if(get_conf_key_value(key_buf,value_buf,str) == STATUS_ERROR)
+	{
+		return STATUS_ERROR;
+	}
+	add_conf_data(NULL,0,key_buf,value_buf);
+	return STATUS_OK;
+}
+
+
+static int
+get_conf_file(char * fname)
+{
+	FILE * fp = NULL;
+	int len;
+	char buf[1024];
+	char key_buf[1024];
+	char last_key_buf[1024];
+	char *ptr;
+	int rec_no = 0;
+
+	/*
+	 * configuration file open
+	 */
+	if ((fp = fopen(fname,"r")) == NULL)
+	{
+		return STATUS_ERROR;
+	}
+	/*
+	 * configuration file read
+	 */
+	memset(last_key_buf,0,sizeof(last_key_buf));
+	memset(key_buf,0,sizeof(key_buf));
+	while (fgets(buf,sizeof(buf),fp) != NULL)
+	{
+		/*
+		 * pic up a data string
+		 */
+		ptr = get_string(buf);
+		len = strlen(ptr);
+		if (len == 0)
+		{
+			continue;
+		}
+		if (is_start_tag(ptr))
+		{
+			if(get_key(key_buf,ptr) == STATUS_ERROR)
+			{
+				fclose(fp);
+				return STATUS_ERROR;
+			}
+			if (strstr(ptr,"</") == NULL)
+			{
+				if (strcmp(last_key_buf,key_buf))
+				{
+					rec_no = 0;
+					strcpy(last_key_buf,key_buf);
+				}
+				get_table_data(fp,key_buf,rec_no);
+				rec_no ++;
+			}
+			else
+			{
+				get_single_data(ptr);
+			}
+		}
+	}
+	fclose(fp);
+	return STATUS_OK;
+}
+
+int
+PGR_Free_Conf_Data(void)
+{
+	ConfDataType * conf, *nextp;
+
+	if (ConfData_Info->ConfData_Top == (ConfDataType *)NULL)
+	{
+		return STATUS_ERROR;
+	}
+	conf = ConfData_Info->ConfData_Top;
+
+	while (conf != (ConfDataType *)NULL)
+	{
+		nextp = (ConfDataType*)conf->next;
+		free (conf);
+		conf = nextp;
+	}
+	ConfData_Info->ConfData_Top = ConfData_Info->ConfData_End = (ConfDataType *)NULL;
+	return STATUS_OK;
+}
+
+int
+PGR_Get_Conf_Data(char * dir , char * fname)
+{
+
+	int status;
+
+	char * conf_file;
+	if ((dir == NULL) || ( fname == NULL))
+	{
+		return STATUS_ERROR;
+	}
+	conf_file = malloc(strlen(dir) + strlen(fname) + 2);
+	if (conf_file == NULL)
+	{
+		return STATUS_ERROR;
+	}
+	sprintf(conf_file,"%s/%s",dir,fname);
+
+	ConfData_Info->ConfData_Top = ConfData_Info->ConfData_End = (ConfDataType * )NULL;
+	status = get_conf_file(conf_file);
+	free (conf_file);
+	conf_file = NULL;
+
+	return status;
+}
+
+void
+PGRset_recovery_packet_no(RecoveryPacket * packet, int packet_no)
+{
+	if (packet == NULL)
+	{
+		return;
+	}
+	packet->packet_no = htons(packet_no) ;
+
+}
+
+unsigned int
+PGRget_ip_by_name(char * host)
+{
+	struct hostent *hp = NULL;
+	unsigned int ip = 0;
+	unsigned char uc = 0;
+	int i;
+
+	if ((host == NULL) || (*host == '\0'))
+	{
+		return 0;
+	}
+	hp = gethostbyname( host );
+	if (hp == NULL)
+	{
+		return 0;
+	}
+	for (i = 3 ; i>= 0 ; i --)
+	{
+		uc = (unsigned char)hp->h_addr_list[0][i];
+		ip = ip | uc;
+		if (i > 0)
+		ip = ip << 8;
+	}
+	return ip;
+}
+
+void
+PGRsem_unlock( int semid, int sem_num )
+{
+	int	status;
+	int cnt = 10;
+	struct sembuf sops;
+
+	if (semid <= 0)
+		return;
+	sops.sem_num = sem_num;
+	sops.sem_op = 1;
+	sops.sem_flg = 0;
+
+	do
+	{
+		status = semop(semid, &sops, 1);
+		if ((status == -1) && (errno != EINTR))
+		{
+			usleep(cnt);
+			cnt ++;
+			if (cnt > 20)
+				break;
+		}
+	} while (status == -1 && errno == EINTR);
+}
+
+void
+PGRsem_lock( int semid, int sem_num )
+{
+	int cnt = 10;
+	int	status;
+	struct sembuf sops;
+
+	if (semid <= 0)
+		return;
+	sops.sem_num = sem_num;
+	sops.sem_op = -1;
+	sops.sem_flg = 0;
+
+	do
+	{
+		status = semop(semid, &sops, 1);
+		if ((status == -1) && (errno != EINTR))
+		{
+			usleep(cnt);
+			cnt ++;
+			if (cnt > 20)
+				break;
+		}
+	} while (status == -1 && errno == EINTR);
+}
+
+void
+PGRwrite_log_file(FILE * fp, const char * fmt,...)
+{
+	char buf[256];
+	char log[288];
+	char * p;
+	va_list ap;
+	time_t t;
+
+	if (fp == NULL)
+	{
+		return;
+	}
+	if (time(&t) < 0)
+	{
+		return;
+	}
+	snprintf(log,sizeof(log),"%s ",ctime(&t));
+	p = strchr(log,'\n');
+	if (p != NULL)
+	{
+		*p = ' ';
+	}
+	va_start(ap,fmt);
+	vsnprintf(buf,sizeof(buf),fmt,ap);
+	va_end(ap);
+	strcat(log,buf);
+	strcat(log,"\n");
+	if (fputs(log,fp) >= 0)
+	{
+		fflush(fp);
+	}
+}
+
+
+void
+show_debug(const char * fmt,...)
+{
+	va_list ap;
+
+	if (Log_Info->Debug_Print)
+	{
+		fprintf(stdout,"DEBUG:");
+		va_start(ap,fmt);
+		vfprintf(stdout,fmt,ap);
+		va_end(ap);
+		fprintf(stdout,"\n");
+		fflush(stdout);
+	}
+}
+
+void
+show_error(const char * fmt,...)
+{
+	va_list ap;
+	char buf[256];
+
+	if (Log_Info->Debug_Print)
+	{
+		fprintf(stderr,"ERROR:");
+		va_start(ap,fmt);
+		vfprintf(stderr,fmt,ap);
+		va_end(ap);
+		fprintf(stderr,"\n");
+		fflush(stderr);
+	}
+	if (Log_Info->Log_Print)
+	{
+		va_start(ap,fmt);
+		vsnprintf(buf,sizeof(buf),fmt,ap);
+		va_end(ap);
+		PGRwrite_log_file(Log_Info->LogFp,buf);
+	}
+}
+
+void 
+PGR_Init_Com_Info(PGR_Com_Info * p)
+{
+	if (p != (PGR_Com_Info *)NULL)
+	{
+		/* init PGR_ConfData_Info data */
+		ConfData_Info = &(p->ConfData_Info);
+		ConfData_Info->ConfData_Top = (ConfDataType*)NULL;
+		ConfData_Info->ConfData_End = (ConfDataType*)NULL;
+		ConfData_Info->LifeCheck_Port_Number = 0;
+		ConfData_Info->Recovery_Port_Number = 0;
+
+		/* init PGR_Log_Info data */
+		Log_Info = &(p->Log_Info);
+		Log_Info->StatusFp = (FILE *)NULL;
+		Log_Info->LogFp = (FILE *)NULL;
+		Log_Info->PGRStatusFileName = NULL;
+		Log_Info->PGRLogFileName = NULL;
+		Log_Info->Log_Print = 0;
+		Log_Info->Debug_Print = 0;
+	}
+	else
+	{
+		ConfData_Info = (PGR_ConfData_Info *)NULL;
+		Log_Info = (PGR_Log_Info *)NULL;
+	}
+}
+
+/*--------------------------------------
+ * Watch Dog functions
+ *--------------------------------------
+ */
+
+
+int
+PGRsyn_init(void)
+{
+	union semun sem_arg;
+	int sem_nums = 0;
+	int i = 0;
+	int size = 0;
+
+	size = sizeof(MapTable) * (MAX_DB_SERVER+1);
+	WatchDog_Info.MapTableShmid = shmget(IPC_PRIVATE,size,IPC_CREAT | IPC_EXCL | 0600);
+	if (WatchDog_Info.MapTableShmid < 0)
+	{
+		show_error("shmget() failed. (%s)",strerror(errno));
+		return STATUS_ERROR;
+	}
+	WatchDog_Info.Map_Table = (MapTable *)shmat(WatchDog_Info.MapTableShmid,0,0);
+	if (WatchDog_Info.Map_Table == (MapTable *)-1)
+	{
+		show_error("shmat() failed. (%s)",strerror(errno));
+		return STATUS_ERROR;
+	}
+	memset(WatchDog_Info.Map_Table,0,size);
+
+	size = sizeof(char);
+	WatchDog_Info.LifeCheckStartShmid = shmget(IPC_PRIVATE,size,IPC_CREAT | IPC_EXCL | 0600);
+	if (WatchDog_Info.LifeCheckStartShmid < 0)
+	{
+		show_error("shmget() failed. (%s)",strerror(errno));
+		return STATUS_ERROR;
+	}
+	WatchDog_Info.LifeCheckStartFlag = (char *)shmat(WatchDog_Info.LifeCheckStartShmid,0,0);
+	if (WatchDog_Info.LifeCheckStartFlag == (char *)-1)
+	{
+		show_error("shmat() failed. (%s)",strerror(errno));
+		return STATUS_ERROR;
+	}
+	*WatchDog_Info.LifeCheckStartFlag = LIFE_CHECK_STOP;
+
+	sem_nums = MAX_DB_SERVER + 4;
+	if ((WatchDog_Info.SynSemID = semget(IPC_PRIVATE,sem_nums,IPC_CREAT | IPC_EXCL | 0600)) < 0)
+	{
+		show_error("semget() failed. (%s)",strerror(errno));
+		return STATUS_ERROR;
+	}
+	for ( i = 0 ; i < sem_nums ; i ++)
+	{
+		semctl(WatchDog_Info.SynSemID, i, GETVAL, sem_arg);
+		sem_arg.val = 1;
+		semctl(WatchDog_Info.SynSemID, i, SETVAL, sem_arg);
+	}
+	WatchDog_Info.LifeCheckTimeOut = 10;
+	return STATUS_OK;
+}
+
+void
+PGRsyn_quit(void)
+{
+	if (WatchDog_Info.Map_Table != (MapTable *)NULL)
+	{
+		shmdt((char *)WatchDog_Info.Map_Table);
+		shmctl(WatchDog_Info.MapTableShmid,IPC_RMID,(struct shmid_ds *)NULL);
+		WatchDog_Info.Map_Table = (MapTable *)NULL;
+	}
+
+	if (WatchDog_Info.LifeCheckStartFlag != (char *)NULL)
+	{
+		shmdt((char *)WatchDog_Info.LifeCheckStartFlag);
+		shmctl(WatchDog_Info.LifeCheckStartShmid,IPC_RMID,(struct shmid_ds *)NULL);
+		WatchDog_Info.LifeCheckStartFlag = (char *)NULL;
+	}
+
+	if (WatchDog_Info.SynSemID >= 0)
+	{
+		semctl(WatchDog_Info.SynSemID, 0, IPC_RMID);
+		WatchDog_Info.SynSemID = -1;
+	}
+}
+
+int
+PGRmap_to_cluster_tbl(HostTbl * ptr)
+{
+	int cnt = 0;
+	MapTable * map;
+	map = WatchDog_Info.Map_Table;
+
+	if ((ptr == (HostTbl*)NULL) || (map == (MapTable*)NULL))
+	{
+		return 0;
+	}
+	cnt = 0;
+	while (ptr->useFlag != DATA_END)
+	{
+		cnt ++;
+		map->useFlag = &(ptr->useFlag);
+		map->hostName = (char *)(ptr->hostName);
+		map->port = &(ptr->port);
+		map->lifecheckPort = &(ptr->lifecheckPort);
+		map->sock = 0;
+		map->rec_no = cnt;
+		set_life_check_status(map,LIFE_CHECK_TRY_COUNT);
+		show_debug("use[%d] host[%s] port[%d] life[%d] rec[%d]",
+				*(map->useFlag),
+				map->hostName,
+				*(map->port),
+				*(map->lifecheckPort),
+				map->rec_no);
+		ptr ++;
+		map ++;
+	}
+	map->useFlag = &(ptr->useFlag);
+	return cnt;
+}
+
+int
+PGRmap_to_replication_server_tbl(ReplicateServerInfo * ptr)
+{
+	int cnt = 0;
+	MapTable * map;
+	map = WatchDog_Info.Map_Table;
+
+	if ((ptr == (ReplicateServerInfo*)NULL) || (map == (MapTable*)NULL))
+	{
+		return 0;
+	}
+	cnt = 0;
+	while (ptr->useFlag != DATA_END)
+	{
+		cnt ++;
+		map->useFlag = &(ptr->useFlag);
+		map->hostName = (char *)(ptr->hostName);
+		map->port = &(ptr->portNumber);
+		map->lifecheckPort = &(ptr->lifecheckPortNumber);
+		map->sock = 0;
+		map->rec_no = cnt;
+		set_life_check_status(map,LIFE_CHECK_TRY_COUNT);
+		show_debug("use[%d] host[%s] port[%d] life[%d] rec[%d]",
+				*(map->useFlag),
+				map->hostName,
+				*(map->port),
+				*(map->lifecheckPort),
+				map->rec_no);
+		ptr ++;
+		map ++;
+	}
+	map->useFlag = &(ptr->useFlag);
+	return cnt;
+}
+
+int
+PGRmap_to_load_balancer_tbl(RecoveryTbl * ptr)
+{
+	int cnt = 0;
+	MapTable * map;
+	map = WatchDog_Info.Map_Table;
+
+	if ((ptr == (RecoveryTbl*)NULL) || (map == (MapTable*)NULL))
+	{
+		return 0;
+	}
+	cnt = 0;
+	while (ptr->useFlag != DATA_END)
+	{
+		cnt ++;
+		map->useFlag = &(ptr->useFlag);
+		map->hostName = (char *)(ptr->hostName);
+		map->port = &(ptr->port);
+		map->lifecheckPort = &(ptr->lifecheckPort);
+		map->sock = 0;
+		map->rec_no = cnt;
+		set_life_check_status(map,LIFE_CHECK_TRY_COUNT);
+		show_debug("use[%d] host[%s] port[%d] life[%d] rec[%d]",
+				*(map->useFlag),
+				map->hostName,
+				*(map->port),
+				*(map->lifecheckPort),
+				map->rec_no);
+		ptr ++;
+		map ++;
+	}
+	map->useFlag = &(ptr->useFlag);
+	return cnt;
+}
+
+void
+PGRexit_life_check(int sig)
+{
+	PGRsyn_quit();
+	signal(SIGCHLD,SIG_IGN);
+	signal(sig,SIG_IGN);
+	kill (0,sig);
+	while (wait(NULL) > 0 )
+		;
+	exit(0);
+}
+
+void
+PGRquit_lifecheck_child(int sig)
+{
+	MapTable * map = NULL; 
+	pid_t pid = getpid();
+	map = get_map_by_pid(pid);
+	if (map != NULL)
+	{
+		if (map->sock > 0)
+		{
+			close(map->sock);
+		}
+		map->sock = -1;
+		map->pid = 0;
+	}
+	exit(0);
+
+}
+
+static MapTable *
+get_map_by_pid(pid_t pid)
+{
+	MapTable * map;
+	map = WatchDog_Info.Map_Table;
+
+	if (( map == NULL ) || (pid <= 0))
+	{
+		return (MapTable *)NULL;
+	}
+	while (*(map->useFlag) != DATA_END)
+	{
+		if (map->pid == pid)
+		{
+			return map;
+		}
+		map ++;
+	}
+	return (MapTable *)NULL;
+}
+
+static pid_t
+do_life_check(MapTable * map, int timeout)
+{
+	pid_t pid;
+	pid_t pgid = 0;
+	int status;
+
+	pgid = getpgid(0);
+	if ((pid = fork()) != 0 )
+	{
+		return pid;
+	}
+	
+	setpgid(0,pgid);
+	pqsignal(SIGHUP,PGRquit_lifecheck_child);
+	pqsignal(SIGTERM,PGRquit_lifecheck_child);
+	pqsignal(SIGINT,PGRquit_lifecheck_child);
+	pqsignal(SIGQUIT,PGRquit_lifecheck_child);
+	PG_SETMASK(&AuthBlockSig);
+
+	if (map == NULL)
+	{
+		exit(0);
+	}
+	if (*(map->useFlag) == DATA_ERR)
+	{
+		map->pid = 0;
+		exit(0);
+	}
+	if (map->sock > 0)
+	{
+		close(map->sock);
+	}
+	status = PGR_Create_Socket_Connect(&(map->sock),map->hostName,*(map->lifecheckPort));
+	if (status != STATUS_OK)
+	{
+		set_map_status(map,DATA_ERR);
+		close(map->sock);
+		map->sock = -1;
+		map->pid = 0;
+		exit(0);
+	}
+	for (;;)
+	{
+		status = send_life_check(map->sock, timeout);
+		if (status != STATUS_OK)
+		{
+			set_map_status(map,DATA_ERR);
+			close(map->sock);
+			map->sock = -1;
+			map->pid = 0;
+			exit(0);
+		}
+		status = read_life_check(map->sock, timeout);
+		if (status != STATUS_OK)
+		{
+			set_map_status(map,DATA_ERR);
+			close(map->sock);
+			map->sock = -1;
+			map->pid = 0;
+			exit(0);
+		}
+		set_life_check_status(map,LIFE_CHECK_TRY_COUNT);
+		sleep(timeout);
+	}
+}
+
+static int
+send_life_check(int sock, int send_timeout)
+{
+	char life_check_data;
+	int buf_size = sizeof(char);
+	int s;
+	int rtn;	
+	fd_set	  wmask;
+	struct timeval timeout;
+
+	timeout.tv_sec = send_timeout;
+	timeout.tv_usec = 0;
+
+	life_check_data = 'L';
+	/*
+	 * Wait for something to happen.
+	 */
+	FD_ZERO(&wmask);
+	FD_SET(sock,&wmask);
+	rtn = select(sock+1, (fd_set *)NULL, &wmask, (fd_set *)NULL, &timeout);
+	if (rtn && FD_ISSET(sock, &wmask))
+	{
+		for (;;)
+		{
+			s = send(sock,&life_check_data,buf_size ,0);
+			if (s <= 0){
+				if (errno == EINTR)
+				{
+					continue;
+				}
+				return STATUS_ERROR;
+			}
+			if (s == buf_size)
+			{
+				return STATUS_OK;
+			}
+		}
+	}
+	return STATUS_ERROR;
+}
+
+static int
+read_life_check(int sock, int recv_timeout)
+{
+	char life_check_data;
+	int buf_size = sizeof(char);
+	int	rtn = 0;
+	fd_set	  rmask;
+	struct timeval timeout;
+	int r = 0;
+
+	timeout.tv_sec = recv_timeout;
+	timeout.tv_usec = 0;
+
+	/*
+	 * Wait for something to happen.
+	 */
+	FD_ZERO(&rmask);
+	FD_SET(sock,&rmask);
+	rtn = select(sock+1, &rmask, (fd_set *)NULL, (fd_set *)NULL, &timeout);
+	if (rtn && FD_ISSET(sock, &rmask))
+	{
+		for (;;)
+		{
+			r = recv(sock,&life_check_data,buf_size, MSG_WAITALL);
+			if (r <= 0)
+			{
+				if (errno == EINTR)
+				{
+					continue;
+				}
+				return STATUS_ERROR;
+			}
+			if (r == buf_size)
+			{
+				return STATUS_OK;
+			}
+		}
+	}
+	return STATUS_ERROR;
+}
+
+static void
+set_map_status(MapTable *map,int status)
+{
+	if (map == NULL)
+	{
+		return;
+	}
+	PGRsem_lock(WatchDog_Info.SynSemID,map->rec_no);
+	if (*(map->useFlag) != status)
+	{
+		*(map->useFlag) = status;
+		write_status_file(map);
+	}
+	PGRsem_unlock(WatchDog_Info.SynSemID,map->rec_no);
+
+}
+
+static void
+write_status_file(MapTable * map)
+{
+	if (Log_Info == NULL)
+		return;
+	switch(*(map->useFlag))
+	{
+		case DATA_FREE:
+			PGRwrite_log_file(Log_Info->StatusFp,"port(%d) host:%s free",
+					*(map->port),
+					map->hostName);
+			break;
+		case DATA_INIT:
+			PGRwrite_log_file(Log_Info->StatusFp,"port(%d) host:%s initialize",
+					*(map->port),
+					map->hostName);
+			break;
+		case DATA_USE:
+			PGRwrite_log_file(Log_Info->StatusFp,"port(%d) host:%s start use",
+					*(map->port),
+					map->hostName);
+			break;
+		case DATA_ERR:
+			PGRwrite_log_file(Log_Info->StatusFp,"port(%d) host:%s error",
+					*(map->port),
+					map->hostName);
+			break;
+		case DATA_END:
+			PGRwrite_log_file(Log_Info->StatusFp,"port(%d) host:%s end",
+					*(map->port),
+					map->hostName);
+			break;
+	}
+}
+
+static void
+set_life_check_status( MapTable *map,int status)
+{
+	if (map == NULL)
+	{
+		return;
+	}
+	PGRsem_lock(WatchDog_Info.SynSemID,map->rec_no);
+	if (map->status != status)
+	{
+		map->status = status;
+	}
+	PGRsem_unlock(WatchDog_Info.SynSemID,map->rec_no);
+}
+
+void
+PGRchild_wait(int sig)
+{
+	pid_t pid = 0;
+
+	do {
+		int ret;
+		pid = waitpid(-1,&ret,WNOHANG);
+	} while(pid > 0);
+}
+
+pid_t
+PGR_ACK_Main(uint16_t port)
+{
+	int status;
+	int fd = -1;
+	int rtn;
+	pid_t pid = 0;
+	pid_t pgid = 0;
+
+	pgid = getpgid(0);
+	if ((pid = fork()) != 0 )
+	{
+		return pid;
+	}
+	setpgid(0,pgid);	
+	pqsignal(SIGHUP,PGRexit_life_check);
+	pqsignal(SIGTERM,PGRexit_life_check);
+	pqsignal(SIGINT,PGRexit_life_check);
+	pqsignal(SIGQUIT,PGRexit_life_check);
+	pqsignal(SIGCHLD,PGRchild_wait);
+	PG_SETMASK(&AuthBlockSig);
+	status = PGR_Create_Socket_Bind(&fd, "", port);
+
+	if (status != STATUS_OK)
+	{
+		return pid;
+	}
+	for (;;)
+	{
+		fd_set	  rmask;
+		struct timeval timeout;
+
+		timeout.tv_sec = 60;
+		timeout.tv_usec = 0;
+
+		/*
+		 * Wait for something to happen.
+		 */
+		FD_ZERO(&rmask);
+		FD_SET(fd,&rmask);
+		rtn = select(fd+1, &rmask, (fd_set *)NULL, (fd_set *)NULL, &timeout);
+		if (rtn && FD_ISSET(fd, &rmask))
+		{
+			ack_loop(fd,port);
+		}
+	}
+	exit(0);
+}
+
+static pid_t
+ack_loop(int fd, uint16_t port)
+{
+
+	int count;
+	int sock;
+	int status = STATUS_OK;
+	int timeout = 600;
+	pid_t pid;
+	pid_t pgid = 0;
+
+	pgid = getpgid(0);
+	if ((pid = fork()) != 0 )
+	{
+		return pid;
+	}
+	
+	setpgid(0,pgid);
+	pqsignal(SIGHUP,PGRquit_lifecheck_child);
+	pqsignal(SIGTERM,PGRquit_lifecheck_child);
+	pqsignal(SIGINT,PGRquit_lifecheck_child);
+	pqsignal(SIGQUIT,PGRquit_lifecheck_child);
+	PG_SETMASK(&AuthBlockSig);
+
+	count = 0;
+	while ((status = PGR_Create_Acception(fd,&sock,"",port)) != STATUS_OK)
+	{
+		close(sock);
+		sock = -1;
+		if ( count > MAX_RETRY_TIMES)
+		{
+			PGRquit_lifecheck_child(15);
+		}
+		count ++;
+	}
+	for(;;)
+	{
+		status = read_life_check(sock, timeout);
+		if (status != STATUS_OK)
+		{
+			close(sock);
+			break;
+		}
+		status = send_life_check(sock, timeout);
+		if (status != STATUS_OK)
+		{
+			close(sock);
+			break;
+		}
+	}
+	PGRquit_lifecheck_child(15);
+	return pid;
+}
+
+pid_t
+PGR_SYN_Main(int syn_target, void * status_tbl)
+{
+	int cnt = 0;
+	pid_t pid = 0;
+	pid_t pgid = 0;
+	int i = 0;
+	int status = 0;
+	int syn_timeout = 0;
+	MapTable * map = (MapTable *)NULL;
+
+	pgid = getpgid(0);
+	if ((pid = fork()) != 0 )
+	{
+		return pid;
+	}
+	
+	setpgid(0,pgid);
+	pqsignal(SIGHUP,PGRexit_life_check);
+	pqsignal(SIGTERM,PGRexit_life_check);
+	pqsignal(SIGINT,PGRexit_life_check);
+	pqsignal(SIGQUIT,PGRexit_life_check);
+	signal(SIGCHLD,SIG_IGN);
+	PG_SETMASK(&AuthBlockSig);
+
+	syn_timeout = WatchDog_Info.LifeCheckTimeOut / LIFE_CHECK_TRY_COUNT;
+	syn_timeout += 1;
+
+	/* wait until target server is ready */
+	wait_start_life_check(syn_timeout);
+
+	/* map the target status table */
+	switch (syn_target)
+	{
+		case SYN_TO_LOAD_BALANCER:
+			cnt = PGRmap_to_load_balancer_tbl((RecoveryTbl *)status_tbl);
+			break;
+		case SYN_TO_CLUSTER_DB:
+			cnt = PGRmap_to_cluster_tbl((HostTbl *) status_tbl);
+			break;
+		case SYN_TO_REPLICATION_SERVER:
+			cnt = PGRmap_to_replication_server_tbl((ReplicateServerInfo *) status_tbl);
+			break;
+	}
+	map = WatchDog_Info.Map_Table;
+	if (map == (MapTable *)NULL)
+	{
+		show_error("target status table is not ready");
+		PGRexit_life_check(15);
+	}
+
+	/* create child process */
+	for (i = 0 ; i < cnt ; i ++)
+	{
+		do_life_check((map + i), syn_timeout);
+	}
+
+	/* check response from each target servers */
+	for (;;)
+	{
+		i = 0;
+		while(*((map + i)->useFlag) != DATA_END)
+		{
+			status = (map +i)->status;
+			if (status < 0) 
+			{
+				if (*((map +i)->useFlag) == DATA_ERR)
+				{
+					/* already closed */
+					i++;
+					continue;
+				}
+				else
+				{
+					/* restart life check */
+					do_life_check((map + i), syn_timeout);
+					status = 1;
+				}
+			}
+			if (status == 0)
+			{
+				/* the target server should be down */
+				set_map_status((map + i),DATA_ERR);
+				if ((map + i)->pid > 0)
+				{
+					kill((map + i)->pid,SIGTERM);
+				}
+			}
+			status --;
+			set_life_check_status((map + i),status);
+			i ++;
+		}
+		sleep(WatchDog_Info.LifeCheckTimeOut);
+	}
+}
+
+void
+PGRset_start_life_check(void)
+{
+	if (WatchDog_Info.LifeCheckStartFlag == NULL)
+	{
+		return;
+	}
+	if (*WatchDog_Info.LifeCheckStartFlag == LIFE_CHECK_STOP)
+	{
+		*WatchDog_Info.LifeCheckStartFlag = LIFE_CHECK_START;
+	}
+}
+
+static void
+wait_start_life_check(int timeout)
+{
+	while(WatchDog_Info.LifeCheckStartFlag == NULL)
+	{
+		sleep(timeout);
+	}
+	while (*WatchDog_Info.LifeCheckStartFlag != LIFE_CHECK_START)
+	{
+		sleep(timeout);
+	}
+
+}
+
+#endif /* USE_REPLICATION */
diff -ruN postgresql-7.4.13-old/src/backend/main/main.c postgresql-7.4.13/src/backend/main/main.c
--- postgresql-7.4.13-old/src/backend/main/main.c	2006-01-05 01:55:23.000000000 +0100
+++ postgresql-7.4.13/src/backend/main/main.c	2006-08-05 16:53:43.000000000 +0200
@@ -41,6 +41,11 @@
 #include "utils/pg_locale.h"
 #include "utils/ps_status.h"
 
+#ifdef USE_REPLICATION
+#include "replicate.h"
+
+PGR_PGCluster_Info * PGCluster_Info = NULL;
+#endif /* USE_REPLICATION */
 
 
 int
diff -ruN postgresql-7.4.13-old/src/backend/postmaster/postmaster.c postgresql-7.4.13/src/backend/postmaster/postmaster.c
--- postgresql-7.4.13-old/src/backend/postmaster/postmaster.c	2006-03-18 23:10:44.000000000 +0100
+++ postgresql-7.4.13/src/backend/postmaster/postmaster.c	2006-08-05 16:53:43.000000000 +0200
@@ -112,6 +112,9 @@
 #include "bootstrap/bootstrap.h"
 #include "pgstat.h"
 
+#ifdef USE_REPLICATION
+#include "replicate.h"
+#endif /* USE_REPLICATION */
 
 #define INVALID_SOCK	(-1)
 
@@ -387,6 +390,13 @@
 	char	   *potential_DataDir = NULL;
 	int			i;
 
+#ifdef USE_REPLICATION
+	if (PGR_Init_PGCluster_Info() != STATUS_OK)
+	{
+		postmaster_error("PGR_Init_PGCluster_Info failed");
+		ExitPostmaster(1);
+	}
+#endif /* USE REPLICATION */
 	*original_extraoptions = '\0';
 
 	progname = argv[0];
@@ -448,10 +458,18 @@
 
 	opterr = 1;
 
-	while ((opt = getopt(argc, argv, "A:a:B:b:c:D:d:Fh:ik:lm:MN:no:p:Ss-:")) != -1)
+	while ((opt = getopt(argc, argv, "A:a:B:b:c:D:d:Fh:ik:lm:MN:no:p:Ss-:R")) != -1)
 	{
 		switch (opt)
 		{
+#ifdef USE_REPLICATION
+			case 'R':
+				if (PGCluster_Info != NULL)
+				{
+					PGCluster_Info->PGR_Recovery_Option = true;
+				}
+				break;
+#endif /* USE_REPLICATION */
 			case 'A':
 #ifdef USE_ASSERT_CHECKING
 				SetConfigOption("debug_assertions", optarg, PGC_POSTMASTER, PGC_S_ARGV);
@@ -481,6 +499,12 @@
 									PGC_POSTMASTER, PGC_S_ARGV);
 					pfree(debugstr);
 					debug_flag = atoi(optarg);
+#ifdef USE_REPLICATION
+					if (PGCluster_Info != NULL)
+					{
+						PGCluster_Info->Com_Info.Log_Info.Log_Print = 1;
+					}
+#endif
 					break;
 				}
 			case 'F':
@@ -610,6 +634,13 @@
 #ifdef EXEC_BACKEND
 	write_nondefault_variables(PGC_POSTMASTER);
 #endif
+#ifdef USE_REPLICATION
+	if (PGR_Get_Cluster_Conf_Data(potential_DataDir) != STATUS_OK)
+	{
+		postmaster_error( "PGR_Get_Cluster_Conf_Data failed");
+		ExitPostmaster(1);
+	}
+#endif /* USE_REPLICATION */
 
 	/*
 	 * Check for invalid combinations of GUC settings.
@@ -894,6 +925,14 @@
 	 */
 	StartupPID = StartupDataBase();
 
+#ifdef USE_REPLICATION
+	if (PGR_startup_lifecheck() != STATUS_OK)
+	{
+		elog(DEBUG1,"PGR_startup_lifecheck failed");
+		ExitPostmaster(1);
+	}
+#endif /* USE_REPLICATION */
+
 	status = ServerLoop();
 
 	/*
@@ -1450,6 +1489,9 @@
 			ereport(FATAL,
 					(errcode(ERRCODE_TOO_MANY_CONNECTIONS),
 					 errmsg("sorry, too many clients already")));
+#ifdef USE_REPLICATION
+			return STATUS_ERROR;
+#endif
 			break;
 		case CAC_OK:
 		default:
@@ -1688,6 +1730,9 @@
 	ereport(DEBUG2,
 			(errmsg_internal("postmaster received signal %d",
 							 postgres_signal_arg)));
+#ifdef USE_REPLICATION
+	PGR_Clear_Children(postgres_signal_arg);
+#endif /* USE_REPLICATION */
 
 	switch (postgres_signal_arg)
 	{
@@ -2582,7 +2627,9 @@
 	 */
 	/* Should I use true instead? */
 	ClosePostmasterPorts(false);
-
+#ifdef USE_REPLICATION
+	PGR_Recovery_Failed();
+#endif /* USE_REPLICATION */
 	proc_exit(status);
 }
 
diff -ruN postgresql-7.4.13-old/src/backend/storage/lmgr/lock.c postgresql-7.4.13/src/backend/storage/lmgr/lock.c
--- postgresql-7.4.13-old/src/backend/storage/lmgr/lock.c	2005-03-01 22:15:26.000000000 +0100
+++ postgresql-7.4.13/src/backend/storage/lmgr/lock.c	2006-08-05 16:53:43.000000000 +0200
@@ -39,6 +39,9 @@
 #include "utils/memutils.h"
 #include "utils/ps_status.h"
 
+#ifdef USE_REPLICATION
+#include "replicate.h"
+#endif /* USE_REPLICATION */
 
 /* This configuration variable is used to set the lock table size */
 int			max_locks_per_xact; /* set by guc.c */
@@ -625,6 +628,13 @@
 									lock, proclock,
 									MyProc, myHolding);
 
+#ifdef USE_REPLICATION
+	if (PGCluster_Info != NULL)
+	{
+		PGCluster_Info->PGR_Check_Lock.status_lock_conflict = status;
+		PGCluster_Info->PGR_Check_Lock.deadlock = false;
+	}
+#endif /* USE_REPLICATION */
 	if (status == STATUS_OK)
 	{
 		/* No conflict with held or previously requested locks */
@@ -634,6 +644,18 @@
 	{
 		Assert(status == STATUS_FOUND);
 
+#ifdef USE_REPLICATION
+		if ((PGCluster_Info != NULL) &&
+			(PGCluster_Info->PGR_Need_Notice == true) &&
+			(PGCluster_Info->PGR_Check_Lock.check_lock_conflict == true))
+		{
+			if (PGR_Notice_Conflict() == STATUS_ERROR)
+			{
+				return FALSE;
+			}
+			PGCluster_Info->PGR_Lock_Noticed = true;
+		}
+#endif /* USE_REPLICATION */
 		/*
 		 * We can't acquire the lock immediately.  If caller specified no
 		 * blocking, remove the proclock entry and return FALSE without
diff -ruN postgresql-7.4.13-old/src/backend/storage/lmgr/proc.c postgresql-7.4.13/src/backend/storage/lmgr/proc.c
--- postgresql-7.4.13-old/src/backend/storage/lmgr/proc.c	2003-10-16 22:59:35.000000000 +0200
+++ postgresql-7.4.13/src/backend/storage/lmgr/proc.c	2006-08-05 16:53:43.000000000 +0200
@@ -52,6 +52,10 @@
 #include "storage/sinval.h"
 #include "storage/spin.h"
 
+#ifdef USE_REPLICATION
+#include "replicate.h"
+#endif /* USE_REPLICATION */
+
 /* GUC variables */
 int			DeadlockTimeout = 1000;
 int			StatementTimeout = 0;
@@ -885,6 +889,9 @@
 	 * RemoveFromWaitQueue took care of waking up any such processes.
 	 */
 	LWLockRelease(LockMgrLock);
+#ifdef USE_REPLICATION
+	PGR_Notice_DeadLock();
+#endif
 }
 
 
diff -ruN postgresql-7.4.13-old/src/backend/tcop/postgres.c postgresql-7.4.13/src/backend/tcop/postgres.c
--- postgresql-7.4.13-old/src/backend/tcop/postgres.c	2005-12-14 18:07:00.000000000 +0100
+++ postgresql-7.4.13/src/backend/tcop/postgres.c	2006-08-05 16:53:43.000000000 +0200
@@ -65,6 +65,9 @@
 
 #include "pgstat.h"
 
+#ifdef USE_REPLICATION
+#include "replicate.h"
+#endif /* USE_REPLICATION */
 extern int	optind;
 extern char *optarg;
 
@@ -735,6 +738,9 @@
 	int			save_log_min_duration_statement = log_min_duration_statement;
 	bool		save_log_statement_stats = log_statement_stats;
 
+#ifdef USE_REPLICATION
+	PGR_init_replication(query_string, strlen(query_string));
+#endif /* USE_REPLICATION */
 	/*
 	 * Report query to various monitoring facilities.
 	 */
@@ -808,17 +814,32 @@
 		Portal		portal;
 		DestReceiver *receiver;
 		int16		format;
-
+#ifdef USE_REPLICATION
+		int status = STATUS_OK;
+#endif /* USE_REPLICATION */
 		/*
 		 * Get the command name for use in status display (it also becomes
 		 * the default completion tag, down inside PortalRun).	Set
 		 * ps_status and do any special start-of-SQL-command processing
 		 * needed by the destination.
 		 */
+#ifdef USE_REPLICATION
+		PGR_init_each_query();
+#endif /* USE_REPLICATION */
 		commandTag = CreateCommandTag(parsetree);
 
+#ifdef USE_REPLICATION
+		 status = PGR_exec_replication(commandTag,dest);
+		if (status !=STATUS_OK)
+		{
+			if (status == STATUS_SKIP_QUERY)
+			{
+				break;
+			}
+			continue;
+		}
+#endif /* USE_REPLICATION */
 		set_ps_display(commandTag);
-
 		BeginCommand(commandTag, dest);
 
 		/*
@@ -831,10 +852,22 @@
 		 */
 		if (IsAbortedTransactionBlockState() &&
 			!IsTransactionExitStmt(parsetree))
+		{
+#if 0
+#ifdef USE_REPLICATION
+ 			if (PGCluster_Info != NULL)
+ 			{
+ 				PGR_Notice_Transaction_Query_Aborted();
+ 			}
+				
+
+#endif /* USE_REPLICATION */
+#endif			
 			ereport(ERROR,
 					(errcode(ERRCODE_IN_FAILED_SQL_TRANSACTION),
 					 errmsg("current transaction is aborted, "
 					 "commands ignored until end of transaction block")));
+		}
 
 		/* Make sure we are in a transaction command */
 		start_xact_command();
@@ -954,6 +987,10 @@
 			CommandCounterIncrement();
 		}
 
+#ifdef USE_REPLICATION
+		PGR_Notice_Transaction_Query_Done();
+		PGR_Wait_Reliable_Trigger(commandTag);
+#endif /* USE_REPLICATION */
 		/*
 		 * Tell client that we're done with this query.  Note we emit
 		 * exactly one EndCommand report for each raw parsetree, thus one
@@ -1138,11 +1175,12 @@
 		 */
 		if (IsAbortedTransactionBlockState() &&
 			!IsTransactionExitStmt(parsetree))
+		{
 			ereport(ERROR,
 					(errcode(ERRCODE_IN_FAILED_SQL_TRANSACTION),
 					 errmsg("current transaction is aborted, "
 					 "commands ignored until end of transaction block")));
-
+		}
 		/*
 		 * OK to analyze, rewrite, and plan this query.  Note that the
 		 * originally specified parameter set is not required to be
@@ -1576,11 +1614,13 @@
 	 */
 	if (IsAbortedTransactionBlockState() &&
 		!IsTransactionExitStmtList(portal->parseTrees))
+	{
 		ereport(ERROR,
 				(errcode(ERRCODE_IN_FAILED_SQL_TRANSACTION),
 				 errmsg("current transaction is aborted, "
 						"commands ignored until end of transaction block")));
-
+	}
+		
 	/* Check for cancel signal before we start execution */
 	CHECK_FOR_INTERRUPTS();
 
@@ -1919,6 +1959,9 @@
 	 * random backend.	This is necessary precisely because we don't clean
 	 * up our shared memory state.
 	 */
+#ifdef USE_REPLICATION
+	PGR_delete_shm();
+#endif /* USE_REPLICATION */
 	exit(1);
 }
 
@@ -1954,6 +1997,9 @@
 			ProcessInterrupts();
 		}
 	}
+#ifdef USE_REPLICATION
+	PGR_delete_shm();
+#endif /* USE_REPLICATION */
 
 	errno = save_errno;
 }
@@ -1969,6 +2015,9 @@
 void
 authdie(SIGNAL_ARGS)
 {
+#ifdef USE_REPLICATION
+	PGR_delete_shm();
+#endif /* USE_REPLICATION */
 	exit(0);
 }
 
@@ -2954,7 +3003,6 @@
 		 */
 		if (ignore_till_sync && firstchar != EOF)
 			continue;
-
 		switch (firstchar)
 		{
 			case 'Q':			/* simple query */
@@ -3142,6 +3190,13 @@
 			case 'X':
 			case EOF:
 
+#ifdef USE_REPLICATION
+				if (PGR_Is_This_Transaction_Committed() == true)
+				{
+					pgstat_report_activity("commit");
+					exec_simple_query("commit");
+				}
+#endif /* USE_REPLICATION */
 				/*
 				 * Reset whereToSendOutput to prevent ereport from
 				 * attempting to send any more messages to client.
diff -ruN postgresql-7.4.13-old/src/backend/tcop/utility.c postgresql-7.4.13/src/backend/tcop/utility.c
--- postgresql-7.4.13-old/src/backend/tcop/utility.c	2005-01-24 18:46:41.000000000 +0100
+++ postgresql-7.4.13/src/backend/tcop/utility.c	2006-08-05 16:53:43.000000000 +0200
@@ -56,6 +56,10 @@
 #include "utils/syscache.h"
 #include "access/xlog.h"
 
+#ifdef USE_REPLICATION
+#include "replicate.h"
+#endif /* USE_REPLICATION */
+
 /*
  * Error-checking support for DROP commands
  */
@@ -1565,5 +1569,8 @@
 			break;
 	}
 
+#ifdef USE_REPLICATION
+	PGR_Set_Replication_Flag(parsetree);
+#endif /* USE_REPLICATION */
 	return tag;
 }
diff -ruN postgresql-7.4.13-old/src/backend/utils/Makefile postgresql-7.4.13/src/backend/utils/Makefile
--- postgresql-7.4.13-old/src/backend/utils/Makefile	2002-09-03 23:45:42.000000000 +0200
+++ postgresql-7.4.13/src/backend/utils/Makefile	2006-08-05 16:53:43.000000000 +0200
@@ -8,7 +8,7 @@
 top_builddir = ../../..
 include $(top_builddir)/src/Makefile.global
 
-SUBDIRS     := adt cache error fmgr hash init misc mmgr sort time mb
+SUBDIRS     := adt cache error fmgr hash init misc mmgr sort time mb pgcluster
 SUBDIROBJS  := $(SUBDIRS:%=%/SUBSYS.o)
 
 
diff -ruN postgresql-7.4.13-old/src/backend/utils/adt/float.c postgresql-7.4.13/src/backend/utils/adt/float.c
--- postgresql-7.4.13-old/src/backend/utils/adt/float.c	2003-09-25 08:58:03.000000000 +0200
+++ postgresql-7.4.13/src/backend/utils/adt/float.c	2006-08-05 16:53:43.000000000 +0200
@@ -69,6 +69,9 @@
 #include "utils/array.h"
 #include "utils/builtins.h"
 
+#ifdef USE_REPLICATION
+#include "replicate.h"
+#endif /* USE_REPLICATION */
 
 #ifndef HAVE_CBRT
 static double cbrt(double x);
@@ -1594,7 +1597,11 @@
 	float8		result;
 
 	/* result 0.0-1.0 */
+#ifdef USE_REPLICATION
+	result = ((double) PGR_Random()) / ((double) MAX_RANDOM_VALUE);
+#else
 	result = ((double) random()) / ((double) MAX_RANDOM_VALUE);
+#endif /* USE_REPLICATION */
 
 	PG_RETURN_FLOAT8(result);
 }
diff -ruN postgresql-7.4.13-old/src/backend/utils/adt/nabstime.c postgresql-7.4.13/src/backend/utils/adt/nabstime.c
--- postgresql-7.4.13-old/src/backend/utils/adt/nabstime.c	2005-05-26 04:14:31.000000000 +0200
+++ postgresql-7.4.13/src/backend/utils/adt/nabstime.c	2006-08-05 16:53:43.000000000 +0200
@@ -27,6 +27,9 @@
 #include "miscadmin.h"
 #include "utils/builtins.h"
 
+#ifdef USE_REPLICATION
+#include "replicate.h"
+#endif /* USE_REPLICATION */
 
 #define MIN_DAYNUM -24856		/* December 13, 1901 */
 #define MAX_DAYNUM 24854		/* January 18, 2038 */
@@ -110,7 +113,11 @@
 	time_t		now;
 	struct timeval tp;
 
+#ifdef USE_REPLICATION
+	PGR_GetTimeOfDay(&tp,NULL);
+#else
 	gettimeofday(&tp, NULL);
+#endif /* USE_REPLICATION */
 	now = tp.tv_sec;
 	*usec = tp.tv_usec;
 	return (AbsoluteTime) now;
@@ -149,7 +156,19 @@
 {
 	int			tz;
 
+#ifdef USE_REPLICATION
+	if ((PGCluster_Info != NULL) &&
+		(PGCluster_Info->ReplicateCurrentTime->useFlag == DATA_USE))
+	{
+		abstime2tm( GetCurrentAbsoluteTime() , &tz, tm, NULL);
+	}
+	else
+	{
+		abstime2tm(GetCurrentTransactionStartTime(), &tz, tm, NULL);
+	}
+#else	
 	abstime2tm(GetCurrentTransactionStartTime(), &tz, tm, NULL);
+#endif
 }
 
 /*
@@ -164,7 +183,19 @@
 	int			tz;
 	int			usec;
 
+#ifdef USE_REPLICATION
+	if ((PGCluster_Info != NULL) &&
+		(PGCluster_Info->ReplicateCurrentTime->useFlag == DATA_USE))
+	{
+		abstime2tm( GetCurrentAbsoluteTimeUsec(&usec) , &tz, tm, NULL);
+	}
+	else
+	{
+		abstime2tm(GetCurrentTransactionStartTimeUsec(&usec), &tz, tm, NULL);
+	}
+#else	
 	abstime2tm(GetCurrentTransactionStartTimeUsec(&usec), &tz, tm, NULL);
+#endif /* USE_REPLICATION */
 	/* Note: don't pass NULL tzp to abstime2tm; affects behavior */
 	if (tzp != NULL)
 		*tzp = tz;
@@ -1726,7 +1757,11 @@
 	int			len;
 	time_t		tt;
 
+#ifdef USE_REPLICATION
+	PGR_GetTimeOfDay(&tp,&tpz);
+#else
 	gettimeofday(&tp, &tpz);
+#endif /* USE_REPLICATION */
 	tt = (time_t) tp.tv_sec;
 	strftime(templ, sizeof(templ), "%a %b %d %H:%M:%S.%%06d %Y %Z",
 			 localtime(&tt));
diff -ruN postgresql-7.4.13-old/src/backend/utils/error/assert.c postgresql-7.4.13/src/backend/utils/error/assert.c
--- postgresql-7.4.13-old/src/backend/utils/error/assert.c	2003-08-04 04:40:06.000000000 +0200
+++ postgresql-7.4.13/src/backend/utils/error/assert.c	2006-08-05 16:53:43.000000000 +0200
@@ -19,6 +19,9 @@
 
 #include <unistd.h>
 
+#ifdef USE_REPLICATION
+#include "replicate.h"
+#endif /* USE_REPLICATION */
 /*
  * ExceptionalCondition - Handles the failure of an Assert()
  */
@@ -39,6 +42,9 @@
 				fileName, lineNumber);
 	}
 
+#ifdef USE_REPLICATION
+	PGR_ExceptionalCondition();
+#endif /* USE_REPLICATION */
 #ifdef SLEEP_ON_ASSERT
 	sleep(1000000);
 #endif
diff -ruN postgresql-7.4.13-old/src/backend/utils/error/elog.c postgresql-7.4.13/src/backend/utils/error/elog.c
--- postgresql-7.4.13-old/src/backend/utils/error/elog.c	2005-10-20 03:31:50.000000000 +0200
+++ postgresql-7.4.13/src/backend/utils/error/elog.c	2006-08-05 16:53:43.000000000 +0200
@@ -63,6 +63,9 @@
 #include "utils/memutils.h"
 #include "utils/guc.h"
 
+#ifdef USE_REPLICATION
+#include "replicate.h"
+#endif /* USE_REPLICATION */
 
 /* Global variables */
 ErrorContextCallback *error_context_stack = NULL;
@@ -348,7 +351,22 @@
 	 * output_to_client.
 	 */
 	if (elevel >= ERROR && whereToSendOutput == Remote)
+	{
+#ifdef USE_REPLICATION
+		PGR_Elog_Abort_Copy();
+#endif /* USE_REPLICATION */
 		pq_endcopyout(true);
+	}
+
+#ifdef USE_REPLICATION
+	if (elevel == ERROR &&
+			!ExitOnAnyError &&
+			Warn_restart_ready &&
+			!proc_exit_inprogress)
+	{
+		PGR_Elog_Warn_Proc(edata->message,edata->detail);
+	}
+#endif /* USE_REPLICATION */
 
 	/* Send to client, if enabled */
 	if (edata->output_to_client)
@@ -445,6 +463,9 @@
 			 */
 			fflush(stdout);
 			fflush(stderr);
+#ifdef USE_REPLICATION
+			PGR_Elog_Abort_Proc(0);
+#endif /* USE_REPLICATION */
 			proc_exit(proc_exit_inprogress || !IsUnderPostmaster);
 		}
 
@@ -473,6 +494,9 @@
 		ImmediateInterruptOK = false;
 		fflush(stdout);
 		fflush(stderr);
+#ifdef USE_REPLICATION
+		PGR_Elog_Abort_Proc(PGR_RECV_TIMEOUT);
+#endif /* USE_REPLICATION */
 		abort();
 	}
 
diff -ruN postgresql-7.4.13-old/src/backend/utils/fmgr/dfmgr.c postgresql-7.4.13/src/backend/utils/fmgr/dfmgr.c
--- postgresql-7.4.13-old/src/backend/utils/fmgr/dfmgr.c	2003-09-25 08:58:05.000000000 +0200
+++ postgresql-7.4.13/src/backend/utils/fmgr/dfmgr.c	2006-08-05 16:53:43.000000000 +0200
@@ -21,6 +21,9 @@
 #include "miscadmin.h"
 #include "utils/dynamic_loader.h"
 
+#ifdef USE_REPLICATION
+#include "replicate.h"
+#endif /* USE_REPLICATION */
 
 /*
  * List of dynamically loaded files (kept in malloc'd memory).
@@ -74,6 +77,9 @@
 	char	   *load_error;
 	struct stat stat_buf;
 	char	   *fullname;
+#ifdef USE_REPLICATION
+	int status = STATUS_OK;
+#endif /* USE_REPLICATION */
 
 	fullname = expand_dynamic_library_name(filename);
 	if (!fullname)
@@ -166,6 +172,13 @@
 						funcname, fullname)));
 
 	pfree(fullname);
+#ifdef USE_REPLICATION
+	status = PGR_Replicate_Function_Call();
+	if (status != STATUS_OK)
+	{
+		return NULL;
+	}
+#endif /* USE_REPLICATION */
 	return retval;
 }
 
diff -ruN postgresql-7.4.13-old/src/backend/utils/mb/mbutils.c postgresql-7.4.13/src/backend/utils/mb/mbutils.c
--- postgresql-7.4.13-old/src/backend/utils/mb/mbutils.c	2006-05-21 22:06:44.000000000 +0200
+++ postgresql-7.4.13/src/backend/utils/mb/mbutils.c	2006-08-05 16:53:43.000000000 +0200
@@ -16,6 +16,9 @@
 #include "utils/syscache.h"
 #include "catalog/namespace.h"
 
+#ifdef USE_REPLICATION
+#include "replicate.h"
+#endif /* USE_REPLICATION */
 /*
  * We handle for actual FE and BE encoding setting encoding-identificator
  * and encoding-name too. It prevent searching and conversion from encoding
@@ -452,6 +455,14 @@
 				dest_encoding;
 	FmgrInfo   *flinfo;
 
+#ifdef USE_REPLICATION
+	if ((PGCluster_Info != NULL) &&
+		(PGCluster_Info->PGR_Is_Replicated_Query))
+	{
+		return src;
+	}
+#endif /* USE_REPLICATION */
+
 	if (is_client_to_server)
 	{
 		src_encoding = ClientEncoding->encoding;
diff -ruN postgresql-7.4.13-old/src/backend/utils/pgcluster/Makefile postgresql-7.4.13/src/backend/utils/pgcluster/Makefile
--- postgresql-7.4.13-old/src/backend/utils/pgcluster/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ postgresql-7.4.13/src/backend/utils/pgcluster/Makefile	2006-08-05 16:53:43.000000000 +0200
@@ -0,0 +1,29 @@
+subdir = src/backend/utils/pgcluster
+top_builddir = ../../../..
+include $(top_builddir)/src/Makefile.global
+
+override CPPFLAGS := -I$(srcdir) $(CPPFLAGS)
+
+OBJS = replicate.o recovery.o
+
+# This location might depend on the installation directories. Therefore
+# we can't subsitute it into config.h.
+ifdef krb_srvtab
+override CPPFLAGS += -DPG_KRB_SRVTAB='"$(krb_srvtab)"'
+endif
+
+
+all: SUBSYS.o
+
+SUBSYS.o: $(OBJS)
+	$(LD) $(LDREL) $(LDOUT) SUBSYS.o $(OBJS)
+
+clean: 
+	rm -f SUBSYS.o $(OBJS)
+
+depend dep:
+	$(CC) -MM $(CFLAGS) *.c >depend
+
+ifeq (depend,$(wildcard depend))
+include depend
+endif
diff -ruN postgresql-7.4.13-old/src/backend/utils/pgcluster/cluster.conf.sample postgresql-7.4.13/src/backend/utils/pgcluster/cluster.conf.sample
--- postgresql-7.4.13-old/src/backend/utils/pgcluster/cluster.conf.sample	1970-01-01 01:00:00.000000000 +0100
+++ postgresql-7.4.13/src/backend/utils/pgcluster/cluster.conf.sample	2006-08-05 16:53:43.000000000 +0200
@@ -0,0 +1,60 @@
+#============================================================
+#          Cluster DB Server configuration file
+#------------------------------------------------------------
+# file: cluster.conf
+#------------------------------------------------------------
+# This file controls:
+#       o which hosts & port are replication server
+#       o which port use for replication request to replication server
+#       o which command use for recovery function
+#============================================================
+#------------------------------------------------------------
+# set Replication Server information
+#		o Host_Name : hostname
+#		o Port : connection for postmaster
+#		o Recovery_Port : connection for recovery process
+#------------------------------------------------------------
+<Replicate_Server_Info>
+	<Host_Name> replicate1.postgres.jp </Host_Name>
+	<Port> 8001 </Port>
+	<Recovery_Port> 8101 </Recovery_Port>
+	<LifeCheck_Port> 8201 </LifeCheck_Port>
+</Replicate_Server_Info>
+#<Replicate_Server_Info>
+#	<Host_Name> replicate2.postgres.jp </Host_Name>
+#	<Port> 8002 </Port>
+#	<Recovery_Port> 8102 </Recovery_Port>
+#	<LifeCheck_Port> 8202 </LifeCheck_Port>
+#</Replicate_Server_Info>
+#<Replicate_Server_Info>
+#	<Host_Name> replicate3.postgres.jp </Host_Name>
+#	<Port> 8003 </Port>
+#	<Recovery_Port> 8103 </Recovery_Port>
+#	<LifeCheck_Port> 8203 </LifeCheck_Port>
+#</Replicate_Server_Info>
+#-------------------------------------------------------------
+# set Cluster DB Server information
+#		o Recovery_Port : connection for recovery
+#		o Rsync_Path : path of rsync command 
+#		o Rsync_Option : file transfer option for rsync
+#       o When_Stand_Alone : When all replication servers fell,
+#                            you can set up two kinds of permittion,
+#                            "real_only" or "read_write".
+#-------------------------------------------------------------
+<Recovery_Port> 7101 </Recovery_Port>
+<LifeCheck_Port> 7201 </LifeCheck_Port>
+<Rsync_Path> /usr/bin/rsync </Rsync_Path>
+<Rsync_Option> ssh -1 </Rsync_Option>
+<When_Stand_Alone> read_only  </When_Stand_Alone>
+<Status_Log_File>  /tmp/cluster.sts </Status_Log_File>
+<Error_Log_File> /tmp/cluster.log  </Error_Log_File>
+#-------------------------------------------------------------
+# set partitional replicate control information
+#     set DB name and Table name to stop reprication
+#       o DB_Name : DB name
+#       o Table_Name : table name
+#-------------------------------------------------------------
+#<Not_Replicate_Info>
+#	<DB_Name>     test_db      </DB_Name>
+#	<Table_Name>  log_table    </Table_Name>
+#</Not_Replicate_Info>
diff -ruN postgresql-7.4.13-old/src/backend/utils/pgcluster/recovery.c postgresql-7.4.13/src/backend/utils/pgcluster/recovery.c
--- postgresql-7.4.13-old/src/backend/utils/pgcluster/recovery.c	1970-01-01 01:00:00.000000000 +0100
+++ postgresql-7.4.13/src/backend/utils/pgcluster/recovery.c	2006-08-05 16:53:43.000000000 +0200
@@ -0,0 +1,1015 @@
+/*--------------------------------------------------------------------
+ * FILE:
+ *     recovery.c
+ *
+ * NOTE:
+ *     This file is composed of the functions to call with the source
+ *     at backend for the recovery.
+ *     Low level I/O functions that called by in these functions are 
+ *     contained in 'replicate_com.c'.
+ *
+ *--------------------------------------------------------------------
+ */
+
+/*--------------------------------------
+ * INTERFACE ROUTINES
+ *
+ * I/O call:
+ *      PGR_recovery_finish_send
+ * master module:
+ *      PGR_Master_Main(void);
+ * recovery module:
+ *      PGR_Recovery_Main
+ *-------------------------------------
+ */
+#ifdef USE_REPLICATION
+
+#include "postgres.h"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sys/wait.h>
+#include <ctype.h>
+#include <time.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <time.h>
+#include <sys/param.h>
+#include <sys/select.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+#include <sys/file.h>
+#include <dirent.h>
+
+#include "libpq/pqsignal.h"
+#include "utils/guc.h"
+#include "miscadmin.h"
+#include "nodes/nodes.h"
+#include "nodes/parsenodes.h"
+#include "access/xact.h"
+#include "access/xlog.h"
+#include "tcop/tcopprot.h"
+
+#include "replicate.h"
+
+#ifdef WIN32
+#include "win32.h"
+#else
+#ifdef HAVE_NETINET_TCP_H
+#include <netinet/tcp.h>
+#endif
+#include <arpa/inet.h>
+#endif
+
+#ifndef HAVE_STRDUP
+#include "strdup.h"
+#endif
+#ifdef HAVE_CRYPT_H
+#include <crypt.h>
+#endif
+
+#ifdef MULTIBYTE
+#include "mb/pg_wchar.h"
+#endif
+
+#ifdef HAVE_SIGPROCMASK
+sigset_t	UnBlockSig,
+			BlockSig,
+			AuthBlockSig;
+
+#else
+int			UnBlockSig,
+			BlockSig,
+			AuthBlockSig;
+#endif
+
+#define RECOVERY_LOOP_END	(0)
+#define RECOVERY_LOOP_CONTINUE	(1)
+#define RECOVERY_LOOP_FAIL	(2)
+char Local_Host_Name[HOSTNAME_MAX_LENGTH];
+
+static int read_packet(int sock,RecoveryPacket * packet);
+static int send_recovery_packet(int  sock, RecoveryPacket * packet);
+static int send_packet(int * sock, RecoveryPacket * packet );
+static void master_loop(int fd);
+static int start_recovery_send(int * sock, ReplicateServerInfo * host);
+static int stop_recovery_send(int * sock, ReplicateServerInfo * host);
+static int rsync_pg_data(char * src , char * dest);
+static int remove_dir(char * dir_name);
+static int clear_bkup_dir(char * dir_name);
+static int bkup_dir(char * dir_name);
+static int restore_dir(char * dir_name);
+static int rsync_global_dir(char * src, char * dest);
+static int first_recovery(char * src, char * dest, char * dir);
+static int second_recovery(char * src, char * dest, char * dir);
+static int recovery_rsync(char * src , char * dest, int stage);
+static int recovery_loop(int fd);
+static void show_recovery_packet(RecoveryPacket * packet);
+static int direct_send_packet(int packet_no);
+static void set_recovery_packet(RecoveryPacket * packet, int packet_no);
+
+int PGR_recovery_error_send(void);
+int PGR_recovery_finish_send(void);
+int PGR_Master_Main(void);
+int PGR_Recovery_Main(void);
+
+static int
+read_packet(int sock,RecoveryPacket * packet)
+{
+	int r;
+	char * read_ptr;
+	int read_size = 0;
+	int packet_size = 0;
+	int cnt = 0;
+
+	read_ptr = (char*)packet;
+	packet_size = sizeof(RecoveryPacket);
+	for (;;){
+		r = recv(sock,read_ptr + read_size ,packet_size, MSG_WAITALL);
+		if (r < 0){
+			if (errno == EINTR)
+			{
+				continue;
+			}
+#ifdef EAGAIN
+			else if (errno == EAGAIN)
+			{
+				usleep(PGR_RECV_WAIT_MSEC);
+				continue;
+			}
+#endif /* EAGAIN */
+#ifdef ECONNREFUSED
+			else if (errno == ECONNREFUSED)
+			{
+				usleep(PGR_RECV_WAIT_MSEC);
+				continue;
+			}
+#endif /* ECONNREFUSED */
+#ifdef ENOTCONN
+			else if (errno == ENOTCONN)
+			{
+				usleep(PGR_RECV_WAIT_MSEC);
+				continue;
+			}
+#endif /* ENOTCONN */
+			if (cnt < PGR_RECV_RETRY_CNT )
+			{
+				cnt ++;
+				usleep(PGR_RECV_WAIT_MSEC);
+				continue;
+			}
+			else
+			{
+				if (read_size == 0)
+				{
+					return -1;
+				}
+			}
+			return -1;
+		}
+		if (r > 0)
+		{
+			read_size += r;
+			if (read_size == packet_size)
+			{
+				show_recovery_packet(packet);
+				return read_size;
+			}
+		}
+		if ((r == 0) && (read_size == 0))
+		{
+			return -1;
+		}
+		if (cnt < PGR_RECV_RETRY_CNT )
+		{
+			cnt ++;
+			usleep(PGR_RECV_WAIT_MSEC);
+			continue;
+		}
+		else
+		{
+			return -1;
+		}
+	}
+}
+
+static int
+send_recovery_packet(int  sock, RecoveryPacket * packet)
+{
+
+	char * send_ptr;
+	int send_size= 0;
+	int buf_size = 0;
+	int s;
+	int rtn;	
+	fd_set	  wmask;
+	struct timeval timeout;
+
+	timeout.tv_sec = PGR_SEND_TIMEOUT;
+	timeout.tv_usec = 0;
+
+	/*
+	 * Wait for something to happen.
+	 */
+	FD_ZERO(&wmask);
+	FD_SET(sock,&wmask);
+	rtn = select(sock+1, (fd_set *)NULL, &wmask, (fd_set *)NULL, &timeout);
+	if (rtn && FD_ISSET(sock, &wmask))
+	{
+		send_ptr = (char *)packet;
+		buf_size = sizeof(RecoveryPacket);
+
+		for (;;)
+		{
+			s = send(sock,send_ptr + send_size,buf_size - send_size ,0);
+			if (s < 0){
+				if (errno == EINTR)
+				{
+					continue;
+				}
+				return STATUS_ERROR;
+			}
+			if (s > 0)
+			{
+				send_size += s;
+				if (send_size == buf_size)
+				{
+					return STATUS_OK;
+				}
+			}
+		}
+	}
+	return STATUS_ERROR;
+}
+
+static int
+send_packet(int * sock, RecoveryPacket * packet )
+{
+
+	int count = 0;
+	ReplicateServerInfo * host = NULL;
+
+	host = PGR_get_replicate_server_info();
+	if (host == (ReplicateServerInfo*)NULL)
+	{
+		return STATUS_ERROR;
+	}
+	count = 0;
+	while (send_recovery_packet(*sock,packet) != STATUS_OK)
+	{
+		if (count < MAX_RETRY_TIMES )
+		{
+			count ++;
+			continue;
+		}
+		count = 0;
+		close(*sock);
+		PGR_Set_Replication_Server_Status(host,DATA_ERR);
+		host = PGR_get_replicate_server_info();
+		if (host == (ReplicateServerInfo*)NULL)
+		{
+			return STATUS_ERROR;
+		}
+		PGR_Set_Replication_Server_Status(host,DATA_USE);
+		PGR_Create_Socket_Connect(sock, host->hostName , host->recoveryPortNumber);
+	}
+	return STATUS_OK;
+}
+
+static void
+master_loop(int fd)
+{
+
+	int count;
+	int sock;
+	int status = STATUS_OK;
+	RecoveryPacket packet;
+	int r_size = 0;
+	bool loop_end = false;
+
+	if (PGCluster_Info == NULL)
+	{
+		return;
+	}
+	count = 0;
+	while ((status = PGR_Create_Acception(fd,&sock,"",PGCluster_Info->Com_Info.ConfData_Info.Recovery_Port_Number)) != STATUS_OK)
+	{
+		PGR_Close_Sock(&sock);
+		sock = -1;
+		if ( count > MAX_RETRY_TIMES)
+		{
+			return;
+		}
+		count ++;
+	}
+	for(;;)
+	{
+		int	rtn;
+		fd_set	  rmask;
+		struct timeval timeout;
+
+		timeout.tv_sec = PGR_RECV_TIMEOUT;
+		timeout.tv_usec = 0;
+
+		/*
+		 * Wait for something to happen.
+		 */
+		FD_ZERO(&rmask);
+		FD_SET(sock,&rmask);
+		rtn = select(sock+1, &rmask, (fd_set *)NULL, (fd_set *)NULL, &timeout);
+		if (rtn && FD_ISSET(sock, &rmask))
+		{
+			r_size = read_packet(sock,&packet);
+			if (r_size <= 0)
+			{
+				continue;
+			}
+		}
+		else
+		{
+			continue;
+		}
+		switch (ntohs(packet.packet_no))
+		{
+			case RECOVERY_PGDATA_REQ :
+				/*
+				 * PGDATA information request
+				 */
+				/*
+				 * get master server information
+				 */
+				memset(&packet,0,sizeof(packet));
+				set_recovery_packet(&packet, RECOVERY_PGDATA_ANS) ;
+				status = send_packet(&sock,&packet);
+				PGR_Set_Cluster_Status(STATUS_RECOVERY);
+				break;
+			case RECOVERY_FSYNC_REQ : 
+				/*
+				 * get master server information
+				 */
+				memset(&packet,0,sizeof(packet));
+				set_recovery_packet(&packet, RECOVERY_FSYNC_ANS );
+				status = send_packet(&sock,&packet);
+				PGR_Set_Cluster_Status(STATUS_RECOVERY);
+				loop_end = true;
+				break;
+			case RECOVERY_ERROR_CONNECTION:
+				memset(&packet,0,sizeof(packet));
+				set_recovery_packet(&packet, RECOVERY_ERROR_ANS );
+				status = send_packet(&sock,&packet);
+				PGR_Set_Cluster_Status(STATUS_REPLICATE);
+				loop_end = true;
+				break;
+			case RECOVERY_ERROR_ANS:
+			case RECOVERY_FINISH:
+				PGR_Set_Cluster_Status(STATUS_REPLICATE);
+				loop_end = true;
+				break;
+		}
+		if (loop_end)
+		{
+			break;
+		}
+	}
+	PGR_Close_Sock(&sock);
+}
+
+int
+PGR_Master_Main(void)
+{
+	int status;
+	int fd = -1;
+	int rtn;
+	int pid;
+
+	if (PGCluster_Info == NULL)
+	{
+		return -1;
+	}
+	if ((pid = fork()) != 0 )
+	{
+		return pid;
+	}
+	
+	memset(Local_Host_Name,0,sizeof(Local_Host_Name));
+	gethostname(Local_Host_Name,sizeof(Local_Host_Name));
+	pqsignal(SIGHUP, authdie);
+	pqsignal(SIGTERM, authdie);
+	pqsignal(SIGQUIT, authdie);
+	pqsignal(SIGALRM, authdie);
+	PG_SETMASK(&AuthBlockSig);
+
+	status = STATUS_ERROR;
+	status = PGR_Create_Socket_Bind(&fd, "", PGCluster_Info->Com_Info.ConfData_Info.Recovery_Port_Number);
+
+	if (status != STATUS_OK)
+	{
+		return pid;
+	}
+	for (;;)
+	{
+		fd_set	  rmask;
+		struct timeval timeout;
+
+		timeout.tv_sec = 60;
+		timeout.tv_usec = 0;
+
+		/*
+		 * Wait for something to happen.
+		 */
+		FD_ZERO(&rmask);
+		FD_SET(fd,&rmask);
+		rtn = select(fd+1, &rmask, (fd_set *)NULL, (fd_set *)NULL, &timeout);
+		if (rtn && FD_ISSET(fd, &rmask))
+		{
+			master_loop(fd);
+		}
+	}
+	return pid;
+}
+
+static int
+start_recovery_send(int * sock, ReplicateServerInfo * host)
+{
+	int status;
+	RecoveryPacket packet;
+	status = PGR_Create_Socket_Connect(sock, host->hostName, host->recoveryPortNumber);
+	if (status != STATUS_OK)
+	{
+		if (Debug_pretty_print)
+		{
+			elog(DEBUG1,"connection error to replication server");
+		}
+		return STATUS_ERROR;
+	}
+
+	memset(&packet,0,sizeof(packet));
+	set_recovery_packet(&packet, RECOVERY_PREPARE_REQ );
+	status = send_packet(sock,&packet);
+
+	return status;
+}
+
+static int
+stop_recovery_send(int * sock, ReplicateServerInfo * host)
+{
+	int status;
+	RecoveryPacket packet;
+	memset(&packet,0,sizeof(packet));
+	set_recovery_packet(&packet, RECOVERY_ERROR_ANS );
+	status = send_packet(sock,&packet);
+	return status;
+}
+
+static int
+direct_send_packet(int packet_no)
+{
+
+	int status;
+	int fd = -1;
+	ReplicateServerInfo * host;
+	RecoveryPacket packet;
+
+	host = PGR_get_replicate_server_info();
+	if (host == NULL)
+	{
+		return STATUS_ERROR;
+	}
+	status = PGR_Create_Socket_Connect(&fd, host->hostName, host->recoveryPortNumber);
+	if (status != STATUS_OK)
+	{
+		PGR_Set_Replication_Server_Status(host,DATA_ERR);
+		return STATUS_ERROR;
+	}
+
+	memset(&packet,0,sizeof(packet));
+	set_recovery_packet(&packet, packet_no );
+	status = send_packet(&fd,&packet);
+
+	close(fd);
+
+	return status;
+}
+
+int
+PGR_recovery_error_send(void)
+{
+	return direct_send_packet(RECOVERY_ERROR_ANS);
+}
+
+int
+PGR_recovery_finish_send(void)
+{
+	return direct_send_packet(RECOVERY_FINISH);
+}
+
+static int
+rsync_pg_data(char * src, char * dest)
+{
+	int status;
+	char *args[12];
+	int pid;
+
+	args[0] = "rsync";
+	args[1] = "-a";
+	args[2] = "-r";
+	args[3] = "-z";
+	args[4] = "--delete";
+	args[5] = "-e";
+	args[6] = PGCluster_Info->RsyncOption;
+	args[7] = src;
+	args[8] = dest;
+	args[9] = NULL;
+	pid = fork();
+	if (pid == 0)
+	{
+		status = execv(PGCluster_Info->RsyncPath,args);
+	}
+	else
+	{
+		while (waitpid(pid, &status, WNOHANG) < 0 ) 
+		{
+			if (errno != EINTR)
+				return STATUS_ERROR;
+			usleep(10);
+		}
+	}
+	return STATUS_OK;
+}
+
+static int
+remove_dir(char * dir_name)
+{
+	DIR * dp = NULL;
+	struct dirent *dirp = NULL;
+	char fname[256];
+	int status = 0;
+
+	if ((dp = opendir(dir_name)) == NULL)
+	{
+		return STATUS_ERROR;
+	}
+	while ((dirp = readdir(dp)) != NULL)
+	{
+		if ((!strcmp(dirp->d_name,".")) ||
+			(!strcmp(dirp->d_name,"..")))
+		{
+			continue;
+		}
+		sprintf(fname,"%s/%s",dir_name,dirp->d_name);
+		status = remove(fname);
+		if (status < 0)
+		{
+			remove_dir(fname);
+		}
+	}
+	closedir(dp);
+	if (remove(dir_name) < 0)
+	{
+		return STATUS_ERROR;
+	}
+	return STATUS_OK;
+}
+
+static int
+clear_bkup_dir(char * dir_name)
+{
+	char bkp_dir[256];
+	pid_t pid = getpid();
+
+	sprintf(bkp_dir,"%s_%d",dir_name,pid);
+	return (remove_dir(bkp_dir));
+}
+
+static int
+bkup_dir(char * dir_name)
+{
+	int cnt = 0;
+	char org_dir[256];
+	char bkp_dir[256];
+	pid_t pid = getpid();
+
+	sprintf(org_dir,"%s",dir_name);
+	sprintf(bkp_dir,"%s_%d",dir_name,pid);
+	cnt = 0;
+	while (rename(org_dir,bkp_dir) < 0)
+	{
+		remove_dir(bkp_dir);
+		if (cnt > MAX_RETRY_TIMES )
+		{
+			return STATUS_ERROR;
+		}
+		sleep(1);
+		cnt ++;
+	}
+	return STATUS_OK;
+}
+
+static int
+restore_dir(char * dir_name)
+{
+	int  cnt = 0;
+	char org_dir[256];
+	char bkp_dir[256];
+	pid_t pid = getpid();
+
+	sprintf(org_dir,"%s",dir_name);
+	sprintf(bkp_dir,"%s_%d",dir_name,pid);
+	cnt = 0;
+	while (rename(bkp_dir,org_dir) < 0)
+	{
+		remove_dir(org_dir);
+		if (cnt > MAX_RETRY_TIMES )
+		{
+			return STATUS_ERROR;
+		}
+		sleep(1);
+		cnt ++;
+	}
+	return STATUS_OK;
+}
+
+static int
+rsync_global_dir(char * src, char * dest)
+{
+	int status;
+	char control_file[256];
+	char org_dir[256];
+	char src_dir[256];
+	struct stat fstat;
+	int cnt = 0;
+
+	sprintf(org_dir,"%s/global",dest);
+	sprintf(control_file,"%s/global/pg_control",dest);
+	if (bkup_dir(org_dir) != STATUS_OK)
+	{
+		return STATUS_ERROR;
+	}
+	sprintf(src_dir,"%s/global",src);
+	status = rsync_pg_data(src_dir, dest);
+	if (status != STATUS_OK )
+	{
+		restore_dir(org_dir);
+		return STATUS_ERROR;
+	}
+	/* check pg_control file */
+	cnt = 0;
+	while (stat(control_file,&fstat) < 0)
+	{
+		if (cnt > MAX_RETRY_TIMES )
+		{
+			restore_dir(org_dir);
+			return STATUS_ERROR;
+		}
+		cnt ++;
+		sleep(1);
+	}
+	clear_bkup_dir(org_dir);
+	return STATUS_OK;
+}
+
+static int
+first_recovery(char * src, char * dest, char * dir)
+{
+	int status = STATUS_OK;
+	char src_dir[256];
+	char dest_dir[256];
+
+	memset(src_dir,0,sizeof(src_dir));
+	memset(dest_dir,0,sizeof(dest_dir));
+	sprintf(src_dir,"%s/%s",src,dir);
+	sprintf(dest_dir,"%s/%s",dest,dir);
+	status = bkup_dir(dest_dir);
+	if (status < 0)
+	{
+		return STATUS_ERROR;
+	}
+	status = rsync_pg_data(src_dir, dest);
+	if (status != STATUS_OK )
+	{
+		restore_dir(dest_dir);
+		return STATUS_ERROR;
+	}
+	return STATUS_OK;
+}
+
+static int
+second_recovery(char * src, char * dest, char * dir)
+{
+	int status = STATUS_OK;
+	char src_dir[256];
+	char dest_dir[256];
+
+	memset(src_dir,0,sizeof(src_dir));
+	memset(dest_dir,0,sizeof(dest_dir));
+	sprintf(src_dir,"%s/%s",src,dir);
+	sprintf(dest_dir,"%s/%s",dest,dir);
+
+	status = rsync_pg_data(src_dir, dest);
+	if (status != STATUS_OK )
+	{
+		restore_dir(dest_dir);
+		return STATUS_ERROR;
+	}
+	clear_bkup_dir(dest_dir);
+
+	return STATUS_OK;
+}
+
+static int
+recovery_rsync(char * src , char * dest, int stage)
+{
+	if ((src== NULL) || ( dest == NULL))
+	{
+		return STATUS_ERROR;
+	}
+
+	/* recovery step of "global" directory */
+	fprintf(stderr,"%s recovery step of [global] directory...",
+			((stage == 1)?"1st":"2nd"));
+	if (rsync_global_dir(src, dest) != STATUS_OK)
+	{
+		fprintf(stderr,"NG\n");
+		return STATUS_ERROR;
+	}
+	fprintf(stderr,"OK\n");
+
+	if (stage == PGR_1ST_RECOVERY)
+	{
+		/* 1st recovery step of "base" directory */
+		fprintf(stderr,"1st recovery step of [base] directory...");
+		if (first_recovery(src,dest,"base") != STATUS_OK)
+		{
+			fprintf(stderr,"NG\n");
+			return STATUS_ERROR;
+		}
+		fprintf(stderr,"OK\n");
+
+		fprintf(stderr,"1st recovery step of [pg_clog] directory...");
+		/* 1st recovery step of "pg_clog" directory */
+		if (first_recovery(src,dest,"pg_clog") != STATUS_OK)
+		{
+			fprintf(stderr,"NG\n");
+			return STATUS_ERROR;
+		}
+		fprintf(stderr,"OK\n");
+
+		fprintf(stderr,"1st recovery step of [pg_xlog] directory...");
+		/* 1st recovery step of "pg_xlog" directory */
+		if (first_recovery(src,dest,"pg_xlog") != STATUS_OK)
+		{
+			fprintf(stderr,"NG\n");
+			return STATUS_ERROR;
+		}
+		fprintf(stderr,"OK\n");
+
+	}
+	else
+	{
+		/* 2nd recovery step of "base" directory */
+		fprintf(stderr,"2nd recovery step of [base] directory...");
+		if (second_recovery(src,dest,"base") != STATUS_OK)
+		{
+			fprintf(stderr,"NG\n");
+			return STATUS_ERROR;
+		}
+		fprintf(stderr,"OK\n");
+
+		/* 2nd recovery step of "pg_clog" directory */
+		fprintf(stderr,"2nd recovery step of [pg_clog] directory...");
+		if (second_recovery(src,dest,"pg_clog") != STATUS_OK)
+		{
+			fprintf(stderr,"NG\n");
+			return STATUS_ERROR;
+		}
+		fprintf(stderr,"OK\n");
+
+		/* 2nd recovery step of "pg_xlog" directory */
+		fprintf(stderr,"2nd recovery step of [pg_xlog] directory...");
+		if (second_recovery(src,dest,"pg_xlog") != STATUS_OK)
+		{
+			fprintf(stderr,"NG\n");
+			return STATUS_ERROR;
+		}
+		fprintf(stderr,"OK\n");
+
+	}
+
+	return STATUS_OK;
+}
+
+static int
+recovery_loop(int fd)
+{
+
+	int status = STATUS_OK;
+	RecoveryPacket packet;
+	int r_size = 0;
+	int rtn = RECOVERY_LOOP_END;
+	char src[256];
+
+	r_size = read_packet(fd,&packet);
+	if (r_size <= 0)
+	{
+		rtn = RECOVERY_LOOP_FAIL;
+	}
+	switch (ntohs(packet.packet_no))
+	{
+		case RECOVERY_PREPARE_ANS :
+			/*
+			 * get master information
+			 */
+			/*
+			 * rsync master data before recovery
+			 */
+			if (Debug_pretty_print)
+			{
+				elog(DEBUG1,"local host : %s  master:%s",Local_Host_Name,packet.hostName);
+			}
+			if (!strncmp(Local_Host_Name,packet.hostName,strlen(packet.hostName)))
+			{
+				strcpy(src,packet.pg_data);
+			}
+			else
+			{
+				sprintf(src,"%s:%s",packet.hostName,packet.pg_data);
+			}
+			status = recovery_rsync(src,DataDir,PGR_1ST_RECOVERY);
+			if (status != STATUS_OK)
+			{
+				if (Debug_pretty_print)
+				{
+					elog(DEBUG1,"1st rsync error");
+				}
+				rtn = RECOVERY_LOOP_FAIL;
+				break;
+			}
+			/*
+			 * send recovery start request
+			 */
+			PGRset_recovery_packet_no(&packet, RECOVERY_START_REQ );
+			status = send_packet(&fd,&packet);
+			if (status != STATUS_OK)
+			{
+				rtn = RECOVERY_LOOP_FAIL;
+				break;
+			}
+			rtn = RECOVERY_LOOP_CONTINUE;
+			break;
+		case RECOVERY_START_ANS : 
+			/*
+			 * rsync master data before recovery
+			 */
+			if (!strncmp(Local_Host_Name,packet.hostName,strlen(packet.hostName)))
+			{
+				strcpy(src,packet.pg_data);
+			}
+			else
+			{
+				sprintf(src,"%s:%s",packet.hostName,packet.pg_data);
+			}
+			status = recovery_rsync(src,DataDir,PGR_2ND_RECOVERY);
+			if (status != STATUS_OK)
+			{
+				if (Debug_pretty_print)
+				{
+					elog(DEBUG1,"2nd rsync error");
+				}
+				rtn = RECOVERY_LOOP_FAIL;
+				break;
+			}
+			rtn = RECOVERY_LOOP_END;
+			break;
+		case RECOVERY_ERROR_OCCUPIED:
+		case RECOVERY_ERROR_CONNECTION:
+			rtn = RECOVERY_LOOP_FAIL;
+			break;
+	}
+
+	return rtn;
+}
+
+int
+PGR_Recovery_Main(void)
+{
+	int status;
+	int fd = -1;
+	int rtn;
+	ReplicateServerInfo * host;
+
+	memset(Local_Host_Name,0,sizeof(Local_Host_Name));
+	gethostname(Local_Host_Name,sizeof(Local_Host_Name));
+
+	status = STATUS_ERROR;
+	host = PGR_get_replicate_server_info();
+	if (host == NULL)
+	{
+		if (Debug_pretty_print)
+		{
+			elog(DEBUG1,"not found replication server");
+		}
+		return STATUS_ERROR;
+	}
+
+	status = start_recovery_send(&fd,host);
+	if (status != STATUS_OK)
+	{
+		PGR_Set_Replication_Server_Status(host,DATA_ERR);
+		close(fd);
+		if (Debug_pretty_print)
+		{
+			elog(DEBUG1,"start recovery packet send error");
+		}
+		return STATUS_ERROR;
+	}
+
+	for (;;)
+	{
+		fd_set	  rmask;
+		struct timeval timeout;
+
+		timeout.tv_sec = RECOVERY_TIMEOUT;
+		timeout.tv_usec = 0;
+
+		/*
+		 * Wait for something to happen.
+		 */
+		FD_ZERO(&rmask);
+		FD_SET(fd,&rmask);
+		rtn = select(fd+1, &rmask, (fd_set *)NULL, (fd_set *)NULL, &timeout);
+		if (rtn && FD_ISSET(fd, &rmask))
+		{
+			status = recovery_loop(fd);
+			if (status == RECOVERY_LOOP_CONTINUE)
+			{
+				continue;
+			}
+			if (status == RECOVERY_LOOP_END)
+			{
+				close(fd);
+				break;
+			}
+			if (status == RECOVERY_LOOP_FAIL)
+			{
+				status = stop_recovery_send(&fd,host);
+				if (status != STATUS_OK)
+				{
+					close(fd);
+					return STATUS_ERROR;
+				}
+				close(fd);
+				return STATUS_ERROR;
+			}
+		}
+	}
+	return STATUS_OK;
+}
+
+static void
+show_recovery_packet(RecoveryPacket * packet)
+{
+
+	if (Debug_pretty_print)
+	{
+		elog(DEBUG1,"no = %d",ntohs(packet->packet_no));
+		elog(DEBUG1,"max_connect = %d",ntohs(packet->max_connect));
+		elog(DEBUG1,"port = %d",ntohs(packet->port));
+		elog(DEBUG1,"recoveryPort = %d",ntohs(packet->recoveryPort));
+		if (packet->hostName != NULL)
+			elog(DEBUG1,"hostName = %s",packet->hostName);
+		if (packet->pg_data != NULL)
+			elog(DEBUG1,"pg_data = %s",packet->pg_data);
+	}
+}
+
+static void
+set_recovery_packet(RecoveryPacket * packet, int packet_no)
+{
+
+	if (packet == NULL)
+	{
+		return;
+	}
+	PGRset_recovery_packet_no(packet, packet_no );
+	packet->max_connect = htons(MaxBackends);
+	packet->port = htons(PostPortNumber);
+	if (PGCluster_Info != NULL)
+	{
+		packet->recoveryPort = htons(PGCluster_Info->Com_Info.ConfData_Info.Recovery_Port_Number);
+	}
+	gethostname(packet->hostName,sizeof(packet->hostName));
+	memcpy(packet->pg_data,DataDir,sizeof(packet->pg_data));
+	memset(packet->userName,0,sizeof(packet->userName));
+	cuserid(packet->userName);
+}
+
+#endif /* USE_REPLICATION */
diff -ruN postgresql-7.4.13-old/src/backend/utils/pgcluster/replicate.c postgresql-7.4.13/src/backend/utils/pgcluster/replicate.c
--- postgresql-7.4.13-old/src/backend/utils/pgcluster/replicate.c	1970-01-01 01:00:00.000000000 +0100
+++ postgresql-7.4.13/src/backend/utils/pgcluster/replicate.c	2006-08-05 16:53:43.000000000 +0200
@@ -0,0 +1,4172 @@
+/*--------------------------------------------------------------------
+ * FILE:
+ *     replicate.c
+ *
+ * NOTE:
+ *     This file is composed of the functions to call with the source
+ *     at backend for the replication.
+ *     Low level I/O functions that called by in these functions are 
+ *     contained in 'replicate_com.c'.
+ *
+ *--------------------------------------------------------------------
+ */
+
+/*--------------------------------------
+ * INTERFACE ROUTINES
+ *
+ * setup/teardown:
+ *      PGR_Init_Replicate_Server_Data
+ *      PGR_Set_Replicate_Server_Socket
+ *      PGR_delete_shm
+ * I/O call:
+ *      PGR_Send_Replicate_Command
+ * table handling:
+ *      PGR_get_replicate_server_info
+ * status distinction:
+ *      PGR_Is_Replicated_Command
+ *      Xlog_Check_Replicatec
+ * replicateion main:
+ *      PGR_replication 
+ *-------------------------------------
+ */
+#ifdef USE_REPLICATION
+
+#include "postgres.h"
+
+#include <stdio.h>
+#include <signal.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <grp.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <time.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#ifdef HAVE_NETINET_TCP_H
+#include <netinet/tcp.h>
+#endif
+#include <arpa/inet.h>
+#include <sys/file.h>
+#include <netdb.h>
+
+#include "pg_config.h"
+#include "libpq/libpq.h"
+#include "libpq/pqformat.h"
+#include "miscadmin.h"
+#include "nodes/nodes.h"
+#include "nodes/print.h"
+#include "utils/guc.h"
+#include "parser/parser.h"
+#include "access/xact.h"
+#include "replicate.h"
+
+/* the source of this value is 'access/transam/varsup.c' */
+#define VAR_OID_PREFETCH                (8192)
+
+PGR_ClusterDB_Info ClusterDB_Info;
+PGR_Partial_Info Partial_Info;
+PGR_QueryString_Info QueryString_Info;
+PGR_Lifecheck_Pid_Info Lifecheck_Pid_Info;
+PGR_ReplicationServer_Info ReplicationServer_Info;
+PGR_ReplicationLog_Info ReplicationLog_Info;
+PGR_ClusterDB_Mode_Info ClusterDB_Mode_Info;
+
+bool autocommit = true;
+
+/*--------------------------------------
+ * PROTOTYPE DECLARATION
+ *--------------------------------------
+ */
+int PGR_Init_Replicate_Server_Data(char * path);
+int PGR_Set_Replicate_Server_Socket(void);
+char * PGR_Send_Replicate_Command(const char * query_string, int query_len, char cmdSts ,char cmdType);
+bool PGR_Is_Replicated_Command(const char * query);
+int Xlog_Check_Replicate(int operation);
+int PGR_Replicate_Function_Call(void);
+void PGR_delete_shm(void);
+ReplicateServerInfo * PGR_get_replicate_server_info(void);
+bool PGR_Is_System_Command(const char * query);
+int PGR_Call_System_Command(char * command);
+int PGR_GetTimeOfDay(struct timeval *tp, struct timezone *tpz);
+long PGR_Random(void);
+int PGR_Set_Current_Time(char * sec, char * usec);
+int PGR_Send_Copy(CopyData * copy,int end);
+CopyData * PGR_Set_Copy_Data(CopyData * copy, char * str, int len, int end);
+char * PGR_scan_terminate(const char * str);
+bool PGR_Is_Stand_Alone(void);
+void PGR_Send_Message_To_Frontend(char * msg);
+void PGR_Notice_Transaction_Query_Done(void);
+void PGR_Notice_Transaction_Query_Aborted(void);
+int PGR_Notice_Conflict(void);
+int PGR_Recv_Trigger (int user_timeout);
+bool PGR_Check_DeadLock(LOCKMETHODTABLE *lockMethodTable, LOCKMODE lockmode, LOCK *lock, PROCLOCK *holder);
+void PGR_Set_Replication_Server_Status( ReplicateServerInfo * sp, int status);
+int PGR_Is_Skip_Replication(const char * query);
+bool PGR_Did_Commit_Transaction(void);
+bool PGR_Set_Transaction_Mode(bool mode,const char * commandTag);
+char * PGR_Remove_Comment(const char * str);
+void PGR_Force_Replicate_Query(void);
+void PGR_Notice_DeadLock(void);
+void PGR_Set_Cluster_Status(int status);
+int PGR_Get_Cluster_Status(void);
+int PGR_lo_create(int flags);
+int PGR_lo_open(Oid lobjId,int32 mode);
+int PGR_lo_close(int32 fd);
+int PGR_lo_write(int fd, char *buf, int len);
+int PGR_lo_lseek(int32 fd, int32 offset, int32 whence);
+int PGR_lo_unlink(Oid lobjId);
+void PGR_init_replication(const char * query, int len);
+void PGR_init_each_query(void);
+int PGR_exec_replication(const char * commandTag,CommandDest dest );
+int PGR_startup_lifecheck(void);
+void PGR_finish_lifecheck(int sig);
+int PGR_Wait_Reliable_Trigger(const char * commandTag);
+void PGR_Set_Replication_Flag(Node * parsetree);
+int PGR_Init_PGCluster_Info(void);
+int PGR_Get_Cluster_Conf_Data(char * path);
+void PGR_Clear_Children(int sig);
+void PGR_Recovery_Failed(void);
+void PGR_Elog_Abort_Copy(void);
+void PGR_Elog_Abort_Proc(int timeout);
+void PGR_Elog_Warn_Proc(char * msg, char * fix);
+void PGR_ExceptionalCondition(void);
+bool PGR_Is_This_Transaction_Committed(void);
+void PGR_Set_Copy_Char(int ch);
+
+static int PGR_replication(const char * query_string, CommandDest dest, const char * commandTag);
+static int set_command_args(char argv[PGR_CMD_ARG_NUM][256],char *str);
+static bool is_same_replication_server(ReplicateServerInfo * sp1, ReplicateServerInfo * sp2 );
+static ReplicateServerInfo * search_new_replication_server ( ReplicateServerInfo * sp , int socket_type );
+
+static int close_replicate_server_socket ( ReplicateServerInfo * sp , int socket_type );
+static int recv_replicate_result(int sock,char * result,int user_timeout);
+static int recv_message(int sock,char * buf,int flag);
+static void clear_recv_queue(int sock);
+static int send_replicate_packet(int sock,ReplicateHeader * header, const char * query_string);
+static int get_replicate_server_socket ( ReplicateServerInfo * sp , int socket_type );
+static bool is_copy_from(const char * query);
+static int is_session_authorization(const char * query);
+static int get_words( char words[MAX_WORDS][MAX_WORD_LETTERS] ,const char * string,int length,int upper);
+static int get_table_name(char * table_name, const char * query, int position );
+static bool is_not_replication_query(const char * query_string, int query_len, char cmdType);
+static int Comp_Not_Replicate(PGR_Not_Replicate_Type * nrp1,PGR_Not_Replicate_Type* nrp2);
+static bool is_serial_control_query(char cmdType, const char * query);
+static bool is_select_into_query(char cmdType, const char * query);
+static int send_response_to_replication_server(const char * notice);
+static bool is_transaction_command(const char * commandTag);
+static bool do_not_replication_command(const char * commandTag);
+static bool is_create_temp_table(const char * query);
+static int add_replication_server(char * hostname,char * port, char * recovery_port, char * lifecheck_port);
+static int change_replication_server(char * hostname,char * port, char * recovery_port);
+static int get_new_replication_socket( ReplicateServerInfo * base, ReplicateServerInfo * sp, int socket_type);
+/*
+static bool confirm_query_done(int sock, ReplicateHeader * header, char *result);
+*/
+static char * get_hostName(char * str);
+static unsigned int get_next_request_id(void);
+static bool is_this_query_replicated(char * id);
+static int set_replication_id(char * id);
+static void set_response_mode(char * mode);
+#ifdef CONTROL_LOCK_CONFLICT
+static int wait_lock_answer(void);
+static int read_trigger(char * result, int buf_size);
+#endif
+static int return_current_oid(void);
+static int sync_oid(char * oid);
+
+extern ssize_t secure_read(Port *, void *, size_t);
+/*--------------------------------------------------------------------
+ * SYMBOL
+ *    PGR_Init_Replicate_Server_Data()
+ * NOTES
+ *    Read Configuration file and create ReplicationServer_Info.ReplicateServerData table
+ * ARGS
+ *    void
+ * RETURN
+ *    OK: STATUS_OK
+ *    NG: STATUS_ERROR
+ *--------------------------------------------------------------------
+ */
+int
+PGR_Init_Replicate_Server_Data(char * path)
+{
+	int table_size,str_size;
+	ReplicateServerInfo  *sp;
+	PGR_Not_Replicate_Type * nrp;
+	ConfDataType * conf;
+	int rec_no,cnt;
+	char fname[256];
+	int status = STATUS_OK;
+
+	if (PGCluster_Info == NULL)
+	{
+		return STATUS_ERROR;
+	}
+	if (PGCluster_Info->Com_Info.ConfData_Info.ConfData_Top == (ConfDataType *)NULL)
+	{
+		return STATUS_ERROR;
+	}
+
+	/* allocate replication server information table */
+	table_size = sizeof(ReplicateServerInfo) * MAX_SERVER_NUM;
+	ClusterDB_Info.ReplicateServerShmid = shmget(IPC_PRIVATE,table_size,IPC_CREAT | IPC_EXCL | 0600);
+	if (ClusterDB_Info.ReplicateServerShmid < 0)
+	{
+		return STATUS_ERROR;
+	}
+	ReplicationServer_Info.ReplicateServerData = (ReplicateServerInfo *)shmat(ClusterDB_Info.ReplicateServerShmid,0,0);
+	if (ReplicationServer_Info.ReplicateServerData == (ReplicateServerInfo *)-1)
+	{
+		return STATUS_ERROR;
+	}
+	memset(ReplicationServer_Info.ReplicateServerData,0,table_size);
+	sp = ReplicationServer_Info.ReplicateServerData;
+
+	/* allocate cluster db information table */
+	ClusterDB_Info.ClusterDBShmid = shmget(IPC_PRIVATE,sizeof(ClusterDBInfo),IPC_CREAT | IPC_EXCL | 0600);
+	if (ClusterDB_Info.ClusterDBShmid < 0)
+	{
+		return STATUS_ERROR;
+	}
+	ClusterDB_Info.ClusterDBData = (ClusterDBInfo *)shmat(ClusterDB_Info.ClusterDBShmid,0,0);
+	if (ClusterDB_Info.ClusterDBData == (ClusterDBInfo *)-1)
+	{
+		return STATUS_ERROR;
+	}
+	memset(ClusterDB_Info.ClusterDBData,0,sizeof(ClusterDBInfo));
+	PGR_Set_Cluster_Status(STATUS_REPLICATE);
+
+	/* allocate partial replicate table */
+	table_size = sizeof(PGR_Not_Replicate_Type) * MAX_SERVER_NUM;
+	Partial_Info.PGR_Not_Replicate = malloc(table_size);
+	if (Partial_Info.PGR_Not_Replicate == (PGR_Not_Replicate_Type*)NULL)
+	{
+		return STATUS_ERROR;
+	}
+	memset(Partial_Info.PGR_Not_Replicate, 0, table_size);
+	nrp = Partial_Info.PGR_Not_Replicate;
+	cnt = 0;
+	conf = PGCluster_Info->Com_Info.ConfData_Info.ConfData_Top;
+	while ((conf != (ConfDataType *)NULL) && (cnt < MAX_SERVER_NUM))
+	{
+		/* set replication server table */
+		if (!strcmp(conf->table,REPLICATION_SERVER_INFO_TAG))
+		{
+			rec_no = conf->rec_no;
+			cnt = rec_no;
+			if (!strcmp(conf->key,HOST_NAME_TAG))
+			{
+				strncpy((sp + rec_no)->hostName,conf->value,sizeof(sp->hostName));
+				conf = (ConfDataType *)conf->next;
+				continue;
+			}
+			if (!strcmp(conf->key,PORT_TAG))
+			{
+				if (atoi(conf->value) > 0)
+				{
+					(sp + rec_no)->portNumber = atoi(conf->value);
+				}
+				else
+				{
+					(sp + rec_no)->portNumber = DEFAULT_PGRP_PORT;
+				}
+				(sp + rec_no)->sock = -1;
+				if ((sp + rec_no)->useFlag != DATA_USE)
+				{
+					PGR_Set_Replication_Server_Status((sp+rec_no), DATA_USE);
+				}
+				memset((sp + rec_no + 1)->hostName,0,sizeof(sp->hostName));
+				(sp + rec_no + 1)->useFlag = DATA_END;
+				conf = (ConfDataType *)conf->next;
+				continue;
+			}
+			if (!strcmp(conf->key,LIFECHECK_PORT_TAG))
+			{
+				if (atoi(conf->value) > 0)
+				{
+					(sp + rec_no)->lifecheckPortNumber = atoi(conf->value);
+				}
+				else
+				{
+					(sp + rec_no)->lifecheckPortNumber = DEFAULT_PGRP_LIFECHECK_PORT;
+				}
+				conf = (ConfDataType *)conf->next;
+				continue;
+			}
+			if (!strcmp(conf->key,RECOVERY_PORT_TAG))
+			{
+				if (atoi(conf->value) > 0)
+				{
+					(sp + rec_no)->recoveryPortNumber = atoi(conf->value);
+				}
+				else
+				{
+					(sp + rec_no)->recoveryPortNumber = DEFAULT_PGRP_RECOVERY_PORT;
+				}
+				if ((sp + rec_no)->useFlag != DATA_USE)
+				{
+					PGR_Set_Replication_Server_Status((sp+rec_no), DATA_USE);
+				}
+				memset((sp + rec_no + 1)->hostName,0,sizeof(sp->hostName));
+				(sp + rec_no + 1)->useFlag = DATA_END;
+				conf = (ConfDataType *)conf->next;
+				continue;
+			}
+		}
+		/* set part replication table */
+		if (!strcmp(conf->table,NOT_REPLICATE_INFO_TAG))
+		{
+			rec_no = conf->rec_no;
+			cnt = rec_no;
+			if (Partial_Info.PGR_Not_Replicate_Rec_Num < rec_no +1)
+			{
+				Partial_Info.PGR_Not_Replicate_Rec_Num = rec_no +1;
+			}
+			if (!strcmp(conf->key,DB_NAME_TAG))
+			{
+				strncpy((nrp + rec_no)->db_name,conf->value,sizeof(nrp->db_name));
+				conf = (ConfDataType *)conf->next;
+				continue;
+			}
+			if (!strcmp(conf->key,TABLE_NAME_TAG))
+			{
+				strncpy((nrp + rec_no)->table_name,conf->value,sizeof(nrp->table_name));
+				conf = (ConfDataType *)conf->next;
+				continue;
+			}
+		}
+
+		/* set cluster db data */
+		if (!strcmp(conf->key,RECOVERY_PORT_TAG))
+		{
+			if (atoi(conf->value))
+			{
+				PGCluster_Info->Com_Info.ConfData_Info.Recovery_Port_Number = atoi(conf->value);
+			}
+			else
+			{
+				PGCluster_Info->Com_Info.ConfData_Info.Recovery_Port_Number = DEFAULT_CLUSTER_RECOVERY_PORT;
+			}
+		}
+		if (!strcmp(conf->key,LIFECHECK_PORT_TAG))
+		{
+			if (atoi(conf->value) > 0)
+			{
+				PGCluster_Info->Com_Info.ConfData_Info.LifeCheck_Port_Number = atoi(conf->value);
+			}
+			else
+			{
+				PGCluster_Info->Com_Info.ConfData_Info.LifeCheck_Port_Number = DEFAULT_CLUSTER_LIFECHECK_PORT;
+			}
+		}
+		if (!strcmp(conf->key,STATUS_LOG_FILE_TAG))
+		{
+			PGCluster_Info->Com_Info.Log_Info.PGRStatusFileName = strdup(conf->value);
+			conf = (ConfDataType*)conf->next;
+			continue;
+		}
+		if (!strcmp(conf->key,ERROR_LOG_FILE_TAG))
+		{
+			PGCluster_Info->Com_Info.Log_Info.PGRLogFileName = strdup(conf->value);
+			conf = (ConfDataType*)conf->next;
+			continue;
+		}
+		if (!strcmp(conf->key,RSYNC_PATH_TAG))
+		{
+			str_size = strlen(conf->value) ;
+			PGCluster_Info->RsyncPath = malloc(str_size + 1);
+			if (PGCluster_Info->RsyncPath == NULL)
+			{
+				return STATUS_ERROR;
+			}
+			memset(PGCluster_Info->RsyncPath,0,str_size + 1);
+			strncpy(PGCluster_Info->RsyncPath,conf->value,str_size);
+		}
+		if (!strcmp(conf->key,RSYNC_OPTION_TAG))
+		{
+			str_size = strlen(conf->value) ;
+			PGCluster_Info->RsyncOption = malloc(str_size + 1);
+			if (PGCluster_Info->RsyncOption == NULL)
+			{
+				return STATUS_ERROR;
+			}
+			memset(PGCluster_Info->RsyncOption,0,str_size + 1);
+			strncpy(PGCluster_Info->RsyncOption,conf->value,str_size);
+		}
+		if (!strcmp(conf->key,STAND_ALONE_TAG))
+		{
+			if (PGCluster_Info->PGR_Stand_Alone == (PGR_Stand_Alone_Type*)NULL)
+			{
+				PGCluster_Info->PGR_Stand_Alone = (PGR_Stand_Alone_Type*)malloc(sizeof(PGR_Stand_Alone_Type));
+			}
+			if (PGCluster_Info->PGR_Stand_Alone == (PGR_Stand_Alone_Type *)NULL)
+			{
+				return STATUS_ERROR;
+			}
+			memset(PGCluster_Info->PGR_Stand_Alone, 0, sizeof(PGR_Stand_Alone_Type));
+			PGCluster_Info->PGR_Stand_Alone->is_stand_alone = false;
+			if (!strcmp(conf->value,READ_WRITE_IF_STAND_ALONE))
+			{
+				PGCluster_Info->PGR_Stand_Alone->permit = PERMIT_READ_WRITE;
+			}
+			else
+			{
+				PGCluster_Info->PGR_Stand_Alone->permit = PERMIT_READ_ONLY;
+			}
+		}
+		conf = (ConfDataType *)conf->next;
+	}
+	if (PGCluster_Info->Com_Info.Log_Info.Log_Print)
+	{
+		if (PGCluster_Info->Com_Info.Log_Info.PGRLogFileName == NULL)
+		{
+			snprintf(fname,sizeof(fname),"%s/%s",path,CLUSTER_ERROR_LOG_FILE);
+		}
+		else
+		{
+			strncpy(fname,PGCluster_Info->Com_Info.Log_Info.PGRLogFileName,sizeof(fname));
+		}
+		PGCluster_Info->Com_Info.Log_Info.LogFp = fopen(fname,"a");
+		if (PGCluster_Info->Com_Info.Log_Info.LogFp == NULL)
+		{
+			if (Debug_pretty_print)
+				elog(DEBUG1, "fopen failed: (%s)",strerror(errno));
+			return STATUS_ERROR;
+		}
+	}
+
+	if (PGCluster_Info->Com_Info.Log_Info.PGRStatusFileName == NULL)
+	{
+		snprintf(fname,sizeof(fname),"%s/%s",path,CLUSTER_STATUS_LOG_FILE);
+	}
+	else
+	{
+		strncpy(fname,PGCluster_Info->Com_Info.Log_Info.PGRStatusFileName,sizeof(fname));
+	}
+	PGCluster_Info->Com_Info.Log_Info.StatusFp = fopen(fname,"a");
+	if (PGCluster_Info->Com_Info.Log_Info.StatusFp == NULL)
+	{
+		if (Debug_pretty_print)
+			elog(DEBUG1, "fopen failed: (%s)",strerror(errno));
+		return STATUS_ERROR;
+	}
+	ReplicationServer_Info.TransactionSock = -1;
+	if (PGCluster_Info->ReplicateCurrentTime == (ReplicateNow *)NULL)
+	{
+		PGCluster_Info->ReplicateCurrentTime = (ReplicateNow *)malloc(sizeof(ReplicateNow));
+	}
+	if (PGCluster_Info->ReplicateCurrentTime == (ReplicateNow *)NULL)
+	{
+		return STATUS_ERROR;
+	}
+	memset(PGCluster_Info->ReplicateCurrentTime,0,sizeof(ReplicateNow));
+	if (PGCluster_Info->PGRCopyData == (CopyData *)NULL)
+	{
+		PGCluster_Info->PGRCopyData = (CopyData *)malloc(sizeof(CopyData));
+	}
+	if (PGCluster_Info->PGRCopyData == (CopyData *)NULL)
+	{
+		return STATUS_ERROR;
+	}
+	memset(PGCluster_Info->PGRCopyData,0,sizeof(CopyData));
+
+	if (Partial_Info.PGR_Not_Replicate_Rec_Num  == 0)
+	{
+		free(Partial_Info.PGR_Not_Replicate);
+		Partial_Info.PGR_Not_Replicate = NULL;
+	}
+	else
+	{
+		qsort((char *)Partial_Info.PGR_Not_Replicate,Partial_Info.PGR_Not_Replicate_Rec_Num,sizeof(PGR_Not_Replicate_Type), (int (*)(const void*,const void*))Comp_Not_Replicate);
+	}
+
+	ClusterDB_Info.PGRSelfHostName = malloc(HOSTNAME_MAX_LENGTH);
+	if (ClusterDB_Info.PGRSelfHostName == NULL)
+	{
+		return STATUS_ERROR;
+	}
+	memset(ClusterDB_Info.PGRSelfHostName,0,HOSTNAME_MAX_LENGTH);
+	if (gethostname(ClusterDB_Info.PGRSelfHostName,HOSTNAME_MAX_LENGTH) < 0)
+	{
+		return STATUS_ERROR;
+	}
+
+	/* initialize global tables */
+	status = PGRsyn_init();
+	if (status != STATUS_OK)
+	{
+		return STATUS_ERROR;
+	}
+
+	return	STATUS_OK;
+}
+
+/*--------------------------------------------------------------------
+ * SYMBOL
+ *    PGR_Set_Replicate_Server_Socket()
+ * NOTES
+ *    Create new socket and set ReplicationServer_Info.ReplicateServerData table
+ * ARGS
+ *    void
+ * RETURN
+ *    OK: STATUS_OK
+ *    NG: STATUS_ERROR
+ *--------------------------------------------------------------------
+ */
+int
+PGR_Set_Replicate_Server_Socket(void)
+{
+	ReplicateServerInfo * sp;
+	if (PGCluster_Info == NULL)
+	{
+		return STATUS_ERROR;
+	}
+	if (ReplicationServer_Info.ReplicateServerData == NULL)
+	{
+		return STATUS_ERROR;
+	}
+	sp = ReplicationServer_Info.ReplicateServerData;
+	while (sp->useFlag != DATA_END){
+		sp->sock = -1;
+		PGR_Create_Socket_Connect(&(sp->sock),sp->hostName,sp->portNumber);
+		sp ++;
+	}
+	return	STATUS_OK;
+}
+
+/*--------------------------------------------------------------------
+ * SYMBOL
+ *    get_replicate_server_socket()
+ * NOTES
+ *    search or create a socket to connect with the replication server
+ * ARGS
+ *    ReplicateServerInfo * sp: replication server data (I)
+ *    int socket_type: socket type (I)
+ *                       -PGR_TRANSACTION_SOCKET:
+ *                       -PGR_QUERY_SOCKET:
+ * RETURN
+ *    OK: >0(socket)
+ *    NG: -1
+ *--------------------------------------------------------------------
+ */
+static int
+get_replicate_server_socket ( ReplicateServerInfo * sp , int socket_type )
+{
+	ReplicateServerInfo * tmp;
+
+	tmp = sp;
+	if (tmp == (ReplicateServerInfo *) NULL)
+	{
+		return -1;
+	}
+	if (tmp->hostName[0] == '\0')
+	{
+		return -1;
+	}
+
+	if (ReplicationServer_Info.TransactionSock > 0)
+	{
+		return ReplicationServer_Info.TransactionSock;
+	}
+
+	while(PGR_Create_Socket_Connect(&ReplicationServer_Info.TransactionSock,tmp->hostName,tmp->portNumber) != STATUS_OK)
+	{
+		if (ReplicationServer_Info.TransactionSock > 0)
+			close(ReplicationServer_Info.TransactionSock);
+		ReplicationServer_Info.TransactionSock = -1;
+		PGR_Set_Replication_Server_Status(tmp, DATA_ERR);
+		tmp = PGR_get_replicate_server_info();
+		if (tmp == (ReplicateServerInfo *)NULL)
+		{
+			return -1;
+		}
+		PGR_Set_Replication_Server_Status(tmp, DATA_USE);
+	}
+	return ReplicationServer_Info.TransactionSock;
+}
+
+/*--------------------------------------------------------------------
+ * SYMBOL
+ *    close_replicate_server_socket()
+ * NOTES
+ *    close the socket connected with the replication server
+ * ARGS
+ *    ReplicateServerInfo * sp: replication server data (I)
+ *    int socket_type: socket type (I)
+ *                       -PGR_TRANSACTION_SOCKET:
+ *                       -PGR_QUERY_SOCKET:
+ * RETURN
+ *    OK: STATUS_OK
+ *    NG: STATUS_ERROR
+ *--------------------------------------------------------------------
+ */
+static int
+close_replicate_server_socket ( ReplicateServerInfo * sp , int socket_type )
+{
+	if (sp == (ReplicateServerInfo *)NULL )
+	{
+		return STATUS_ERROR;
+	}
+	if (sp->hostName[0] == '\0')
+	{
+		return STATUS_ERROR;
+	}
+	if (ReplicationServer_Info.TransactionSock != -1)
+	{
+		PGR_Close_Sock(&(ReplicationServer_Info.TransactionSock));
+		ReplicationServer_Info.TransactionSock = -1;
+	}
+	switch (socket_type)
+	{
+		case PGR_TRANSACTION_SOCKET:
+			if (ReplicationServer_Info.TransactionSock != -1)
+			{
+				PGR_Close_Sock(&(ReplicationServer_Info.TransactionSock));
+			}
+			ReplicationServer_Info.TransactionSock = -1;
+			break;
+		case PGR_QUERY_SOCKET:
+			if (sp->sock != -1)
+			{
+				PGR_Close_Sock(&(sp->sock));
+			}
+			sp->sock = -1;
+			break;
+	}
+	PGR_Set_Replication_Server_Status(sp, DATA_INIT);
+	return STATUS_OK;
+}
+
+static bool
+is_same_replication_server(ReplicateServerInfo * sp1, ReplicateServerInfo * sp2 )
+{
+	if ((sp1 == NULL) || (sp2 == NULL))
+	{
+		return false;
+	}
+	if ((!strcmp(sp1->hostName,sp2->hostName)) &&
+		(sp1->portNumber == sp2->portNumber) &&
+		(sp1->recoveryPortNumber == sp2->recoveryPortNumber))
+	{
+		return true;
+	}
+	return false;
+}
+
+static ReplicateServerInfo *
+search_new_replication_server ( ReplicateServerInfo * sp , int socket_type )
+{
+	ReplicateHeader dummy_header;
+	ReplicateServerInfo * rs_tbl;
+	char command[256];
+	int sock = -1;
+
+	if ((ReplicationServer_Info.ReplicateServerData == NULL) || ( sp == NULL))
+	{
+		return NULL;
+	}
+	rs_tbl = sp;
+	close_replicate_server_socket ( sp , socket_type);
+	sp ++;
+	while (is_same_replication_server(sp,rs_tbl) != true)
+	{
+		if (sp->useFlag == DATA_END)
+		{
+			sp = ReplicationServer_Info.ReplicateServerData;
+		}
+		sock = get_replicate_server_socket( sp , socket_type);
+		if (sock <= 0 )
+		{
+			if (is_same_replication_server(sp,rs_tbl) == true)
+			{
+				return NULL;
+			}
+			else
+			{
+				sp++;
+			}
+			continue;
+		}
+		memset(&dummy_header, 0, sizeof(ReplicateHeader));
+		memset(command,0,sizeof(command));
+		snprintf(command,sizeof(command)-1,"SELECT %s(%d,%s,%d,%d)",
+				PGR_SYSTEM_COMMAND_FUNC,
+				PGR_CHANGE_REPLICATION_SERVER_FUNC_NO,
+				sp->hostName,
+				sp->portNumber,
+				sp->recoveryPortNumber);
+		dummy_header.cmdSys = CMD_SYS_CALL;
+		dummy_header.cmdSts = CMD_STS_NOTICE;
+		dummy_header.query_size = htonl(strlen(command));
+		if (send_replicate_packet(sock,&dummy_header,command) != STATUS_OK)
+		{
+			close_replicate_server_socket ( sp , socket_type);
+			PGR_Set_Replication_Server_Status(sp, DATA_ERR);
+		}
+		else
+		{
+			PGR_Set_Replication_Server_Status(sp, DATA_USE);
+			return sp;
+		}
+		sp++;
+	}
+	return NULL;
+}
+
+static int
+get_table_name(char * table_name, const char * query, int position )
+{
+	
+	int i,wc;
+	char * p;
+	char * sp;
+	int length;
+
+	if ((table_name == NULL) || (query == NULL) || (position < 1))
+	{
+		return STATUS_ERROR;
+	}
+	length = strlen(query);
+	p = (char *)query;
+	wc = 1;
+	sp = table_name;
+	for (i = 0 ; i < length ; i ++)
+	{
+		while(isspace(*p))
+		{
+			p++;
+			i++;
+		}
+		while((*p != '\0') && (! isspace(*p)))
+		{
+			if ((*p == ';') || (*p == '('))
+				break;
+			if (wc == position)
+			{
+				*sp = *p;
+				sp++;
+			}
+			p++;
+			i++;
+		}
+		if (wc == position)
+		{
+			*sp = '\0';
+			break;
+		}
+		wc++;
+	}
+	return STATUS_OK;
+}
+
+static bool 
+is_not_replication_query(const char * query_string, int query_len, char cmdType)
+{
+	PGR_Not_Replicate_Type key;
+	PGR_Not_Replicate_Type * ptr = NULL;
+
+	if (Partial_Info.PGR_Not_Replicate_Rec_Num <= 0)
+		return false;
+	if (query_string == NULL)
+		return true;
+	memset(&key,0,sizeof(PGR_Not_Replicate_Type));
+	strncpy(key.db_name ,(char *)(MyProcPort->database_name),sizeof(key.db_name));
+	switch (cmdType)
+	{
+		case CMD_TYPE_INSERT:
+			get_table_name(key.table_name,query_string,3);
+			break;
+		case CMD_TYPE_UPDATE:
+			get_table_name(key.table_name,query_string,2);
+			break;
+		case CMD_TYPE_DELETE:
+			get_table_name(key.table_name,query_string,3);
+			break;
+		case CMD_TYPE_COPY:
+			get_table_name(key.table_name,query_string,2);
+			break;
+		default:
+			return false;
+	}
+	ptr = (PGR_Not_Replicate_Type*)bsearch((void*)&key,(void*)Partial_Info.PGR_Not_Replicate,Partial_Info.PGR_Not_Replicate_Rec_Num,sizeof(PGR_Not_Replicate_Type), (int (*)(const void*,const void*))Comp_Not_Replicate);
+	if (ptr == NULL)
+	{
+		return false;
+	}
+	return true;
+
+}
+
+/*--------------------------------------------------------------------
+ * SYMBOL
+ *    PGR_Send_Replicate_Command()
+ * NOTES
+ *    create new socket
+ * ARGS
+ *    char * query_string: query strings (I)
+ *    char cmdSts: 
+ *    char cmdType:
+ * RETURN
+ *    OK: result
+ *    NG: NULL
+ *--------------------------------------------------------------------
+ */
+char *
+PGR_Send_Replicate_Command(const char * query_string, int query_len, char cmdSts ,char cmdType)
+{
+	int sock = 0;
+	int cnt = 0;
+	ReplicateHeader header;
+	char * serverName = NULL;
+	int portNumber=0;
+	char * result = NULL;
+	ReplicateServerInfo * sp = NULL;
+	ReplicateServerInfo * base = NULL;
+	int socket_type = 0;
+	char argv[ PGR_CMD_ARG_NUM ][256];
+	int argc = 0;
+	int func_no = 0;
+	int status = 0;
+	int check_flag =0;
+
+	/*
+	 * check query string
+	 */
+	if (PGCluster_Info == NULL)
+	{
+		return NULL;
+	}
+	if ((query_string == NULL)  ||
+		(query_len < 0))
+	{
+		return NULL;
+	}
+	/* check not replication query */
+	if (is_not_replication_query(query_string, query_len, cmdType) == true)
+	{
+		ClusterDB_Mode_Info.PGR_Copy_Data_Need_Replicate = false;
+		return NULL;
+	}
+
+	if ((cmdSts == CMD_STS_TRANSACTION ) ||
+		(cmdSts == CMD_STS_SET_SESSION_AUTHORIZATION ) ||
+		(cmdSts == CMD_STS_TEMP_TABLE ))
+	{
+		socket_type = PGR_TRANSACTION_SOCKET ;
+	}
+	else
+	{
+		socket_type = PGR_QUERY_SOCKET ;
+	}
+	sp = PGR_get_replicate_server_info();
+	if (sp == NULL)
+	{
+		if (Debug_pretty_print)
+			elog(DEBUG1,"PGR_get_replicate_server_info get error");
+		return NULL;
+	}
+	sock = get_replicate_server_socket( sp , socket_type);
+	if (sock <= 0)
+	{
+		if (Debug_pretty_print)
+			elog(DEBUG1,"get_replicate_server_socket fail");
+		return NULL;
+	}
+	result = malloc(PGR_MESSAGE_BUFSIZE + 4);
+	if (result == NULL)
+	{
+		return NULL;
+	}
+	memset(result,0,PGR_MESSAGE_BUFSIZE + 4);
+
+	serverName = sp->hostName;
+	portNumber = (int)sp->portNumber;
+	memset(&header,0,sizeof(ReplicateHeader));
+	header.cmdSys = CMD_SYS_REPLICATE;
+	header.cmdSts = cmdSts;
+	header.cmdType = cmdType;
+	header.port = htons(PostPortNumber);
+	header.pid = htons(getpid());
+	header.query_size = htonl(query_len); 
+	strncpy(header.dbName ,(char *)(MyProcPort->database_name),sizeof(header.dbName));
+	strncpy(header.userName , (char *)(MyProcPort->user_name),sizeof(header.userName));
+	gethostname(header.from_host,sizeof(header.from_host));
+	header.request_id = htonl(get_next_request_id());
+	header.rlog = 0;
+
+	base = sp;
+	ReplicationServer_Info.PGR_Sock_To_Replication_Server = sock;
+
+retry_send_replicate_packet:
+
+	clear_recv_queue(sock); 
+	memset(result,0,PGR_MESSAGE_BUFSIZE + 4);
+	cnt = 0;
+	while (send_replicate_packet(sock,&header,query_string) != STATUS_OK)
+	{
+		if (cnt > MAX_RETRY_TIMES )
+		{
+			sock = get_new_replication_socket( base, sp, socket_type);
+			if (sock < 0)
+			{
+				if (Debug_pretty_print)
+					elog(DEBUG1,"all replication servers may be down");
+				if (PGCluster_Info != NULL)
+				{
+					PGCluster_Info->PGR_Stand_Alone->is_stand_alone = true;
+				}
+				if (cmdSts == CMD_STS_TRANSACTION )
+				{
+					strcpy(result,PGR_REPLICATION_ABORT_MSG);
+					return result;
+				}
+				free(result);
+				result = NULL;
+				return NULL;
+			}
+			ReplicationServer_Info.PGR_Sock_To_Replication_Server = sock;
+			header.rlog = CONNECTION_SUSPENDED_TYPE;
+			cnt = 0;
+		}
+		cnt ++;
+	}
+
+	memset(result,0,PGR_MESSAGE_BUFSIZE);
+	if ((status = recv_replicate_result(sock,result,0)) <= 0)
+	{
+		/* replication server should be down */
+		sock = get_new_replication_socket( base, sp, socket_type);
+		if (sock < 0)
+		{
+			if (Debug_pretty_print)
+				elog(DEBUG1,"all replication servers may be down");
+			if (PGCluster_Info != NULL)
+			{
+				PGCluster_Info->PGR_Stand_Alone->is_stand_alone = true;
+			}
+			if (cmdSts == CMD_STS_TRANSACTION )
+			{
+				strcpy(result,PGR_REPLICATION_ABORT_MSG);
+				return result;
+			}
+			if (result != NULL)
+			{
+				free(result);
+				result = NULL;
+			}
+			return NULL;
+		}
+		ReplicationServer_Info.PGR_Sock_To_Replication_Server = sock;
+		header.rlog = CONNECTION_SUSPENDED_TYPE;
+		goto retry_send_replicate_packet;
+
+		/* connection closed */
+	}
+	argc = set_command_args(argv,result);
+	if (argc >= 1)
+	{
+		func_no = atoi(argv[0]);
+		/* set current system time */
+		if (func_no == PGR_SET_CURRENT_TIME_FUNC_NO)
+		{
+			if (atol(argv[1]) == 0)
+			{
+				CreateCheckPoint(false,true);
+			}
+			else
+			{
+				PGR_Set_Current_Time(argv[1],argv[2]);
+				set_replication_id(argv[3]);
+				set_response_mode(argv[4]);
+			}
+		}
+		else if (func_no == PGR_NOTICE_DEADLOCK_DETECTION_FUNC_NO)
+		{
+			memset(result,0,PGR_MESSAGE_BUFSIZE);
+			strcpy(result,PGR_DEADLOCK_DETECTION_MSG);
+		}
+		else if (func_no == PGR_QUERY_CONFIRM_ANSWER_FUNC_NO)
+		{
+			check_flag = atoi(argv[1]);
+			if (check_flag == PGR_ALREADY_COMMITTED )
+			{
+				PGR_Set_Current_Time(argv[2],argv[3]);
+				set_replication_id(argv[4]);
+			}
+			else
+			{
+				PGR_Set_Current_Time(argv[1],argv[2]);
+				set_replication_id(argv[3]);
+				/* this query is not replicated */
+				/*
+				free(result);
+				return NULL;
+				*/
+			}
+		}
+	}
+	return result;
+}
+
+static int
+get_new_replication_socket( ReplicateServerInfo * base, ReplicateServerInfo * sp, int socket_type)
+{
+	int sock = 0;
+
+	if (( base == NULL) ||
+		( sp == NULL))
+	{
+		return -1;
+	}
+	close_replicate_server_socket ( sp , socket_type);
+	PGR_Set_Replication_Server_Status(sp, DATA_ERR);
+	sp = search_new_replication_server(base, socket_type);
+	if (sp == NULL)
+	{
+		if (Debug_pretty_print)
+			elog(DEBUG1,"all replication servers may be down");
+		if (PGCluster_Info != NULL)
+		{
+			PGCluster_Info->PGR_Stand_Alone->is_stand_alone = true;
+		}
+		return -1;
+	}
+	sock = get_replicate_server_socket( sp , socket_type);
+	return sock;
+}
+
+
+static int
+recv_replicate_result(int sock,char * result,int user_timeout)
+{
+	fd_set      rmask;
+	struct timeval timeout;
+	int rtn;
+
+	if (result == NULL)
+	{
+		return -1;
+	}
+	if (user_timeout == 0)
+	{
+		timeout.tv_sec = PGR_RECV_TIMEOUT * 3;
+	}
+	else
+	{
+		timeout.tv_sec = user_timeout;
+	}
+	timeout.tv_usec = 0;
+
+	/*
+	 * Wait for something to happen.
+	 */
+	rtn = 1;
+	while (rtn)
+	{
+		FD_ZERO(&rmask);
+		FD_SET(sock,&rmask);
+		rtn = select(sock+1, &rmask, (fd_set *)NULL, (fd_set *)NULL, &timeout);
+		if (rtn && FD_ISSET(sock, &rmask))
+		{
+			return (recv_message(sock, result,0));
+		}
+		else
+		{
+			if (errno != EINTR)
+			{
+				return -1;
+			}
+		}
+	}
+	return -1;
+}
+
+static int
+recv_message(int sock,char * buf,int flag)
+{
+	int cnt = 0;
+	int r = 0;
+	char * read_ptr;
+	int read_size = 0;
+	cnt = 0;
+	read_ptr = buf;
+
+	for (;;)
+	{
+		r = recv(sock,read_ptr + read_size ,PGR_MESSAGE_BUFSIZE - read_size, flag); 
+		if (r < 0)
+		{
+			if (errno == EINTR)
+			{
+				usleep(PGR_RECV_WAIT_MSEC);
+				continue;
+			}
+#ifdef EAGAIN
+			else if (errno == EAGAIN)
+			{
+				usleep(PGR_RECV_WAIT_MSEC);
+				continue;
+			}
+#endif /* EAGAIN */
+#ifdef ECONNREFUSED
+			else if (errno == ECONNREFUSED)
+			{
+				usleep(PGR_RECV_WAIT_MSEC);
+				continue;
+			}
+#endif /* ECONNREFUSED */
+#ifdef ENOTCONN
+			else if (errno == ENOTCONN)
+			{
+				usleep(PGR_RECV_WAIT_MSEC);
+				continue;
+			}
+#endif /* ENOTCONN */
+			if (cnt < PGR_RECV_RETRY_CNT )
+			{
+				cnt ++;
+				usleep(PGR_RECV_WAIT_MSEC);
+				continue;
+			}
+			else
+			{
+				if (read_size == 0)
+				{
+					return -1;
+				}
+			}
+		}
+		if (r > 0)
+		{
+			read_size += r;
+			if (read_size == PGR_MESSAGE_BUFSIZE)
+			{
+				return read_size;
+			}
+		}
+		if ((r == 0) && (read_size == 0))
+		{
+			return -1;
+		}
+		if (cnt < PGR_RECV_RETRY_CNT )
+		{
+			cnt ++;
+			usleep(PGR_RECV_WAIT_MSEC);
+			continue;
+		}
+		else
+		{
+			return -1;
+		}
+	}
+}
+
+static void
+clear_recv_queue(int sock)
+{
+	fd_set      rmask;
+	struct timeval timeout;
+	char buf[PGR_MESSAGE_BUFSIZE];
+	int rtn = 0;
+
+	timeout.tv_sec = 0;
+	timeout.tv_usec = 0;
+
+	FD_ZERO(&rmask);
+	FD_SET(sock,&rmask);
+
+	memset(buf,0,sizeof(buf));
+	rtn = 1;
+	while (rtn)
+	{
+		FD_ZERO(&rmask);
+		FD_SET(sock,&rmask);
+		rtn = select(sock+1, &rmask, (fd_set *)NULL, (fd_set *)NULL, &timeout);
+		if ((rtn > 0) && (FD_ISSET(sock, &rmask)))
+		{
+			if (recv_message(sock, buf,0) <= 0)
+				break;
+		}
+		else if (errno == EINTR)
+		{
+			continue;
+		}
+		else
+		{
+			break;
+		}
+	}
+}
+
+static int
+send_replicate_packet(int sock,ReplicateHeader * header, const char * query_string)
+{
+	int s = 0;
+	int cnt = 0;
+	char * send_ptr = NULL;
+	char * buf = NULL;
+	int send_size = 0;
+	int buf_size = 0;
+	int header_size = 0;
+	int rtn = 0;
+	fd_set      wmask;
+	struct timeval timeout;
+	int query_size = 0;
+
+	/* check parameter */
+	if ((sock <= 0) || (header == NULL))
+	{
+		return STATUS_ERROR;
+	}
+	query_size = ntohl(header->query_size);
+	header_size = sizeof(ReplicateHeader);
+	buf_size = header_size + query_size + 4;
+	buf = (char *)malloc(buf_size);
+	if (buf == (char *)NULL)
+	{
+		return STATUS_ERROR;
+	}
+	memset(buf,0,buf_size);
+	buf_size -= 4;
+	memcpy(buf,header,header_size);
+	if (query_string != NULL)
+	{
+		memcpy((char *)(buf+header_size),query_string,query_size+1);
+	}
+	send_ptr = buf;
+
+	timeout.tv_sec = PGR_SEND_TIMEOUT;
+	timeout.tv_usec = 0;
+
+	/*
+	 * Wait for something to happen.
+	 */
+	rtn = 1;
+	while (rtn)
+	{
+		FD_ZERO(&wmask);
+		FD_SET(sock,&wmask);
+		rtn = select(sock+1, (fd_set *)NULL, &wmask, (fd_set *)NULL, &timeout);
+		if (rtn && FD_ISSET(sock, &wmask))
+		{
+			cnt = 0;
+			send_size = 0;
+			for (;;)
+			{
+				/* s = send(sock,send_ptr + send_size,buf_size - send_size ,MSG_DONTWAIT); */
+				s = send(sock,send_ptr + send_size,buf_size - send_size ,0);
+				if (s < 0){
+					if (errno == EINTR)
+					{
+						usleep(PGR_SEND_WAIT_MSEC);
+						continue;
+					}
+	#ifdef EAGAIN
+					if (errno == EAGAIN)
+					{
+						usleep(PGR_SEND_WAIT_MSEC);
+						continue;
+					}
+	#endif /* EAGAIN */
+	#ifdef EWOULDBLOCK
+					if (errno == EWOULDBLOCK )
+					{
+						usleep(PGR_SEND_WAIT_MSEC);
+						continue;
+					}
+	#endif /* EWOULDBLOCK */
+	#ifdef ENOBUF
+					if (errno == ENOBUF )
+					{
+						usleep(PGR_SEND_WAIT_MSEC);
+						continue;
+					}
+	#endif /* ENOBUF */
+	#ifdef ENOMEM
+					if (errno == ENOMEM )
+					{
+						usleep(PGR_SEND_WAIT_MSEC);
+						continue;
+					}
+	#endif /* ENOMEM */
+					if (cnt < PGR_SEND_RETRY_CNT )
+					{
+						cnt ++;
+						usleep(PGR_SEND_WAIT_MSEC);
+						continue;
+					}
+					else
+					{
+						if (send_size == 0)
+						{
+							free(buf);
+							buf = NULL;
+							return STATUS_ERROR;
+						}
+					}
+				}
+				if (s > 0)
+				{
+					send_size += s;
+					if (send_size == buf_size)
+					{
+						free(buf);
+						buf = NULL;
+						return STATUS_OK;
+					}
+				}
+				usleep(PGR_SEND_WAIT_MSEC);
+			}
+		}
+	}
+	if (buf != NULL)
+	{
+		free(buf);
+		buf = NULL;
+	}
+	return STATUS_ERROR;
+}
+
+bool
+PGR_Is_Replicated_Command(const char * query)
+{
+
+	return (PGR_Is_System_Command(query));
+}
+
+int
+Xlog_Check_Replicate(int operation)
+{
+	if ((PGR_Get_Cluster_Status() == STATUS_RECOVERY)	&&
+		(ClusterDB_Mode_Info.Transaction_Mode == false ) )
+	{
+		elog(WARNING, "This query is not permitted while recovery db ");
+	}
+	else if ((operation == CMD_UTILITY ) ||
+		(operation == CMD_INSERT )  ||
+		(operation == CMD_UPDATE )  ||
+		(operation == CMD_DELETE ))
+	{
+		return (PGR_Replicate_Function_Call());
+	}
+	return STATUS_OK;
+}
+
+int 
+PGR_Replicate_Function_Call(void)
+{
+	char *result = NULL;
+	int status = STATUS_OK;
+
+	if ((PGCluster_Info == NULL) ||
+		(PGCluster_Info->PGR_Stand_Alone == NULL))
+	{
+		 return STATUS_OK;
+	}
+	if (QueryString_Info.Query_String != NULL)
+	{
+		if (PGR_Is_Stand_Alone() == true)
+		{
+			if (PGCluster_Info->PGR_Stand_Alone->permit == PERMIT_READ_ONLY)
+			{
+				QueryString_Info.Query_String = NULL;
+				return STATUS_ERROR;
+			}
+		}
+		PGCluster_Info->PGR_Need_Notice = true;
+		PGCluster_Info->PGR_Check_Lock.check_lock_conflict = true;
+        result = PGR_Send_Replicate_Command(QueryString_Info.Query_String,strlen(QueryString_Info.Query_String), CMD_STS_QUERY,CMD_TYPE_SELECT);
+		if (result != NULL)
+		{
+			PGR_Reload_Start_Time();
+			if (!strncmp(result,PGR_DEADLOCK_DETECTION_MSG,strlen(PGR_DEADLOCK_DETECTION_MSG)))
+			{
+				status = STATUS_DEADLOCK_DETECT;
+			}
+			free(result);
+			result = NULL;
+		}
+		else
+		{
+			status = STATUS_ERROR;
+		}
+		QueryString_Info.Query_String = NULL;
+    }
+	return status;
+}
+
+void
+PGR_delete_shm(void)
+{
+	/*
+	if (PGCluster_Info == NULL)
+	{
+		return;
+	}
+	*/
+
+	if (ReplicationServer_Info.ReplicateServerData != NULL)
+	{
+		shmdt(ReplicationServer_Info.ReplicateServerData);
+		ReplicationServer_Info.ReplicateServerData = NULL;
+		shmctl(ClusterDB_Info.ReplicateServerShmid,IPC_RMID,(struct shmid_ds *)NULL);
+	}
+	if (ClusterDB_Info.ClusterDBData != NULL)
+	{
+		shmdt(ClusterDB_Info.ClusterDBData);
+		ClusterDB_Info.ClusterDBData = NULL;
+		shmctl(ClusterDB_Info.ClusterDBShmid,IPC_RMID,(struct shmid_ds *)NULL);
+	}
+	if (ReplicationServer_Info.TransactionSock != -1)
+	{
+		close(ReplicationServer_Info.TransactionSock);
+	}
+	if (ClusterDB_Info.PGRSelfHostName != NULL)
+	{
+		free(ClusterDB_Info.PGRSelfHostName);
+		ClusterDB_Info.PGRSelfHostName = NULL;
+	}
+	if (Partial_Info.PGR_Not_Replicate != NULL)
+	{
+		free(Partial_Info.PGR_Not_Replicate);
+		Partial_Info.PGR_Not_Replicate = NULL;
+	}
+	PGRsyn_quit();
+	if (PGCluster_Info == NULL) 
+	{
+		return;
+	}
+
+	if (PGCluster_Info->RsyncPath != NULL)
+	{
+		free(PGCluster_Info->RsyncPath);
+		PGCluster_Info->RsyncPath = NULL;
+	}
+	if (PGCluster_Info->RsyncOption != NULL)
+	{
+		free(PGCluster_Info->RsyncOption);
+		PGCluster_Info->RsyncOption = NULL;
+	}
+
+	if (PGCluster_Info->ReplicateCurrentTime != NULL)
+	{
+		free(PGCluster_Info->ReplicateCurrentTime);
+		PGCluster_Info->ReplicateCurrentTime = NULL;
+	}
+
+	if (PGCluster_Info->PGRCopyData != NULL)
+	{
+		free (PGCluster_Info->PGRCopyData);
+		PGCluster_Info->PGRCopyData = NULL;
+	}
+
+	if (PGCluster_Info->PGR_Stand_Alone != NULL)
+	{
+		free(PGCluster_Info->PGR_Stand_Alone);
+		PGCluster_Info->PGR_Stand_Alone = NULL;
+	}
+
+	if (PGCluster_Info->Com_Info.Log_Info.StatusFp != NULL)
+	{
+		fflush(PGCluster_Info->Com_Info.Log_Info.StatusFp);
+		fclose(PGCluster_Info->Com_Info.Log_Info.StatusFp);
+		PGCluster_Info->Com_Info.Log_Info.StatusFp = NULL;
+	}
+	if (PGCluster_Info->Com_Info.Log_Info.LogFp != NULL)
+	{
+		fflush(PGCluster_Info->Com_Info.Log_Info.LogFp);
+		fclose(PGCluster_Info->Com_Info.Log_Info.LogFp);
+		PGCluster_Info->Com_Info.Log_Info.LogFp = NULL;
+	}
+}
+
+ReplicateServerInfo * 
+PGR_get_replicate_server_info(void)
+{
+	ReplicateServerInfo * sp;
+
+	if (ReplicationServer_Info.ReplicateServerData == NULL)
+	{
+		return (ReplicateServerInfo *)NULL;
+	}
+	sp = ReplicationServer_Info.ReplicateServerData;
+	while (sp->useFlag != DATA_END)
+	{
+		if (sp->useFlag == DATA_USE )
+		{
+			if (ReplicationServer_Info.CurrentReplicateServer != NULL)
+			{
+				ReplicationServer_Info.LastReplicateServer = ReplicationServer_Info.CurrentReplicateServer;
+			}
+			ReplicationServer_Info.CurrentReplicateServer = sp;
+			return (ReplicationServer_Info.CurrentReplicateServer);
+		}
+		sp++;
+	}
+	sp = ReplicationServer_Info.ReplicateServerData;
+	while (sp->useFlag != DATA_END)
+	{
+		if (sp->useFlag != DATA_ERR )
+		{
+			if (ReplicationServer_Info.CurrentReplicateServer != NULL)
+			{
+				ReplicationServer_Info.LastReplicateServer = ReplicationServer_Info.CurrentReplicateServer;
+			}
+			ReplicationServer_Info.CurrentReplicateServer = sp;
+			return (ReplicationServer_Info.CurrentReplicateServer);
+		}
+		sp++;
+	}
+	if (PGCluster_Info != NULL)
+	{
+		PGCluster_Info->PGR_Stand_Alone->is_stand_alone = true;
+	}
+	if (ReplicationServer_Info.CurrentReplicateServer != NULL)
+	{
+		ReplicationServer_Info.LastReplicateServer = ReplicationServer_Info.CurrentReplicateServer;
+	}
+	ReplicationServer_Info.CurrentReplicateServer = NULL;
+	return (ReplicateServerInfo *)NULL;
+}
+
+int
+PGR_Send_Copy(CopyData * copy,int end )
+{
+	char cmdSts,cmdType;
+	char * p = NULL;
+	char *result = NULL;
+	char term[8];
+	int i;
+	/*int status = 0; */
+	fflush(stderr);
+	if (copy == NULL)
+	{
+	fflush(stderr);
+		return STATUS_ERROR;
+	}
+
+	cmdSts = CMD_STS_COPY;
+
+	if (ClusterDB_Mode_Info.Transaction_Mode)
+	{
+		cmdSts = CMD_STS_TRANSACTION ;
+	}
+	if (ClusterDB_Mode_Info.Session_Authorization_Mode)
+	{
+		cmdSts = CMD_STS_SET_SESSION_AUTHORIZATION ;
+	}
+	cmdType = CMD_TYPE_COPY_DATA;
+	fflush(stderr);
+	if (end)
+	{
+		memset(term,0,sizeof(term));
+		cmdType = CMD_TYPE_COPY_DATA_END;
+		i = copy->cnt-1;
+		if ((copy->copy_data[i]) == EOF)
+		{
+			p = &(copy->copy_data[i]);
+			strcpy(term,"\\.\n");
+			strncpy(p,term,sizeof(term));
+			copy->cnt += 2;
+		}
+	}
+	fflush(stderr);
+	result = PGR_Send_Replicate_Command(copy->copy_data, copy->cnt, cmdSts, cmdType);
+	memset(copy,0,sizeof(CopyData));
+
+	if (result != NULL)
+	{
+		PGR_Reload_Start_Time();
+		free(result);
+		result = NULL;
+		return STATUS_OK;
+	}
+	else
+	{
+		return STATUS_ERROR;
+	}
+}
+
+CopyData * 
+PGR_Set_Copy_Data(CopyData * copy, char *str, int len,int end)
+{
+	int copy_size, send_size;
+	char * ep;
+	int rest_len;
+	CopyData rest_data;
+	int status = STATUS_OK;
+	char buf[4096];
+	memset (buf,0,sizeof(buf));
+
+	if (PGCluster_Info == NULL)
+	{
+		return (CopyData *)NULL;
+	}
+	if ((ClusterDB_Mode_Info.PGR_Copy_Data_Need_Replicate == false) ||
+		(copy == NULL))
+	{
+		return (CopyData *)NULL;
+	}
+	if (len > 0)
+	{
+memcpy(buf,str,len);
+		copy_size = COPYBUFSIZ - copy->cnt -4;
+		send_size = 0;
+		if (copy_size < len)
+		{
+			memcpy(&(copy->copy_data[copy->cnt]) ,str + send_size,copy_size);
+			copy->cnt  += copy_size;
+			send_size += copy_size;
+			len -= copy_size;
+			ep = strrchr(copy->copy_data,'\n');
+			if (ep != NULL)
+			{
+				*ep = '\0';
+				rest_len = copy->cnt - strlen(copy->copy_data) -1;
+				memset(&rest_data,0,sizeof(CopyData));
+				memcpy(rest_data.copy_data,(ep +1),rest_len);
+				copy->cnt -= (rest_len );
+				*ep = '\n';
+				*(ep+1) = '\0';
+				status = PGR_Send_Copy(copy,0);
+				memcpy(copy->copy_data,rest_data.copy_data,rest_len);
+				copy->cnt = rest_len;
+			}
+			status = PGR_Send_Copy(copy,0);
+			/*copy_size = COPYBUFSIZ - copy->cnt -1;*/
+		}
+		memcpy(&(copy->copy_data[copy->cnt]) ,str + send_size,len);
+		copy->cnt  += len;
+	}
+	if (end)
+	{
+		status = PGR_Send_Copy(copy,end);
+	}
+
+	if (status != STATUS_OK)
+	{
+		return (CopyData *)NULL;
+	}
+
+	return copy;
+}
+
+static int
+PGR_replication(const char * query_string, CommandDest dest, const char * commandTag)
+{
+	char *result = NULL;
+	char cmdSts = CMD_STS_OTHER;
+	char cmdType = CMD_TYPE_OTHER;
+	int query_len = 0;
+	int session_type;
+
+	if ((PGCluster_Info == NULL)   ||
+		(query_string == NULL) ||
+		(commandTag == NULL))
+	{
+		return STATUS_ERROR;
+	}
+
+	QueryString_Info.Query_String = NULL;
+	query_len = strlen(query_string);
+
+	/* save query data for retry */
+	PGCluster_Info->PGR_Retry_Query.query_string = query_string;
+	PGCluster_Info->PGR_Retry_Query.query_len = query_len;
+	PGCluster_Info->PGR_Retry_Query.cmdSts = cmdSts;
+	PGCluster_Info->PGR_Retry_Query.cmdType = cmdType;
+	PGCluster_Info->PGR_Retry_Query.useFlag = DATA_USE;
+	/* set cmdType */
+	if (!strcmp(commandTag,"BEGIN")) cmdType = CMD_TYPE_BEGIN ;
+	else if (!strcmp(commandTag,"COMMIT")) cmdType = CMD_TYPE_COMMIT ;
+	else if (!strcmp(commandTag,"SELECT")) cmdType = CMD_TYPE_SELECT ;
+	else if (!strcmp(commandTag,"INSERT")) cmdType = CMD_TYPE_INSERT ;
+	else if (!strcmp(commandTag,"UPDATE")) cmdType = CMD_TYPE_UPDATE ;
+	else if (!strcmp(commandTag,"DELETE")) cmdType = CMD_TYPE_DELETE ;
+	else if (!strcmp(commandTag,"VACUUM")) cmdType = CMD_TYPE_VACUUM ;
+	else if (!strcmp(commandTag,"ANALYZE")) cmdType = CMD_TYPE_ANALYZE ;
+	else if (!strcmp(commandTag,"REINDEX")) cmdType = CMD_TYPE_REINDEX ;
+	else if (!strcmp(commandTag,"ROLLBACK")) cmdType = CMD_TYPE_ROLLBACK ;
+	else if (!strcmp(commandTag,"RESET")) cmdType = CMD_TYPE_RESET ;
+	else if (!strcmp(commandTag,"START TRANSACTION")) cmdType = CMD_TYPE_BEGIN ;
+
+	else if (!strcmp(commandTag,"COPY"))
+	{
+		cmdType = CMD_TYPE_COPY ;
+		if (is_copy_from(query_string))
+		{
+			ClusterDB_Mode_Info.PGR_Copy_Data_Need_Replicate = true;
+		}
+		else
+		{
+			ClusterDB_Mode_Info.PGR_Copy_Data_Need_Replicate = false;
+			return STATUS_NOT_REPLICATE;
+		}
+	}
+	else if (!strcmp(commandTag,"SET")) 
+	{
+		cmdType = CMD_TYPE_SET;
+		session_type = is_session_authorization(query_string);
+		switch (session_type)
+		{
+			case SESSION_AUTHORIZATION_BEGIN:
+				cmdType = CMD_TYPE_SESSION_AUTHORIZATION_BEGIN ;
+				ClusterDB_Mode_Info.Session_Authorization_Mode = true;
+				break;
+			case SESSION_AUTHORIZATION_END:
+				cmdType = CMD_TYPE_SESSION_AUTHORIZATION_END ;
+				ClusterDB_Mode_Info.Session_Authorization_Mode = false;
+				break;
+		}
+	}
+	else if (!strcmp(commandTag,"CREATE TABLE")) 
+	{
+		if (is_create_temp_table(query_string))
+		{
+			ClusterDB_Mode_Info.Create_Temp_Table_Mode = true;
+		}
+	}
+	if (ClusterDB_Mode_Info.Create_Temp_Table_Mode)
+	{
+		cmdSts = CMD_STS_TEMP_TABLE ;
+	}
+
+	/* check partitional replication table */
+	if (is_not_replication_query(query_string, query_len, cmdType)== true )
+	{
+		ClusterDB_Mode_Info.PGR_Copy_Data_Need_Replicate = false;
+		return STATUS_NOT_REPLICATE;
+	}
+
+	if ((is_transaction_command(commandTag) == true) ||
+		(autocommit == false ))
+	{
+		ClusterDB_Mode_Info.Transaction_Mode = true;
+	}
+	if (ClusterDB_Mode_Info.Transaction_Mode)
+	{
+		cmdSts = CMD_STS_TRANSACTION ;
+		if ((cmdType == CMD_TYPE_COMMIT ) ||
+			(cmdType == CMD_TYPE_ROLLBACK ))
+		{
+			if (autocommit == true)
+				ClusterDB_Mode_Info.Transaction_Mode = false;
+			if (PGCluster_Info->ReplicateCurrentTime != NULL)
+			{
+				PGCluster_Info->ReplicateCurrentTime->useFlag = DATA_INIT;
+				PGCluster_Info->ReplicateCurrentTime->use_seed = 0;
+				PGCluster_Info->ReplicateCurrentTime->use_time = 0;
+			}
+		}
+	}
+	if (ClusterDB_Mode_Info.Session_Authorization_Mode)
+	{
+		cmdSts = CMD_STS_SET_SESSION_AUTHORIZATION ;
+		if (cmdType == CMD_TYPE_SESSION_AUTHORIZATION_END)
+		{
+			ClusterDB_Mode_Info.Session_Authorization_Mode = false;
+		}
+	}
+	if ((cmdSts == CMD_STS_TRANSACTION ) ||
+		(cmdSts == CMD_STS_SET_SESSION_AUTHORIZATION ) ||
+		(cmdSts == CMD_STS_TEMP_TABLE ))
+	{
+		QueryString_Info.Query_String = NULL;
+		if (( do_not_replication_command(commandTag) == true) &&
+			(strcmp(commandTag,"SELECT")))
+		{
+			return STATUS_NOT_REPLICATE;
+		}
+
+		if (Debug_pretty_print)
+			elog(DEBUG1,"transaction query send :%s",(char *)query_string);
+		PGCluster_Info->PGR_Retry_Query.cmdSts = cmdSts;
+		PGCluster_Info->PGR_Retry_Query.cmdType = cmdType;
+		result = PGR_Send_Replicate_Command(query_string,query_len, cmdSts,cmdType);
+		if (result != NULL)
+		{
+			if (!strncmp(result,PGR_DEADLOCK_DETECTION_MSG,strlen(PGR_DEADLOCK_DETECTION_MSG)))
+			{
+				/*
+				PGR_Send_Message_To_Frontend(result);
+				*/
+				free(result);
+				result = NULL;
+				return STATUS_DEADLOCK_DETECT;
+			}
+			else if (!strncmp(result,PGR_REPLICATION_ABORT_MSG,strlen(PGR_REPLICATION_ABORT_MSG)))
+			{
+				free(result);
+				result = NULL;
+				return STATUS_REPLICATION_ABORT;
+			}
+			free(result);
+			result = NULL;
+			return STATUS_CONTINUE;
+		}
+		else
+		{
+			return STATUS_ERROR;
+		}
+	}
+	else
+	{
+		cmdSts = CMD_STS_QUERY ;
+		if ( do_not_replication_command(commandTag) == false)
+		{
+			QueryString_Info.Query_String = NULL;
+			result = PGR_Send_Replicate_Command(query_string,query_len,cmdSts,cmdType);
+			if (result != NULL)
+			{
+				if (!strncmp(result,PGR_DEADLOCK_DETECTION_MSG,strlen(PGR_DEADLOCK_DETECTION_MSG)))
+				{
+					free(result);
+					result = NULL;
+					return STATUS_DEADLOCK_DETECT;
+				}
+				else if (!strncmp(result,PGR_REPLICATION_ABORT_MSG,strlen(PGR_REPLICATION_ABORT_MSG)))
+				{
+					free(result);
+					result = NULL;
+					return STATUS_REPLICATION_ABORT;
+				}
+				free(result);
+				result = NULL;
+				return STATUS_CONTINUE;
+			}
+			else
+			{
+				return STATUS_ERROR;
+			}
+		}
+		else
+		{
+			if (( is_serial_control_query(cmdType,query_string) == true) ||
+				( is_select_into_query(cmdType,query_string) == true))
+			{
+				QueryString_Info.Query_String = NULL;
+				PGCluster_Info->PGR_Need_Notice = true;
+				PGCluster_Info->PGR_Check_Lock.check_lock_conflict = true;
+				result = PGR_Send_Replicate_Command(query_string,query_len,cmdSts,cmdType);
+				if (result != NULL)
+				{
+					/*
+					PGR_Send_Message_To_Frontend(result);
+					*/
+					if (!strncmp(result,PGR_DEADLOCK_DETECTION_MSG,strlen(PGR_DEADLOCK_DETECTION_MSG)))
+					{
+						free(result);
+						return STATUS_DEADLOCK_DETECT;
+					}
+					free(result);
+					result = NULL;
+					return STATUS_CONTINUE;
+				}
+				else
+				{
+					return STATUS_ERROR;
+				}
+			}
+			else
+			{
+				QueryString_Info.Query_String = query_string;
+				/*ReplicationServer_Info.PGR_Sock_To_Replication_Server = -1;*/
+			}
+			return STATUS_CONTINUE_SELECT;
+		}
+	}
+	return STATUS_CONTINUE;
+}
+
+
+bool
+PGR_Is_System_Command(const char * query)
+{
+	char * ptr;
+
+	if (query == NULL)
+	{
+		return false;
+	}
+	ptr = strstr(query,PGR_SYSTEM_COMMAND_FUNC);
+	if (ptr != NULL)
+	{
+		ptr = strchr(ptr,'(');
+		if (ptr == NULL)
+			return false;
+		return true;
+	}
+	return false;
+}
+
+static int
+set_command_args(char argv[ PGR_CMD_ARG_NUM ][256],char *str)
+{
+	int i,j,cnt,len;
+	char * ptr = str;
+
+	if (str == NULL)
+	{
+		return 0;
+	}
+	len = strlen(str);
+	cnt = j = 0;
+	for ( i = 0 ; i < len ; i++,ptr++)
+	{
+		if (cnt >= PGR_CMD_ARG_NUM)
+			break;
+		if (( *ptr == ',') || (*ptr == ')'))
+		{
+			argv[cnt][j] = '\0';
+			cnt ++;
+			j = 0;
+			continue;
+		}
+		argv[cnt][j] = *ptr;
+		j++;
+	}
+	if (cnt < PGR_CMD_ARG_NUM)
+		argv[cnt][j] = '\0';
+	cnt ++;
+
+	return cnt;
+}
+
+static int
+add_replication_server(char * hostname,char * port, char * recovery_port, char * lifecheck_port)
+{
+	int cnt = 0;
+	uint16_t portNumber = 0;
+	uint16_t recoveryPortNumber = 0;
+	uint16_t lifecheckPortNumber = 0;
+	ReplicateServerInfo * sp = NULL;
+	unsigned int h1,h2;
+
+	if ((PGCluster_Info == NULL) ||
+		(hostname == NULL)   ||
+		(port == NULL )      ||
+		(recovery_port == NULL ))
+	{
+		return STATUS_ERROR;
+	}
+	if (ReplicationServer_Info.ReplicateServerData == NULL)
+	{
+		return STATUS_ERROR;
+	}
+	if (atoi(port) > 0)
+	{
+		portNumber = atoi(port);
+	}
+	else
+	{
+		portNumber = DEFAULT_PGRP_PORT;
+	}
+	if (atoi(recovery_port) > 0)
+	{
+		recoveryPortNumber = atoi(recovery_port);
+	}
+	else
+	{
+		recoveryPortNumber = DEFAULT_PGRP_RECOVERY_PORT;
+	}
+	if (atoi(lifecheck_port) > 0)
+	{
+		lifecheckPortNumber = atoi(lifecheck_port);
+	}
+	else
+	{
+		lifecheckPortNumber = DEFAULT_PGRP_RECOVERY_PORT;
+	}
+	h1 = PGRget_ip_by_name(hostname);
+	cnt = 0;
+	sp = ReplicationServer_Info.ReplicateServerData;
+	while (sp->useFlag != DATA_END){
+		h2 = PGRget_ip_by_name(sp->hostName);
+		if((h1 == h2) &&
+			(sp->portNumber == portNumber) &&
+			(sp->recoveryPortNumber == PGCluster_Info->Com_Info.ConfData_Info.Recovery_Port_Number))
+		{
+			if (sp->useFlag != DATA_USE)
+			{
+				PGR_Set_Replication_Server_Status(sp, DATA_INIT);
+			}
+			return STATUS_OK;
+		}
+		sp ++;
+		cnt ++;
+	}
+	if (cnt < MAX_SERVER_NUM)
+	{
+		strncpy(sp->hostName,hostname,sizeof(sp->hostName));
+		sp->portNumber = portNumber;
+		sp->recoveryPortNumber = PGCluster_Info->Com_Info.ConfData_Info.Recovery_Port_Number;
+		sp->lifecheckPortNumber = lifecheckPortNumber;
+		PGR_Set_Replication_Server_Status(sp, DATA_INIT);
+		memset((sp+1),0,sizeof(ReplicateServerInfo));
+		(sp + 1)->useFlag = DATA_END;
+	}
+	else
+	{
+		return STATUS_ERROR;
+	}
+	return	STATUS_OK;
+}
+
+static int
+change_replication_server(char * hostname,char * port, char * recovery_port)
+{
+	int cnt;
+	uint16_t portNumber;
+	uint16_t recoveryPortNumber;
+	ReplicateServerInfo * sp;
+	uint32_t h1,h2;
+
+	if ((PGCluster_Info == NULL)  ||
+		(hostname == NULL)    ||
+		(port == NULL )       ||
+		(recovery_port == NULL ))
+	{
+		return STATUS_ERROR;
+	}
+	if (ReplicationServer_Info.ReplicateServerData == NULL)
+	{
+		return STATUS_ERROR;
+	}
+
+	h1 = PGRget_ip_by_name(hostname);
+	portNumber = atoi(port);
+	recoveryPortNumber = atol(recovery_port);
+	cnt = 0;
+	sp = ReplicationServer_Info.ReplicateServerData;
+	while (sp->useFlag != DATA_END){
+		h2 = PGRget_ip_by_name(sp->hostName);
+		if((h1 == h2) &&
+			(sp->portNumber == portNumber) &&
+			(sp->recoveryPortNumber == PGCluster_Info->Com_Info.ConfData_Info.Recovery_Port_Number))
+		{
+			PGR_Set_Replication_Server_Status(sp, DATA_USE);
+		}
+		else
+		{
+			if (sp->useFlag == DATA_USE)
+			{
+				PGR_Set_Replication_Server_Status(sp, DATA_INIT);
+			}
+		}
+		sp ++;
+		cnt ++;
+	}
+	return	STATUS_OK;
+}
+
+int
+PGR_Set_Current_Time(char * sec, char * usec)
+{
+	struct timeval orig_tv;
+	struct timezone tpz;
+	struct timeval tv;
+
+	if ((PGCluster_Info == NULL) ||
+		(sec == NULL)  ||
+		(usec == NULL) ||
+		(PGCluster_Info->ReplicateCurrentTime == (ReplicateNow *)NULL))
+	{
+		return STATUS_ERROR;
+	}
+
+
+	gettimeofday(&orig_tv, &tpz);
+	tv.tv_sec = atol(sec);
+	tv.tv_usec = atol(usec);
+	PGCluster_Info->ReplicateCurrentTime->tp.tv_sec = tv.tv_sec;
+	PGCluster_Info->ReplicateCurrentTime->tp.tv_usec = tv.tv_usec;
+	PGCluster_Info->ReplicateCurrentTime->useFlag = DATA_USE;
+	PGCluster_Info->ReplicateCurrentTime->use_seed = 0;
+	/* set offset */
+	PGCluster_Info->ReplicateCurrentTime->use_time = 0;
+	PGCluster_Info->ReplicateCurrentTime->offset_sec = tv.tv_sec - orig_tv.tv_sec;
+	PGCluster_Info->ReplicateCurrentTime->offset_usec = tv.tv_usec - orig_tv.tv_usec;
+	return	STATUS_OK;
+}
+
+static int
+set_replication_id(char * id)
+{
+	if (id == NULL)
+	{
+		return STATUS_ERROR;
+	}
+	/*set replicate id in this process */
+	ReplicationLog_Info.PGR_Replicate_ID = atol(id);
+
+	if (ReplicationServer_Info.CurrentReplicateServer == NULL)
+	{
+		PGR_get_replicate_server_info();
+	}
+	if (ReplicationServer_Info.CurrentReplicateServer != NULL)
+	{
+		/* set replicate id in this system */
+		ReplicationServer_Info.CurrentReplicateServer->replicate_id = atol(id);
+	}
+	
+	return STATUS_OK;
+}
+
+static void
+set_response_mode(char * mode)
+{
+	int response_mode = 0;
+
+	if (mode == NULL)
+		return;
+	response_mode = atoi(mode);
+	if (response_mode < 0)
+		return;
+	if (ReplicationServer_Info.CurrentReplicateServer == NULL)
+	{
+		PGR_get_replicate_server_info();
+		if (ReplicationServer_Info.CurrentReplicateServer == NULL)
+		{
+			return;
+		}
+	}
+	if (ReplicationServer_Info.CurrentReplicateServer->response_mode != response_mode)
+	{
+		ReplicationServer_Info.CurrentReplicateServer->response_mode = response_mode;
+	}
+}
+
+int
+PGR_Call_System_Command(char * command)
+{
+	char * ptr;
+	char * args;
+	char argv[ PGR_CMD_ARG_NUM ][256];
+	int argc = 0;
+	int func_no;
+	char * hostName = NULL;
+
+	if ((PGCluster_Info == NULL) ||
+		(command == NULL)    || 
+		(PGCluster_Info->ReplicateCurrentTime == NULL))
+	{
+		return STATUS_ERROR;
+	}
+
+	ptr = strstr(command,PGR_SYSTEM_COMMAND_FUNC);
+	if (ptr == NULL)
+		return STATUS_ERROR;
+	ptr = strchr(ptr,'(');
+	if (ptr == NULL)
+		return STATUS_ERROR;
+	args = ptr+1;
+	ptr = strchr(ptr,')');
+	if (ptr == NULL)
+		return STATUS_ERROR;
+	*ptr = '\0';
+	argc = set_command_args(argv,args);
+	if (argc < 1)
+		return STATUS_ERROR;
+	func_no = atoi(argv[0]);
+	switch (func_no)
+	{
+		/* set current system time */
+		case PGR_SET_CURRENT_TIME_FUNC_NO:
+			if ((atoi(argv[3]) > 0) &&
+				(is_this_query_replicated(argv[3]) == true))
+			{
+				/* skip this query */
+				return STATUS_SKIP_QUERY;
+			}
+			PGR_Set_Current_Time(argv[1],argv[2]);
+			set_replication_id(argv[3]);
+			set_response_mode(argv[4]);
+			break;
+		/* add new replication server data */
+		case PGR_STARTUP_REPLICATION_SERVER_FUNC_NO:
+			hostName = get_hostName(argv[1]);
+			add_replication_server(hostName,argv[2],argv[3],argv[4]);
+			break;
+		/* change new replication server */
+		case PGR_CHANGE_REPLICATION_SERVER_FUNC_NO:
+			hostName = get_hostName(argv[1]);
+			change_replication_server(hostName,argv[2],argv[3]);
+			break;
+		/* check replication id */
+		case PGR_QUERY_CONFIRM_ANSWER_FUNC_NO:
+			if ((atoi(argv[3]) > 0) &&
+				(is_this_query_replicated(argv[3]) == true))
+			{
+				/* skip this query */
+				return STATUS_SKIP_QUERY;
+			}
+			else
+			{
+				PGR_Set_Current_Time(argv[1],argv[2]);
+				set_replication_id(argv[3]);
+			}
+			break;
+		/* get current oid */
+		case PGR_GET_OID_FUNC_NO:
+			return_current_oid();
+			break;
+		/* set current oid */
+		case PGR_SET_OID_FUNC_NO:
+			sync_oid(argv[1]);
+			break;
+	}
+	return STATUS_OK;
+}
+
+int
+PGR_GetTimeOfDay(struct timeval *tp, struct timezone *tpz)
+{
+
+	int rtn;
+
+	rtn = gettimeofday(tp, tpz);
+	if ((PGCluster_Info == NULL) ||
+		(PGCluster_Info->ReplicateCurrentTime == NULL))
+	{
+		return rtn;
+	}
+	if (PGCluster_Info->ReplicateCurrentTime->useFlag == DATA_USE)
+	{
+		if ( PGCluster_Info->ReplicateCurrentTime->use_time <= 1)
+		{
+			tp->tv_sec = PGCluster_Info->ReplicateCurrentTime->tp.tv_sec;
+			tp->tv_usec = PGCluster_Info->ReplicateCurrentTime->tp.tv_usec;
+			if ((ClusterDB_Mode_Info.Transaction_Mode == false) && 
+				(ClusterDB_Mode_Info.Session_Authorization_Mode == false))
+			{
+				PGCluster_Info->ReplicateCurrentTime->use_time ++;
+			}
+		}
+		else
+		{
+			tp->tv_sec += PGCluster_Info->ReplicateCurrentTime->offset_sec;
+		}
+		rtn = 0;
+	}
+	return rtn;
+}
+
+long
+PGR_Random(void)
+{
+	double rtn;
+	if ((PGCluster_Info != NULL) &&
+		(PGCluster_Info->ReplicateCurrentTime != NULL))
+	{
+		if ( PGCluster_Info->ReplicateCurrentTime->use_seed == 0)
+		{
+			srand( PGCluster_Info->ReplicateCurrentTime->tp.tv_sec );
+			PGCluster_Info->ReplicateCurrentTime->use_seed = 1;
+		}
+	}
+	rtn = random();
+	return rtn;
+}
+
+char *
+PGR_scan_terminate(const char * str)
+{
+	char * p;
+	int sflag = 0;
+	int dflag = 0;
+
+	if (str == NULL)
+		return NULL;
+	p = (char *)str;
+	while ( *p != '\0' )
+	{
+		if ((!strncmp(p,"--",2)) ||
+			(!strncmp(p,"//",2)))
+		{
+			while (( *p != '\n') && (*p != '\0'))
+			{
+				p++;
+			}
+			continue;
+		}
+
+		switch (*p)
+		{
+			case '\'':
+				sflag ^= 1;
+				break;
+			case '\"':
+				dflag ^= 1;
+				break;
+			case '\\':
+				p +=2;
+				continue;
+				break;
+			case ';':
+				if ((!sflag) && (!dflag))
+					return p;
+				break;
+		}
+		p++;
+	}
+	return NULL;
+}
+
+static bool
+is_copy_from(const char * query)
+{
+	char * p;
+	int i;
+	char buf[12];
+	int c_flag = 0;
+	if (query == NULL)
+		return false;
+	p = (char *)query;
+	for ( i = 0 ; i <= 1 ; i ++)
+	{
+		/* get 'copy table_name' string */
+		while(isspace(*p))
+			p++;
+		while ((*p != '\0') && (*p  != '(') && (!isspace(*p)))
+			p++;
+	}
+	while(isspace(*p))
+		p++;
+	/* skip table column */
+	if (*p == '(')
+	{
+		c_flag = 1;
+		p++;
+		while (*p != '\0') 
+		{
+			if (*p == '(')
+				c_flag ++;
+			if (*p == ')')
+				c_flag --;
+			if (c_flag == 0)
+			{
+				p++;
+				break;
+			}
+			p++;
+		}
+		while(isspace(*p))
+			p++;
+	}
+	/* get 'from' or 'to' */
+	i = 0;
+	memset(buf,0,sizeof(buf));
+	while ((*p != '\0') && (!isspace(*p)) && ( i < sizeof(buf)-1))
+	{
+		buf[i] = (char)toupper(*p);
+		p++;
+		i++;
+	}
+	if (!strcmp(buf,"FROM"))
+	{
+		return true;
+	}
+	else
+	{
+		return false;
+	}
+}
+
+static bool
+is_create_temp_table(const char * query)
+{
+	int len,wc;
+	char buf[MAX_WORDS][MAX_WORD_LETTERS];
+
+	if (query == NULL)
+		return false;
+	len = strlen(query);
+	wc = get_words(buf,query,len,1);
+	if (wc < 4)
+		return false;
+	if ((!strncmp(buf[0],"CREATE", strlen("CREATE"))) &&
+		(!strncmp(buf[1],"TEMP",strlen("TEMP"))) &&
+		(!strncmp(buf[2],"TABLE",strlen("TABLE"))))
+	{
+		return true;
+	}
+	return false;
+}
+	
+static int
+is_session_authorization(const char * query)
+{
+
+	int len,wc;
+	int cnt,rtn;
+	char buf[MAX_WORDS][MAX_WORD_LETTERS];
+
+	if (query == NULL)
+		return NOT_SESSION_AUTHORIZATION;
+
+	rtn = NOT_SESSION_AUTHORIZATION;
+	len = strlen(query);
+	wc = get_words(buf,query,len,1);
+	if (wc < 4)
+	{
+		return NOT_SESSION_AUTHORIZATION;
+	}
+	if ((!strncmp(buf[0],"RESET", strlen("RESET"))) &&
+		(!strncmp(buf[1],"SESSION",strlen("SESSION"))) &&
+		(!strncmp(buf[2],"AUTHORIZATION",strlen("AUTHORIZATION"))))
+	{
+		return SESSION_AUTHORIZATION_END;
+	}
+	cnt = 1;
+	if (!strcmp(buf[cnt],"SESSION"))
+	{
+		cnt ++;
+		if (!strcmp(buf[cnt],"AUTHORIZATION"))
+		{
+			rtn = SESSION_AUTHORIZATION_BEGIN;
+		}
+		else
+		{
+			cnt ++;
+			if (!strcmp(buf[cnt],"AUTHORIZATION"))
+			{
+				rtn = SESSION_AUTHORIZATION_BEGIN;
+			}
+		}
+		cnt ++;
+		if (!strcmp(buf[cnt],"DEFAULT"))
+		{
+			rtn = SESSION_AUTHORIZATION_END;
+		}
+	}
+	return rtn;
+}
+
+static int
+get_words( char words[MAX_WORDS][MAX_WORD_LETTERS] ,const char * string,int length,int upper)
+{
+	int i,wc,lc;
+	char * p = NULL;
+	char * buf = NULL;
+
+	if (string == NULL)
+		return STATUS_ERROR;
+	buf = (char *)malloc(length);
+	if (buf == (char *)NULL)
+		return STATUS_ERROR;
+
+	memset(buf,0,length);
+	p = (char *)string;
+	wc = 0;
+	for (i = 0 ; i < length ; i ++)
+	{
+		if ((*p == '\0') || (wc >= MAX_WORDS))
+			break;
+		while (isspace(*p))
+		{
+			p++;
+			i++;
+		}
+		lc = 0;
+		while ((*p != '\0') && (! isspace(*p)))
+		{
+			if (upper)
+				*(buf+lc) = (char)toupper(*p);
+			else
+				*(buf+lc) = *p;
+
+			p++;
+			i++;
+			lc++;
+		}
+		memset(words[wc],0,MAX_WORD_LETTERS);
+		memcpy(words[wc],buf,lc);
+		memset(buf,0,length);
+		wc++;
+	}
+	free(buf);
+	buf = NULL;
+	return wc;
+}
+
+static int
+Comp_Not_Replicate(PGR_Not_Replicate_Type * nrp1,PGR_Not_Replicate_Type* nrp2)
+{
+	int rtn;
+
+	if ((nrp1 == NULL) ||
+		(nrp2 == NULL))
+	{
+		return 0;
+	}
+	rtn = strcmp(nrp1->table_name,nrp2->table_name);
+	if (rtn == 0)
+	{
+		rtn = strcmp(nrp1->db_name,nrp2->db_name);
+	}
+	return rtn;
+}
+
+bool
+PGR_Is_Stand_Alone(void)
+{
+	if ((PGCluster_Info == NULL) || 
+		(PGCluster_Info->PGR_Stand_Alone == NULL))
+	{
+		return true;
+	}
+	if (PGCluster_Info->PGR_Stand_Alone->is_stand_alone == true)
+	{
+		return true;
+	}
+	return false;
+}
+
+void
+PGR_Send_Message_To_Frontend(char * msg)
+{
+	StringInfoData buf;
+
+	if (msg == NULL)
+		return;
+	switch (*msg)
+	{
+		/* normal message */
+		case 'C':
+			pq_puttextmessage(*msg,msg+1);
+			break;
+		/* error message */
+		case 'E':
+		case 'N':
+			initStringInfo(&buf);
+			pq_sendbyte(&buf,*msg);
+			pq_sendstring(&buf, msg+1);
+			pq_endmessage(&buf);
+			break;
+	}
+	pq_flush();
+}
+
+static bool
+is_serial_control_query(char cmdType, const char * query)
+{
+	char * buf = NULL;
+	int len = 0;
+	int i = 0;
+	char * p = NULL;
+
+	if ((cmdType != CMD_TYPE_SELECT ) ||
+		( query == NULL))
+	{
+		return false;
+	}
+
+	p = (char *)query;
+	len = strlen(query) +1;
+	buf = (char *)malloc(len);
+	if (buf == (char *)NULL)
+		return false;
+
+	memset(buf,0,len);
+	for ( i = 0 ; i < len ; i ++)
+	{
+		*(buf+i) = toupper(*(query+i));
+	}
+	if ((strstr(buf,"NEXTVAL") != NULL) ||
+		(strstr(buf,"SETVAL") != NULL))
+	{
+		free(buf);
+		buf = NULL;
+		return true;
+	}
+	free(buf);
+	buf = NULL;
+	return false;
+}
+
+static bool
+is_select_into_query(char cmdType, const char * query)
+{
+	char * buf = NULL;
+	int len = 0;
+	int i = 0;
+	char * p = NULL;
+
+	if ((cmdType != CMD_TYPE_SELECT ) ||
+		( query == NULL))
+	{
+		return false;
+	}
+
+	p = (char *)query;
+	len = strlen(query) +1;
+	buf = malloc(len);
+	if (buf == (char *)NULL)
+		return false;
+
+	memset(buf,0,len);
+	for ( i = 0 ; i < len ; i ++)
+	{
+		*(buf+i) = toupper(*(query+i));
+	}
+	if (strstr(buf,"INTO") != NULL)
+	{
+		free(buf);
+		buf = NULL;
+		return true;
+	}
+	free(buf);
+	buf = NULL;
+	return false;
+}
+
+static int
+send_response_to_replication_server(const char * notice)
+{
+	ReplicateHeader header;
+	int status;
+
+	if ((PGCluster_Info == NULL) ||
+		(PGCluster_Info->PGR_Lock_Noticed))
+	{
+		return STATUS_OK;
+	}
+	if ((notice == NULL) ||
+		(ReplicationServer_Info.PGR_Sock_To_Replication_Server <= 0))
+	{
+		return STATUS_ERROR;
+	}
+
+	memset(&header,0,sizeof(ReplicateHeader));
+	header.cmdSys = CMD_SYS_CALL;
+	header.cmdSts = CMD_STS_RESPONSE;
+	if (!strcmp(notice,PGR_QUERY_ABORTED_NOTICE_CMD))
+	{
+		header.cmdType = CMD_TYPE_FRONTEND_CLOSED;
+	}
+	header.query_size = htonl(strlen(notice));
+	status = send_replicate_packet(ReplicationServer_Info.PGR_Sock_To_Replication_Server,&header,(char *)notice);
+	return status;
+}
+
+void
+PGR_Notice_Transaction_Query_Done(void)
+{
+	if (PGCluster_Info == NULL)
+	{
+		return;
+	}
+	if (PGCluster_Info->PGR_Need_Notice == true)
+	{
+		send_response_to_replication_server(PGR_QUERY_DONE_NOTICE_CMD);
+	}
+}
+
+void
+PGR_Notice_Transaction_Query_Aborted(void)
+{
+	ClusterDB_Mode_Info.Transaction_Mode = false;
+	ClusterDB_Mode_Info.Session_Authorization_Mode = false;
+	send_response_to_replication_server(PGR_QUERY_ABORTED_NOTICE_CMD);
+}
+
+int
+PGR_Notice_Conflict(void)
+{
+	const char * msg = NULL ;
+	int rtn = STATUS_OK;
+
+	if (PGCluster_Info == NULL)
+		return STATUS_ERROR;
+	msg = PGR_LOCK_CONFLICT_NOTICE_CMD ;
+	if (PGCluster_Info->PGR_Check_Lock.deadlock == true)
+	{
+		msg = PGR_DEADLOCK_DETECT_NOTICE_CMD ;
+	}
+	if (PGCluster_Info->PGR_Check_Lock.dest == TO_FRONTEND)
+	{
+		pq_puttextmessage('C',msg);
+		pq_flush();
+#ifdef CONTROL_LOCK_CONFLICT
+		rtn = wait_lock_answer();
+#endif
+	}
+	else
+	{
+		send_response_to_replication_server(msg);
+#ifdef CONTROL_LOCK_CONFLICT
+		rtn = PGR_Recv_Trigger (PGR_RECV_TIMEOUT);
+#endif
+	}
+	return rtn;
+}
+
+#ifdef CONTROL_LOCK_CONFLICT
+static int
+wait_lock_answer(void)
+{
+	char result[PGR_MESSAGE_BUFSIZE+4];
+	int rtn = 0;
+
+	memset(result,0,sizeof(result));
+	rtn = read_trigger(result, PGR_MESSAGE_BUFSIZE);
+	if (rtn < 0)
+		return STATUS_ERROR;
+	return STATUS_OK;
+}
+
+static int
+read_trigger(char * result, int buf_size)
+{
+	int i = 0;
+	char c;
+	int r = 0;
+
+	if ((result == NULL) || (buf_size <= 0 ))
+	{
+		return EOF;
+	}
+	/*
+	pq_getbytes(result,buf_size);
+	*/
+	while ((r = pq_getbytes(&c,1)) == 0)
+	{
+		if (i < buf_size -1)
+		{
+			*(result + i) = c;
+		}
+		else
+		{
+			break;
+		}
+		if (c == '\0')
+			break;
+		i++;
+	}
+
+	return r;
+}
+#endif
+
+int
+PGR_Recv_Trigger (int user_timeout)
+{
+	char result[PGR_MESSAGE_BUFSIZE];
+	int rtn = 0;
+	int func_no = 0;
+
+	if (PGCluster_Info == NULL)
+		return STATUS_ERROR;
+	if (PGCluster_Info->PGR_Lock_Noticed)
+	{
+		return STATUS_OK;
+	}
+	if (ReplicationServer_Info.PGR_Sock_To_Replication_Server < 0)
+		return STATUS_ERROR;
+	memset(result,0,sizeof(result));
+	rtn = recv_replicate_result(ReplicationServer_Info.PGR_Sock_To_Replication_Server,result,user_timeout);
+	if (rtn > 0)
+	{
+		func_no = atoi(result);
+		if (func_no  <= 0)
+		{
+			func_no = STATUS_OK;
+		}
+		return func_no;
+	}
+	else 
+	{
+		if (user_timeout == 0)
+		{
+			PGR_Set_Replication_Server_Status(ReplicationServer_Info.CurrentReplicateServer, DATA_ERR);
+		}
+		return STATUS_ERROR;
+	}
+	return STATUS_OK;
+}
+
+bool
+PGR_Set_Transaction_Mode(bool mode,const char * commandTag)
+{
+	if (commandTag == NULL)
+	{
+		return mode;
+	}
+	if (autocommit == false)
+	{
+		return true;
+	}
+	if (mode == false)
+	{
+		if ((!strcmp(commandTag,"BEGIN")) ||
+			(!strcmp(commandTag,"START TRANSACTION")) )
+		{
+			return true;
+		}
+	}
+	if (mode == true)
+	{
+		if ((!strcmp(commandTag,"COMMIT")) ||
+			(!strcmp(commandTag,"ROLLBACK")))
+		{
+			return false;
+		}
+	}
+	return mode;
+}
+
+
+static bool
+is_transaction_command(const char * commandTag)
+{
+	if (commandTag == NULL)
+	{
+		return false;
+	}
+	if ((!strcmp(commandTag,"BEGIN")) ||
+		(!strcmp(commandTag,"START TRANSACTION")))
+	{
+		return true;
+	}
+	else
+	{
+		return false;
+	}
+}
+
+static bool
+do_not_replication_command(const char * commandTag)
+{
+	if (commandTag == NULL)
+	{
+		return true;
+	}
+	if ((!strcmp(commandTag,"SELECT")) ||
+		(!strcmp(commandTag,"CLOSE CURSOR")) ||
+		(!strcmp(commandTag,"MOVE")) ||
+		(!strcmp(commandTag,"FETCH")) ||
+		(!strcmp(commandTag,"SHOW")) ||
+		(!strcmp(commandTag,"REINDEX")) ||
+		(!strcmp(commandTag,"ANALYZE")) ||
+		(!strcmp(commandTag,"VACUUM")) ||
+		(!strcmp(commandTag,"EXPLAIN")))
+	{
+		return true;
+	}
+	else
+	{
+		return false;
+	}
+}
+
+bool
+PGR_Check_DeadLock(
+	LOCKMETHODTABLE *lockMethodTable,
+	LOCKMODE lockmode,
+	LOCK *lock,
+	PROCLOCK *holder)
+{
+	PROC_QUEUE *waitQueue = &(lock->waitProcs);
+	int			myHeldLocks = MyProc->heldLocks;
+	bool		early_deadlock = false;
+	PGPROC	   *proc;
+	int			i;
+
+	if (myHeldLocks != 0)
+	{
+		proc = (PGPROC *) MAKE_PTR(waitQueue->links.next);
+		for (i = 0; i < waitQueue->size; i++)
+		{
+			/* Must he wait for me? */
+			if (lockMethodTable->conflictTab[proc->waitLockMode] & myHeldLocks)
+			{
+				/* Must I wait for him ? */
+				if (lockMethodTable->conflictTab[lockmode] & proc->heldLocks)
+				{
+					early_deadlock = true;
+					return true;;
+				}
+			}
+			/* Nope, so advance to next waiter */
+			proc = (PGPROC *) MAKE_PTR(proc->links.next);
+		}
+	}
+	else
+	{
+		/* I hold no locks, so I can't push in front of anyone. */
+		proc = (PGPROC *) &(waitQueue->links);
+	}
+
+	/*
+	 * Insert self into queue, ahead of the given proc (or at tail of
+	 * queue).
+	 */
+	SHMQueueInsertBefore(&(proc->links), &(MyProc->links));
+	waitQueue->size++;
+
+	lock->waitMask |= (1 << lockmode);
+
+	/* Set up wait information in PGPROC object, too */
+	MyProc->waitLock = lock;
+	MyProc->waitHolder = holder;
+	MyProc->waitLockMode = lockmode;
+
+	MyProc->errType = STATUS_OK;	/* initialize result for success */
+
+	return false;
+}
+
+void
+PGR_Set_Replication_Server_Status( ReplicateServerInfo * sp, int status)
+{
+	if (sp == NULL)
+	{
+		return;
+	}
+	if (sp->useFlag != status)
+	{
+		sp->useFlag = status;
+	}
+}
+
+int
+PGR_Is_Skip_Replication(const char * query)
+{
+	char skip_2[256];
+
+	if ((query == NULL) ||
+		(MyProcPort == NULL))
+	{
+		return -1;
+	}
+	sprintf(skip_2,SKIP_QUERY_2,MyProcPort->user_name);
+	if ((strncmp(query,SKIP_QUERY_1,strlen(SKIP_QUERY_1)) == 0) ||
+		(strncmp(query,skip_2,strlen(skip_2)) == 0))
+	{
+		return 3;
+	}
+	if ((strncmp(query,SKIP_QUERY_3,strlen(SKIP_QUERY_3)) == 0) ||
+		(strncmp(query,SKIP_QUERY_4,strlen(SKIP_QUERY_4)) == 0))
+	{
+		return 1;
+	}
+	return 0;
+}
+
+bool
+PGR_Did_Commit_Transaction(void)
+{
+	int sock = 0;
+	int cnt = 0;
+	ReplicateHeader header;
+	char * serverName = NULL;
+	int portNumber=0;
+	char * result = NULL;
+	ReplicateServerInfo * sp = NULL;
+	ReplicateServerInfo * base = NULL;
+	int socket_type = 0;
+	char argv[ PGR_CMD_ARG_NUM ][256];
+	int argc = 0;
+	int func_no = 0;
+
+	if ((PGCluster_Info == NULL ) ||
+		(PGCluster_Info->ReplicateCurrentTime == NULL) ||
+		(PGCluster_Info->ReplicateCurrentTime->useFlag != DATA_USE))
+	{
+		return false;
+	}
+	sp = PGR_get_replicate_server_info();
+	if (sp == NULL)
+	{
+		if (Debug_pretty_print)
+			elog(DEBUG1,"PGR_get_replicate_server_info get error");
+		return false;
+	}
+	sock = get_replicate_server_socket( sp , PGR_QUERY_SOCKET);
+	if (sock < 0)
+	{
+		if (Debug_pretty_print)
+			elog(DEBUG1,"get_replicate_server_socket fail");
+		return false;
+	}
+	serverName = sp->hostName;
+	portNumber = (int)sp->portNumber;
+	header.cmdSys = CMD_SYS_CALL;
+	header.cmdSts = CMD_STS_TRANSACTION_ABORT;
+	header.cmdType = CMD_TYPE_COMMIT_CONFIRM;
+	header.port = htons(PostPortNumber);
+	header.pid = htons(getpid());
+	header.tv.tv_sec = htonl(PGCluster_Info->ReplicateCurrentTime->tp.tv_sec);
+	header.tv.tv_usec = htonl(PGCluster_Info->ReplicateCurrentTime->tp.tv_usec);
+	header.query_size = htonl(0); 
+	strncpy(header.dbName ,(char *)(MyProcPort->database_name),sizeof(header.dbName));
+	strncpy(header.userName , (char *)(MyProcPort->user_name),sizeof(header.userName));
+	gethostname(header.from_host,sizeof(header.from_host));
+	header.replicate_id = htonl(ReplicationLog_Info.PGR_Replicate_ID);
+	header.request_id = 0;
+	base = sp;
+	ReplicationServer_Info.PGR_Sock_To_Replication_Server = sock;
+	result = (char *)malloc(PGR_MESSAGE_BUFSIZE);
+	if (result == (char *)NULL)
+	{
+		return false;
+	}
+	memset(result,0,PGR_MESSAGE_BUFSIZE);
+retry_send_confirm_packet:
+
+	cnt = 0;
+	while (send_replicate_packet(sock,&header,"") != STATUS_OK)
+	{
+		if (cnt > MAX_RETRY_TIMES )
+		{
+			sock = get_new_replication_socket( base, sp, socket_type);
+			if (sock < 0)
+			{
+				if (Debug_pretty_print)
+					elog(DEBUG1,"all replication servers may be down");
+				PGCluster_Info->PGR_Stand_Alone->is_stand_alone = true;
+				free(result);
+				result = NULL;
+				return false;
+			}
+			ReplicationServer_Info.PGR_Sock_To_Replication_Server = sock;
+			cnt = 0;
+		}
+		cnt ++;
+	}
+
+	if (recv_replicate_result(sock,result,0) < 0)
+	{
+		/* replication server should be down */
+		sock = get_new_replication_socket( base, sp, socket_type);
+		if (sock < 0)
+		{
+			if (Debug_pretty_print)
+				elog(DEBUG1,"all replication servers may be down");
+			PGCluster_Info->PGR_Stand_Alone->is_stand_alone = true;
+			free(result);
+			result = NULL;
+			return false;
+		}
+		ReplicationServer_Info.PGR_Sock_To_Replication_Server = sock;
+		goto retry_send_confirm_packet;
+	}
+	/* read answer */
+	argc = set_command_args(argv,result);
+	if (argc >= 1)
+	{
+		func_no = atoi(argv[0]);
+		if (func_no == PGR_TRANSACTION_CONFIRM_ANSWER_FUNC_NO)
+		{
+			/* the transaction was commited in other server */
+			if (atoi(argv[1]) == PGR_ALREADY_COMMITTED)
+			{
+				free(result);
+				result = NULL;
+				return true;
+			}
+		}
+	}
+	free(result);
+	result = NULL;
+	return false;
+}
+
+#if 0
+static bool
+confirm_query_done(int sock, ReplicateHeader * header, char *result)
+{
+	char argv[ PGR_CMD_ARG_NUM ][256];
+	int argc = 0;
+	int func_no = 0;
+	int status = 0;
+
+	header->cmdSys = CMD_SYS_CALL;
+	header->cmdSts = CMD_STS_QUERY_SUSPEND;
+	header->cmdType = CMD_TYPE_QUERY_CONFIRM;
+	if (send_replicate_packet(sock,header,"") != STATUS_OK)
+	{
+		return false;
+	}
+	if (recv_replicate_result(sock,result,0) <= 0)
+	{
+		return false;
+	}
+	/* read answer */
+	argc = set_command_args(argv,result);
+	if (argc >= 2)
+	{
+		func_no = atoi(argv[0]);
+		status = atoi(argv[1]);
+		if ((func_no == PGR_QUERY_CONFIRM_ANSWER_FUNC_NO) &&
+			(status == PGR_ALREADY_COMMITTED))
+		{
+			/* the query was done in other server */
+			return true;
+		}
+	}
+	return false;
+}
+#endif
+
+static char *
+get_hostName(char * str)
+{
+	char * top = NULL;
+	char * p = NULL;
+
+	p = str;
+	while ( *p != '\0')
+	{
+		if (*p == '\'')
+		{
+			*p = '\0';
+			p++;
+			if (top == NULL)
+			{
+				top = p;
+			}
+		}
+		p++;
+	}
+	return top;
+}
+
+static unsigned int
+get_next_request_id(void)
+{
+	if (ReplicationLog_Info.PGR_Request_ID +1 < PGR_MAX_COUNTER)
+	{
+		ReplicationLog_Info.PGR_Request_ID ++;
+	}
+	else
+	{
+		ReplicationLog_Info.PGR_Request_ID = 0;
+	}
+	return ReplicationLog_Info.PGR_Request_ID ;
+		
+}
+
+static bool
+is_this_query_replicated(char * id)
+{
+	uint32_t replicate_id = 0;
+	uint32_t saved_id = 0;
+	uint32_t comp_id = 0;
+	uint32_t saved_over_flow_flag = 0;
+	uint32_t comp_over_flow_flag = 0;
+	ReplicateServerInfo * replicate_server_info = NULL;
+
+	if (id == NULL)
+	{
+		return false;
+	}
+	replicate_id = atol(id);
+	comp_id = (replicate_id & PGR_GET_DATA_FILTER);
+	comp_over_flow_flag = (replicate_id & PGR_GET_OVER_FLOW_FILTER);
+
+	if (ReplicationServer_Info.CurrentReplicateServer == NULL)
+	{
+		PGR_get_replicate_server_info();
+	}
+	if (ReplicationServer_Info.CurrentReplicateServer != NULL)
+	{
+		replicate_server_info = ReplicationServer_Info.CurrentReplicateServer;
+	}
+	else if (ReplicationServer_Info.LastReplicateServer != NULL)
+	{
+		replicate_server_info = ReplicationServer_Info.LastReplicateServer;
+	}
+	if (replicate_server_info != NULL)
+	{
+		saved_id = (ReplicationServer_Info.CurrentReplicateServer->replicate_id & PGR_GET_DATA_FILTER);
+		saved_over_flow_flag = (ReplicationServer_Info.CurrentReplicateServer->replicate_id & PGR_GET_OVER_FLOW_FILTER);
+		if (saved_over_flow_flag == comp_over_flow_flag)
+		{
+			if ( saved_id < comp_id)
+			{
+				return false;
+			}
+		}
+		else
+		{
+			if ( saved_id > comp_id)
+			{
+				return false;
+			}
+		}
+		return true;
+	}
+	else
+	{
+		return false;
+	}
+}
+
+char *
+PGR_Remove_Comment(const char * str)
+{
+	char * p = NULL;
+	p = (char *)str;
+	while( *p != '\0')
+	{
+		while(isspace(*p))
+		{
+			p++;
+		}
+		if ((!memcmp(p,"--",2)) ||
+			(!memcmp(p,"//",2)))
+		{
+			while((*p != '\n') && (*p != '\0'))
+			{
+				p++;
+			}
+			continue;
+		}
+		break;
+	}
+	return p;
+}
+
+void
+PGR_Force_Replicate_Query(void)
+{
+	if (PGCluster_Info == NULL)
+	{
+		return;
+	}
+	if (PGCluster_Info->PGR_Retry_Query.useFlag == DATA_USE)
+	{
+		PGR_Send_Replicate_Command(PGCluster_Info->PGR_Retry_Query.query_string,
+			PGCluster_Info->PGR_Retry_Query.query_len,
+			PGCluster_Info->PGR_Retry_Query.cmdSts,
+			PGCluster_Info->PGR_Retry_Query.cmdType);
+	}
+}
+
+void
+PGR_Notice_DeadLock(void)
+{
+	ReplicateHeader header;
+
+	if (PGCluster_Info == NULL)
+	{
+		return;
+	}
+
+	memset(&header,0,sizeof(ReplicateHeader));
+	header.cmdSys = CMD_SYS_CALL;
+	header.cmdSts = CMD_STS_NOTICE;
+	header.cmdType = CMD_TYPE_DEADLOCK_DETECT;
+	header.query_size = 0;
+	send_replicate_packet(ReplicationServer_Info.PGR_Sock_To_Replication_Server,&header,(char *)NULL);
+}
+
+void
+PGR_Set_Cluster_Status(int status)
+{
+	if (PGCluster_Info == NULL)
+	{
+		return;
+	}
+	if (ClusterDB_Info.ClusterDBData != NULL)
+	{
+		if (ClusterDB_Info.ClusterDBData->status != status)
+		{
+			ClusterDB_Info.ClusterDBData->status = status;
+		}
+	}
+}
+
+int
+PGR_Get_Cluster_Status(void)
+{
+	if (PGCluster_Info == NULL)
+	{
+		return 0;
+	}
+	if (ClusterDB_Info.ClusterDBData != NULL)
+	{
+		return (ClusterDB_Info.ClusterDBData->status);
+	}
+	return 0;
+}
+
+static int
+return_current_oid(void)
+{
+	char msg[PGR_MESSAGE_BUFSIZE];
+
+	LWLockAcquire(OidGenLock, LW_EXCLUSIVE);
+
+	if (ShmemVariableCache->nextOid < ((Oid) BootstrapObjectIdData))
+	{
+		ShmemVariableCache->nextOid = BootstrapObjectIdData;
+		ShmemVariableCache->oidCount = 0;
+	}
+
+	if (ShmemVariableCache->oidCount == 0)
+	{
+		XLogPutNextOid(ShmemVariableCache->nextOid + VAR_OID_PREFETCH);
+		ShmemVariableCache->oidCount = VAR_OID_PREFETCH;
+	}
+
+	memset(msg,0,sizeof(msg));
+	snprintf(msg, sizeof(msg), "%u", ShmemVariableCache->nextOid);
+	if ((PGCluster_Info != NULL) &&
+		(PGCluster_Info->PGR_Check_Lock.dest == TO_FRONTEND))
+	{
+		pq_puttextmessage('C',msg);
+		pq_flush();
+	}
+	else
+	{
+		send_response_to_replication_server(msg);
+	}
+	return STATUS_OK;
+}
+
+static int
+sync_oid(char * oid)
+{
+	uint32_t next_oid = 0;
+	int offset = 0;
+	char msg[PGR_MESSAGE_BUFSIZE];
+
+	next_oid =  strtoul(oid, NULL, 10);
+	if (next_oid <= 0)
+		return STATUS_ERROR;
+	next_oid ++;
+	offset = next_oid - ShmemVariableCache->nextOid ;
+	if (offset <= 0)
+		return STATUS_ERROR;
+
+	if (next_oid < BootstrapObjectIdData)
+	{
+		ShmemVariableCache->nextOid = BootstrapObjectIdData;
+		ShmemVariableCache->oidCount = 0;
+	}
+
+	/* If we run out of logged for use oids then we must log more */
+	while (ShmemVariableCache->oidCount - offset <= 0)
+	{
+		offset -= (ShmemVariableCache->oidCount) ;
+		(ShmemVariableCache->nextOid) += (ShmemVariableCache->oidCount);
+		XLogPutNextOid(ShmemVariableCache->nextOid + VAR_OID_PREFETCH);
+		ShmemVariableCache->oidCount = VAR_OID_PREFETCH;
+	}
+
+	(ShmemVariableCache->nextOid) += offset;
+	(ShmemVariableCache->oidCount) -= offset;
+	
+	LWLockRelease(OidGenLock);
+
+	memset(msg,0,sizeof(msg));
+	snprintf(msg, sizeof(msg), "%u", ShmemVariableCache->nextOid);
+	if (PGCluster_Info->PGR_Check_Lock.dest == TO_FRONTEND)
+	{
+		pq_puttextmessage('C',msg);
+		pq_flush();
+	}
+	else
+	{
+		send_response_to_replication_server(msg);
+	}
+	return STATUS_OK;
+}
+
+int
+PGR_lo_create(int flags)
+{
+	char * result = NULL;
+	LOArgs lo_args;
+	
+	if ((PGCluster_Info == NULL)	||
+		(PGCluster_Info->PGR_Is_Replicated_Query == true) ||
+		(PGCluster_Info->PGR_Retry_Query.cmdSts != CMD_STS_TRANSACTION))
+	{
+		return STATUS_OK;
+	}
+	memset(&lo_args, 0, sizeof(LOArgs));
+	lo_args.arg1 = htonl(flags);
+
+	result = PGR_Send_Replicate_Command((char *)&lo_args,
+		sizeof(LOArgs),
+		CMD_STS_LARGE_OBJECT,
+		CMD_TYPE_LO_CREATE);
+
+	if (result != NULL)
+	{
+		free(result);
+		return STATUS_OK;
+	}
+	
+	return STATUS_ERROR;
+}
+
+int
+PGR_lo_open(Oid lobjId,int32 mode)
+{
+	char * result = NULL;
+	LOArgs lo_args;
+	
+	if ((PGCluster_Info == NULL)	||
+		(PGCluster_Info->PGR_Is_Replicated_Query == true) ||
+		(PGCluster_Info->PGR_Retry_Query.cmdSts != CMD_STS_TRANSACTION))
+	{
+		return STATUS_OK;
+	}
+	memset(&lo_args, 0, sizeof(LOArgs));
+	lo_args.arg1 = htonl((uint32_t)lobjId);
+	lo_args.arg2 = htonl((uint32_t)mode);
+
+	result = PGR_Send_Replicate_Command((char *)&lo_args,
+		sizeof(LOArgs),
+		CMD_STS_LARGE_OBJECT,
+		CMD_TYPE_LO_OPEN);
+	
+	if (result != NULL)
+	{
+		free(result);
+		return STATUS_OK;
+	}
+	
+	return STATUS_ERROR;
+}
+
+int
+PGR_lo_close(int32 fd)
+{
+	char * result = NULL;
+	LOArgs lo_args;
+	
+	if ((PGCluster_Info == NULL)	||
+		(PGCluster_Info->PGR_Is_Replicated_Query == true) ||
+		(PGCluster_Info->PGR_Retry_Query.cmdSts != CMD_STS_TRANSACTION))
+	{
+		return STATUS_OK;
+	}
+	memset(&lo_args, 0, sizeof(LOArgs));
+	lo_args.arg1 = htonl((uint32_t)fd);
+
+	result = PGR_Send_Replicate_Command((char *)&lo_args,
+		sizeof(LOArgs),
+		CMD_STS_LARGE_OBJECT,
+		CMD_TYPE_LO_CLOSE);
+
+	if (result != NULL)
+	{
+		free(result);
+		return STATUS_OK;
+	}
+	
+	return STATUS_ERROR;
+}
+
+int
+PGR_lo_write(int fd, char *buf, int len)
+{
+	char * result = NULL;
+	LOArgs *lo_args = NULL;
+	int buf_size = 0;
+	
+	if ((PGCluster_Info == NULL)	||
+		(PGCluster_Info->PGR_Is_Replicated_Query == true) ||
+		(PGCluster_Info->PGR_Retry_Query.cmdSts != CMD_STS_TRANSACTION))
+	{
+		return STATUS_OK;
+	}
+	buf_size = sizeof(LOArgs) + len;
+	lo_args = malloc(buf_size + 4);
+	if (lo_args == (LOArgs *)NULL)
+	{
+		return STATUS_ERROR;
+	}
+	memset(lo_args, 0, buf_size + 4);
+	lo_args->arg1 = htonl((uint32_t)fd);
+	lo_args->arg2 = htonl((uint32_t)len);
+	memcpy(lo_args->buf, buf, len);
+	result = PGR_Send_Replicate_Command((char *)lo_args,
+		buf_size,
+		CMD_STS_LARGE_OBJECT,
+		CMD_TYPE_LO_WRITE);
+
+	free(lo_args);
+	if (result != NULL)
+	{
+		free(result);
+		return STATUS_OK;
+	}
+	
+	return STATUS_ERROR;
+}
+
+int
+PGR_lo_lseek(int32 fd, int32 offset, int32 whence)
+{
+	char * result = NULL;
+	LOArgs lo_args;
+	
+	if ((PGCluster_Info == NULL)	||
+		(PGCluster_Info->PGR_Is_Replicated_Query == true) ||
+		(PGCluster_Info->PGR_Retry_Query.cmdSts != CMD_STS_TRANSACTION))
+	{
+		return STATUS_OK;
+	}
+	memset(&lo_args, 0, sizeof(LOArgs));
+	lo_args.arg1 = htonl((uint32_t)fd);
+	lo_args.arg2 = htonl((uint32_t)offset);
+	lo_args.arg3 = htonl((uint32_t)whence);
+
+	result = PGR_Send_Replicate_Command((char *)&lo_args,
+		sizeof(LOArgs),
+		CMD_STS_LARGE_OBJECT,
+		CMD_TYPE_LO_LSEEK);
+
+	if (result != NULL)
+	{
+		free(result);
+		return STATUS_OK;
+	}
+	
+	return STATUS_ERROR;
+}
+
+int
+PGR_lo_unlink(Oid lobjId)
+{
+	char * result = NULL;
+	LOArgs lo_args;
+	
+	if ((PGCluster_Info == NULL)	||
+		(PGCluster_Info->PGR_Is_Replicated_Query == true) ||
+		(PGCluster_Info->PGR_Retry_Query.cmdSts != CMD_STS_TRANSACTION))
+	{
+		return STATUS_OK;
+	}
+	memset(&lo_args, 0, sizeof(LOArgs));
+	lo_args.arg1 = htonl((uint32_t)lobjId);
+
+	result = PGR_Send_Replicate_Command((char *)&lo_args,
+		sizeof(LOArgs),
+		CMD_STS_LARGE_OBJECT,
+		CMD_TYPE_LO_UNLINK);
+
+	if (result != NULL)
+	{
+		free(result);
+		return STATUS_OK;
+	}
+	
+	return STATUS_ERROR;
+}
+
+void
+PGR_init_replication(const char * query, int len)
+{
+	if (PGCluster_Info == NULL)
+	{
+		return;
+	}
+	QueryString_Info.Skip_Cnt = 0;
+	QueryString_Info.PGR_Status = STATUS_OK;
+	QueryString_Info.Transaction_Aborted = false;
+	QueryString_Info.Query_Ptr = query;
+
+	ClusterDB_Mode_Info.PGR_Reliable_Mode_Wait = false;
+	if (PGCluster_Info == NULL)
+		return;
+	if (PGCluster_Info->PGR_Is_Replicated_Query == false)
+	{
+		PGCluster_Info->PGR_Is_Replicated_Query = PGR_Is_Replicated_Command(QueryString_Info.Query_Ptr);
+	}
+	PGCluster_Info->PGR_Retry_Query.query_string = query;
+	PGCluster_Info->PGR_Retry_Query.query_len = len;
+	PGCluster_Info->PGR_Retry_Query.cmdType = CMD_TYPE_OTHER;
+}
+
+void
+PGR_init_each_query(void)
+{
+	if (PGCluster_Info == NULL)
+	{
+		return;
+	}
+
+	QueryString_Info.PGR_Not_Replication_Query = false;
+	ClusterDB_Mode_Info.PGR_Reliable_Mode_Wait = false;
+
+	PGCluster_Info->PGR_Retry_Query.query_string = NULL;
+	PGCluster_Info->PGR_Retry_Query.query_len = 0;
+	PGCluster_Info->PGR_Retry_Query.cmdSts = CMD_STS_OTHER;
+	PGCluster_Info->PGR_Retry_Query.cmdType = CMD_TYPE_OTHER;
+	PGCluster_Info->PGR_Retry_Query.useFlag = DATA_INIT;
+
+	PGCluster_Info->PGR_Lock_Noticed = false;
+}
+
+int
+PGR_exec_replication(const char * commandTag,CommandDest dest)
+{
+	char *null_ptr = NULL;
+	int status = STATUS_OK;
+
+	if (PGCluster_Info == NULL)
+	{
+		return STATUS_OK;
+	}
+	QueryString_Info.Query_Ptr = PGR_Remove_Comment(QueryString_Info.Query_Ptr);
+	PGCluster_Info->PGR_Check_Lock.dest = TO_FRONTEND;
+	PGCluster_Info->PGR_Need_Notice = false;
+	PGCluster_Info->PGR_Check_Lock.check_lock_conflict = false;
+	if (QueryString_Info.Skip_Cnt == 0)
+	{
+		QueryString_Info.Skip_Cnt = PGR_Is_Skip_Replication(QueryString_Info.Query_Ptr);
+	}
+	null_ptr = PGR_scan_terminate (QueryString_Info.Query_Ptr);
+	if(null_ptr != NULL)
+	{
+		*null_ptr = '\0';
+	}
+	if ((PGCluster_Info->PGR_Is_Replicated_Query ) ||
+		(QueryString_Info.Skip_Cnt != 0))
+	{
+		if (QueryString_Info.Skip_Cnt > 0)
+		{
+			QueryString_Info.Skip_Cnt --;
+		}
+		else
+		{
+			QueryString_Info.Skip_Cnt = 0;
+		}
+		ClusterDB_Mode_Info.Transaction_Mode = PGR_Set_Transaction_Mode(ClusterDB_Mode_Info.Transaction_Mode,commandTag);
+		ClusterDB_Mode_Info.PGR_Copy_Data_Need_Replicate = false;
+		if (!strcmp(commandTag,"SELECT"))
+		{
+			if (PGR_Is_System_Command(QueryString_Info.Query_Ptr))
+			{
+				status = PGR_Call_System_Command((char *)QueryString_Info.Query_Ptr);
+				if (status == STATUS_SKIP_QUERY)
+				{
+					pq_puttextmessage('C',PGR_ALREADY_REPLICATED_NOTICE_CMD);
+					pq_flush();
+					return status;
+				}
+				else
+				{
+					return STATUS_CONTINUE;
+				}
+			}
+		}
+		PGCluster_Info->PGR_Check_Lock.status_lock_conflict = STATUS_OK;
+		PGCluster_Info->PGR_Check_Lock.dest = TO_FRONTEND;
+	}
+	else
+	{
+retry_replication:
+		ClusterDB_Mode_Info.PGR_Copy_Data_Need_Replicate = false;
+
+		/* check cluster db status */
+		if ((PGR_Get_Cluster_Status() == STATUS_RECOVERY)	&&
+			(QueryString_Info.PGR_Not_Replication_Query == false)			&&
+			(ClusterDB_Mode_Info.Transaction_Mode == false ) )
+		{
+			elog(WARNING, "This query is not permitted while recovery db ");
+			if(null_ptr != NULL)
+			{
+				*null_ptr = ';';
+				QueryString_Info.Query_Ptr = null_ptr +1;
+			}
+			return STATUS_CONTINUE;
+		}
+		if (PGR_Is_Stand_Alone() == true)
+		{
+			if (PGCluster_Info->PGR_Stand_Alone->permit == PERMIT_READ_ONLY)
+			{
+				if (QueryString_Info.PGR_Not_Replication_Query == false)
+				{
+					elog(ERROR, "This query is not permitted when all replication servers fell down ");
+					if(null_ptr != NULL)
+					{
+						*null_ptr = ';';
+						QueryString_Info.Query_Ptr = null_ptr +1;
+					}
+					return STATUS_CONTINUE;
+				}
+			}
+		}
+		else if ((QueryString_Info.PGR_Not_Replication_Query == false ) ||
+			(!strcmp(commandTag,"SELECT")))
+		{
+			QueryString_Info.PGR_Status = PGR_replication(QueryString_Info.Query_Ptr,dest,commandTag);
+			if (QueryString_Info.PGR_Status == STATUS_REPLICATED)
+			{
+				CommandCounterIncrement();
+				return STATUS_CONTINUE;
+			}
+			else if (QueryString_Info.PGR_Status == STATUS_ERROR)
+			{
+				goto retry_replication;
+			}
+			else if (QueryString_Info.PGR_Status == STATUS_DEADLOCK_DETECT)
+			{
+				PGCluster_Info->PGR_Need_Notice = false;
+				elog(ERROR, "postmaster deadlock detected");
+				return STATUS_CONTINUE;
+			}
+			else if (QueryString_Info.PGR_Status == STATUS_REPLICATION_ABORT)
+			{
+				PGCluster_Info->PGR_Need_Notice = false;
+				elog(ERROR, "replication server should be down, transaction aborted.");
+				return STATUS_CONTINUE;
+			}
+			else if (QueryString_Info.PGR_Status != STATUS_CONTINUE)
+			{
+				PGCluster_Info->PGR_Check_Lock.dest = TO_FRONTEND;
+			}
+			else
+			{
+				PGCluster_Info->PGR_Check_Lock.dest = TO_REPLICATION_SERVER;
+				ClusterDB_Mode_Info.PGR_Reliable_Mode_Wait = true;
+			}
+		}
+	}
+	if(null_ptr != NULL)
+	{
+		*null_ptr = ';';
+		QueryString_Info.Query_Ptr = null_ptr +1;
+	}
+	if (!PGCluster_Info->PGR_Is_Replicated_Query )
+	{
+		if ((!strcmp(commandTag,"BEGIN")) ||
+			(!strcmp(commandTag, "START TRANSACTION")) ||
+			(ClusterDB_Mode_Info.Transaction_Mode == false ) )
+		{
+			PGR_Reload_Start_Time();
+		}
+	}
+	if ((ClusterDB_Mode_Info.Transaction_Mode == true)            ||
+		(ClusterDB_Mode_Info.Create_Temp_Table_Mode == true)      ||
+		(ClusterDB_Mode_Info.Session_Authorization_Mode == true)  ||
+		(!strcmp(commandTag,"COPY")))
+	{
+		PGCluster_Info->PGR_Need_Notice = true;
+		PGCluster_Info->PGR_Check_Lock.check_lock_conflict = true;
+	}
+	else
+	{
+		if (QueryString_Info.PGR_Not_Replication_Query == false)
+		{
+			PGCluster_Info->PGR_Need_Notice = true;
+			PGCluster_Info->PGR_Check_Lock.check_lock_conflict = true;
+		}
+		else
+		{
+			if ((PGCluster_Info->PGR_Is_Replicated_Query ) &&
+			(!strcmp(commandTag,"SELECT")))
+			{
+				PGCluster_Info->PGR_Need_Notice = true;
+				PGCluster_Info->PGR_Check_Lock.check_lock_conflict = true;
+			}
+		}
+	}
+	return STATUS_OK;
+}
+
+int PGR_startup_lifecheck(void)
+{
+	if (PGCluster_Info == NULL) 
+	{
+		return STATUS_OK;
+	}
+
+	Lifecheck_Pid_Info.Master_Pid = PGR_Master_Main();
+	if (Lifecheck_Pid_Info.Master_Pid < 0)
+	{
+		elog(DEBUG1,"PGR_Master_Main failed");
+		return STATUS_ERROR;
+	}
+	if (PGCluster_Info == NULL)
+	{
+		return STATUS_ERROR;
+	}
+	if (PGCluster_Info->PGR_Recovery_Option)
+	{
+		PGR_recovery_finish_send();
+		PGCluster_Info->PGR_Recovery_Option = false;
+	}
+	/* life check process start */
+	Lifecheck_Pid_Info.SYN_Pid = PGR_SYN_Main(SYN_TO_REPLICATION_SERVER, (void *)ReplicationServer_Info.ReplicateServerData);
+	if (Lifecheck_Pid_Info.SYN_Pid < 0)
+	{
+		elog(DEBUG1,"PGR_SYN_Main failed");
+		return STATUS_ERROR;
+	}
+	Lifecheck_Pid_Info.ACK_Pid = PGR_ACK_Main(PGCluster_Info->Com_Info.ConfData_Info.LifeCheck_Port_Number);
+	if (Lifecheck_Pid_Info.ACK_Pid < 0)
+	{
+		elog(DEBUG1,"PGR_ACK_Main failed");
+		return STATUS_ERROR;
+	}
+	return STATUS_OK;
+}
+
+void PGR_finish_lifecheck(int sig)
+{
+	int status = 0;
+
+	if (PGCluster_Info == NULL)
+	{
+		return ;
+	}
+
+	if (PGCluster_Info->PGR_Recovery_Option)
+	{
+		PGR_recovery_error_send();
+		PGCluster_Info->PGR_Recovery_Option = false;
+	}
+	if (Lifecheck_Pid_Info.Master_Pid > 0)
+	{
+		kill (Lifecheck_Pid_Info.Master_Pid,sig);
+		waitpid(Lifecheck_Pid_Info.Master_Pid,&status,WNOHANG);
+	}
+	if (Lifecheck_Pid_Info.SYN_Pid > 0)
+	{
+		kill (Lifecheck_Pid_Info.SYN_Pid,sig);
+		waitpid(Lifecheck_Pid_Info.SYN_Pid,&status,WNOHANG);
+	}
+	if (Lifecheck_Pid_Info.ACK_Pid > 0)
+	{
+		kill (Lifecheck_Pid_Info.ACK_Pid,sig);
+		waitpid(Lifecheck_Pid_Info.ACK_Pid,&status,WNOHANG);
+	}
+	PGR_delete_shm();
+}
+
+int PGR_Wait_Reliable_Trigger(const char * commandTag)
+{
+	int status = STATUS_OK;
+
+	if (PGCluster_Info == NULL)
+	{
+		return status;
+	}
+	if (ReplicationServer_Info.CurrentReplicateServer != NULL)
+	{
+		if ((PGCluster_Info != NULL) &&
+			(!PGCluster_Info->PGR_Is_Replicated_Query )				&&
+			(PGCluster_Info->PGR_Check_Lock.dest != TO_FRONTEND)	&&
+			(ClusterDB_Mode_Info.PGR_Reliable_Mode_Wait == true)		&&
+			(strcmp(commandTag,"COPY"))				&&
+			(ReplicationServer_Info.CurrentReplicateServer->response_mode == PGR_RELIABLE_MODE))
+		{
+			status = PGR_Recv_Trigger(PGR_RECV_TIMEOUT);
+		}
+	}
+	return status;
+}
+
+void 
+PGR_Set_Replication_Flag(Node * parsetree)
+{
+	if (PGCluster_Info == NULL)
+	{
+		return;
+	}
+	QueryString_Info.PGR_Not_Replication_Query = false;
+	switch (nodeTag(parsetree))
+	{
+		case T_SelectStmt:
+		case T_ClosePortalStmt:
+		case T_FetchStmt:
+		case T_VacuumStmt:
+		case T_ExplainStmt:
+		case T_VariableShowStmt:
+		case T_CheckPointStmt:
+			QueryString_Info.PGR_Not_Replication_Query = true;
+			break;
+		default:
+			QueryString_Info.PGR_Not_Replication_Query = false;
+			break;
+	}
+}
+
+static void
+init_ClusterDB_Mode_Info(PGR_ClusterDB_Mode_Info * p)
+{
+	if (p != (PGR_ClusterDB_Mode_Info *)NULL)
+	{
+		p->Transaction_Mode = false;
+		p->Session_Authorization_Mode = false;
+		p->Create_Temp_Table_Mode = false;
+		p->PGR_Copy_Data_Need_Replicate = false;
+		p->PGR_Reliable_Mode_Wait = false;
+	}
+}
+
+
+int
+PGR_Init_PGCluster_Info(void)
+{
+	/*
+	if (PGCluster_Info == NULL)
+	{
+		return STATUS_OK;
+	}
+	*/
+	PGCluster_Info = (PGR_PGCluster_Info *)malloc(sizeof(PGR_PGCluster_Info));
+	if (PGCluster_Info == (PGR_PGCluster_Info *)NULL)
+	{
+		return STATUS_ERROR;
+	}
+	memset(PGCluster_Info, 0, sizeof(PGR_PGCluster_Info));
+	PGR_Init_Com_Info(&(PGCluster_Info->Com_Info));
+	init_ClusterDB_Mode_Info(&ClusterDB_Mode_Info);
+
+	PGCluster_Info->RsyncPath = NULL;
+	PGCluster_Info->RsyncOption = NULL;
+	PGCluster_Info->PGR_Recovery_Option= false;
+
+	PGCluster_Info->PGRCopyData = malloc(sizeof(CopyData));
+	if (PGCluster_Info->PGRCopyData == (CopyData *)NULL)
+	{
+		return STATUS_ERROR;
+	}
+	PGCluster_Info->PGRCopyData->cnt = 0;	
+	memset(PGCluster_Info->PGRCopyData->copy_data,0,COPYBUFSIZ);
+
+	PGCluster_Info->PGR_Retry_Query.query_string = NULL;
+	PGCluster_Info->PGR_Retry_Query.query_len = 0;
+	PGCluster_Info->PGR_Retry_Query.cmdSts = 0;
+	PGCluster_Info->PGR_Retry_Query.cmdType = 0;
+	PGCluster_Info->PGR_Retry_Query.useFlag = DATA_END;
+
+	PGCluster_Info->PGR_Stand_Alone = (PGR_Stand_Alone_Type *)malloc(sizeof(PGR_Stand_Alone_Type));
+	if (PGCluster_Info->PGR_Stand_Alone == (PGR_Stand_Alone_Type *)NULL)
+	{
+		return STATUS_ERROR;
+	}
+	PGCluster_Info->PGR_Stand_Alone->is_stand_alone = false;
+	PGCluster_Info->PGR_Stand_Alone->permit = PERMIT_READ_ONLY;
+	PGCluster_Info->PGR_Is_Replicated_Query = false;
+
+	PGCluster_Info->PGR_Need_Notice = false;
+	PGCluster_Info->PGR_Lock_Noticed = false;
+	PGCluster_Info->PGR_Check_Lock.check_lock_conflict = false;
+	PGCluster_Info->PGR_Check_Lock.deadlock = false;
+	PGCluster_Info->PGR_Check_Lock.status_lock_conflict = STATUS_OK;
+	PGCluster_Info->PGR_Check_Lock.dest = 0;
+
+	return STATUS_OK;
+}
+
+int
+PGR_Get_Cluster_Conf_Data(char * path)
+{
+	if (PGCluster_Info == NULL) 
+	{
+		return STATUS_OK;
+	}
+	if (PGR_Get_Conf_Data( path, CLUSTER_CONF_FILE ) == STATUS_OK)
+	{
+		if (PGCluster_Info == (PGR_PGCluster_Info *)NULL)
+		{
+			return STATUS_ERROR;
+		}
+		PGR_Init_Replicate_Server_Data(path);
+		PGR_Set_Replicate_Server_Socket();
+		PGR_Free_Conf_Data();
+		if (PGCluster_Info->PGR_Recovery_Option)
+		{
+			fprintf(stderr,"Start in recovery mode! \n");
+			fprintf(stderr,"Please wait until a data synchronization finishes from Master DB... \n");
+			if (PGR_Recovery_Main() != STATUS_OK)
+			{
+				return STATUS_ERROR;
+			}
+		}
+		return STATUS_OK;
+	}
+	else
+	{
+		return STATUS_ERROR;
+	}
+}
+
+void
+PGR_Clear_Children(int sig)
+{
+	int status = 0;
+
+	if (PGCluster_Info == NULL)
+	{
+		return;
+	}
+	if (PGCluster_Info->PGR_Recovery_Option)
+	{
+		PGR_recovery_error_send();
+		PGCluster_Info->PGR_Recovery_Option = false;
+	}
+	if (Lifecheck_Pid_Info.Master_Pid > 0)
+	{
+		kill (Lifecheck_Pid_Info.Master_Pid,sig);
+		waitpid(Lifecheck_Pid_Info.Master_Pid,&status,WNOHANG);
+	}
+	if (Lifecheck_Pid_Info.SYN_Pid > 0)
+	{
+		kill (Lifecheck_Pid_Info.SYN_Pid,sig);
+		waitpid(Lifecheck_Pid_Info.SYN_Pid,&status,WNOHANG);
+	}
+	if (Lifecheck_Pid_Info.ACK_Pid > 0)
+	{
+		kill (Lifecheck_Pid_Info.ACK_Pid,sig);
+		waitpid(Lifecheck_Pid_Info.ACK_Pid,&status,WNOHANG);
+	}
+	PGR_delete_shm();
+}
+
+void
+PGR_Recovery_Failed(void)
+{
+	if (PGCluster_Info == NULL)
+	{
+		return;
+	}
+	if (PGCluster_Info->PGR_Recovery_Option)
+	{
+		PGR_recovery_error_send();
+		PGCluster_Info->PGR_Recovery_Option = false;
+	}
+	PGR_delete_shm();
+}
+
+void
+PGR_Elog_Abort_Copy(void)
+{
+	if (PGCluster_Info == NULL)
+	{
+		return;
+	}
+	if (ClusterDB_Mode_Info.PGR_Copy_Data_Need_Replicate)
+	{
+		PGR_Set_Copy_Data(PGCluster_Info->PGRCopyData,NULL,0,1);
+		ClusterDB_Mode_Info.PGR_Copy_Data_Need_Replicate = false;
+	}
+}
+
+void
+PGR_Elog_Abort_Proc(int timeout)
+{
+	if (PGCluster_Info == NULL)
+	{
+		return;
+	}
+	if (ReplicationServer_Info.CurrentReplicateServer != NULL)
+	{
+		if (PGCluster_Info->PGR_Need_Notice == true)
+		{
+			PGR_Notice_Transaction_Query_Aborted();
+		}
+		if (ClusterDB_Mode_Info.PGR_Copy_Data_Need_Replicate)
+		{
+			PGR_Set_Copy_Data(PGCluster_Info->PGRCopyData,NULL,0,1);
+		}
+		else
+		{
+			if ((! PGCluster_Info->PGR_Is_Replicated_Query ) &&
+				(PGCluster_Info->PGR_Check_Lock.dest != TO_FRONTEND) &&
+				(ClusterDB_Mode_Info.PGR_Reliable_Mode_Wait == true) &&
+				(ReplicationServer_Info.CurrentReplicateServer->response_mode == PGR_RELIABLE_MODE))
+			{
+				PGR_Recv_Trigger(0);
+			}
+		}
+	}
+	if (ReplicationServer_Info.TransactionSock != -1)
+	{
+		close (ReplicationServer_Info.TransactionSock);
+		ReplicationServer_Info.TransactionSock = -1;
+	}
+}
+
+void
+PGR_Elog_Warn_Proc(char * msg, char * fix)
+{
+	if (PGCluster_Info == NULL)
+	{
+		return;
+	}
+	if ((strstr(msg,"parse error") != NULL) ||
+		(strstr(msg,"syntax error") != NULL))
+	{
+		if ((PGCluster_Info->PGR_Check_Lock.dest != TO_FRONTEND) &&
+			(ClusterDB_Mode_Info.Transaction_Mode == true))
+		{
+			PGR_Force_Replicate_Query();
+		}
+	}
+	PGR_Notice_Transaction_Query_Done();
+	if (ClusterDB_Mode_Info.PGR_Copy_Data_Need_Replicate)
+	{
+		PGR_Set_Copy_Data(PGCluster_Info->PGRCopyData,NULL,0,1);
+	}
+}
+
+void
+PGR_ExceptionalCondition(void)
+{
+	if (PGCluster_Info == NULL)
+	{
+		return;
+	}
+	if ((PGCluster_Info->PGR_Check_Lock.dest == TO_REPLICATION_SERVER ) &&
+		(PGCluster_Info->PGR_Need_Notice == true))
+	{
+		PGR_Notice_Transaction_Query_Aborted();
+	}
+	if (ClusterDB_Mode_Info.PGR_Copy_Data_Need_Replicate)
+	{
+		PGR_Set_Copy_Data(PGCluster_Info->PGRCopyData,NULL,0,1);
+	}
+}
+
+bool
+PGR_Is_This_Transaction_Committed(void)
+{
+	if (PGCluster_Info == NULL)
+	{
+		return false;
+	}
+	if ((ClusterDB_Mode_Info.Transaction_Mode == true)  &&
+		(PGR_Did_Commit_Transaction() == true))
+	{
+		return true;
+	}
+	return false;
+}
+
+void
+PGR_Set_Copy_Char(int ch)
+{
+	if (PGCluster_Info == NULL)
+	{
+		return;
+	}
+	if (ch != EOF)
+	{
+		PGR_Set_Copy_Data(PGCluster_Info->PGRCopyData,(char *)&ch,1,0);
+	}
+	else
+	{
+		PGR_Set_Copy_Data(PGCluster_Info->PGRCopyData,NULL,0,1);
+	}
+}
+#endif /* USE_REPLICATION */
diff -ruN postgresql-7.4.13-old/src/bin/initdb/initdb.sh postgresql-7.4.13/src/bin/initdb/initdb.sh
--- postgresql-7.4.13-old/src/bin/initdb/initdb.sh	2004-05-05 18:09:56.000000000 +0200
+++ postgresql-7.4.13/src/bin/initdb/initdb.sh	2006-08-05 16:53:43.000000000 +0200
@@ -415,6 +415,8 @@
 PG_HBA_SAMPLE="$datadir"/pg_hba.conf.sample
 PG_IDENT_SAMPLE="$datadir"/pg_ident.conf.sample
 POSTGRESQL_CONF_SAMPLE="$datadir"/postgresql.conf.sample
+# ADD REPLICATE
+CLUSTER_CONF_SAMPLE="$datadir"/cluster.conf.sample
 
 if [ "$show_setting" = yes ] || [ "$debug" = yes ]
 then
@@ -424,7 +426,7 @@
     for var in PGDATA datadir PGPATH ENCODING ENCODINGID \
         POSTGRES_SUPERUSERNAME POSTGRES_BKI \
         POSTGRES_DESCR POSTGRESQL_CONF_SAMPLE \
-	PG_HBA_SAMPLE PG_IDENT_SAMPLE ; do
+	PG_HBA_SAMPLE PG_IDENT_SAMPLE CLUSTER_CONF_SAMPLE ; do
         eval "echo '  '$var=\$$var"
     done
   ) 1>&2
@@ -435,7 +437,8 @@
 fi
 
 for PREREQ_FILE in "$POSTGRES_BKI" "$POSTGRES_DESCR" \
-    "$PG_HBA_SAMPLE" "$PG_IDENT_SAMPLE" "$POSTGRESQL_CONF_SAMPLE"
+    "$PG_HBA_SAMPLE" "$PG_IDENT_SAMPLE" "$POSTGRESQL_CONF_SAMPLE" \
+	"$CLUSTER_CONF_SAMPLE"
 do
     if [ ! -f "$PREREQ_FILE" ] ; then
       (
@@ -607,9 +610,11 @@
         "$PG_HBA_SAMPLE" > "$PGDATA"/pg_hba.conf       || exit_nicely
 fi
 cp "$PG_IDENT_SAMPLE" "$PGDATA"/pg_ident.conf          || exit_nicely
+# ADD REPLICATE
+cp "$CLUSTER_CONF_SAMPLE" "$PGDATA"/cluster.conf       || exit_nicely
 
 chmod 0600 "$PGDATA"/pg_hba.conf "$PGDATA"/pg_ident.conf \
-	"$PGDATA"/postgresql.conf
+	"$PGDATA"/postgresql.conf "$PGDATA"/cluster.conf
 
 echo "ok"
 
diff -ruN postgresql-7.4.13-old/src/include/replicate.h postgresql-7.4.13/src/include/replicate.h
--- postgresql-7.4.13-old/src/include/replicate.h	1970-01-01 01:00:00.000000000 +0100
+++ postgresql-7.4.13/src/include/replicate.h	2006-08-05 16:53:43.000000000 +0200
@@ -0,0 +1,248 @@
+/*-------------------------------------------------------------------------
+ *
+ * replicate.h
+ *	  Primary include file for replicate server .c files
+ *
+ * This should be the first file included by replicate modules.
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef REPLICATE_H
+#define	REPLICATE_H
+
+#ifndef _SYS_TIME_H
+#include <sys/time.h>
+#endif
+#include "tcop/dest.h"
+#include "storage/proc.h"
+#include "replicate_com.h"
+
+#define STAND_ALONE_TAG "When_Stand_Alone"
+#define NOT_REPLICATE_INFO_TAG "Not_Replicate_Info"
+#define DB_NAME_TAG	"DB_Name"
+#define TABLE_NAME_TAG "Table_Name"
+
+#define CLUSTER_CONF_FILE	"cluster.conf"
+#define	NOT_SESSION_AUTHORIZATION	(0)
+#define SESSION_AUTHORIZATION_BEGIN	(1)
+#define SESSION_AUTHORIZATION_END	(2)
+
+#define CLUSTER_ERROR_LOG_FILE	"pgcluster.log"
+#define CLUSTER_STATUS_LOG_FILE	"pgcluster.sts"
+#define READ_ONLY_IF_STAND_ALONE	"read_only"
+#define READ_WRITE_IF_STAND_ALONE	"read_write"
+#define PERMIT_READ_ONLY		(1)
+#define PERMIT_READ_WRITE		(2)
+#define STATUS_REPLICATED		(3)
+#define STATUS_CONTINUE			(4)
+#define STATUS_CONTINUE_SELECT	(5)
+#define STATUS_NOT_REPLICATE	(6)
+#define STATUS_SKIP_QUERY		(7)
+#define STATUS_REPLICATE		(10)
+#define STATUS_RECOVERY			(11)
+#define STATUS_REPLICATION_ABORT	(98)
+#define STATUS_DEADLOCK_DETECT	(99)
+
+#define TO_REPLICATION_SERVER	(0)
+#define TO_FRONTEND				(1)
+
+#define PGR_DEADLOCK_DETECTION_MSG "deadlock detected!"
+#define PGR_REPLICATION_ABORT_MSG "replication aborted!"
+#define SKIP_QUERY_1 "begin; select getdatabaseencoding(); commit"
+#define SKIP_QUERY_2 "BEGIN; SELECT usesuper FROM pg_catalog.pg_user WHERE usename = '%s'; COMMIT"
+#define SKIP_QUERY_3 "SET autocommit TO 'on'"
+#define SKIP_QUERY_4 "SET search_path = public"
+
+#define PGR_SEND_RETRY_CNT (1500)
+#define PGR_SEND_WAIT_MSEC (150)
+#define PGR_RECV_RETRY_CNT (1500)
+#define PGR_RECV_WAIT_MSEC (150)
+#define PGR_SEND_TIMEOUT	(600)
+#define PGR_RECV_TIMEOUT	(30)
+#define PGR_LOCK_RETRY_CNT (50)
+#define PGR_LOCK_WAIT_MSEC (20)
+
+#define PGR_1ST_RECOVERY (1)
+#define PGR_2ND_RECOVERY (2)
+
+typedef struct CopyDataType
+{
+	int cnt;
+	char copy_data[COPYBUFSIZ];
+} CopyData;
+
+typedef struct
+{
+	bool is_stand_alone;
+	int  permit;
+} PGR_Stand_Alone_Type;
+
+typedef struct
+{
+	char db_name[DBNAME_MAX_LENGTH];
+	char table_name[TABLENAME_MAX_LENGTH];
+} PGR_Not_Replicate_Type;
+
+typedef struct
+{
+	bool check_lock_conflict;
+	bool deadlock;
+	int status_lock_conflict;
+	int dest;
+} PGR_Check_Lock_Type;
+
+typedef struct
+{
+	const char * query_string;
+	int query_len;
+	char cmdSts;
+	char cmdType;
+	char useFlag;
+} PGR_Retry_Query_Type;
+
+/* cluster db data */
+typedef struct {
+	char * PGRSelfHostName;
+	ClusterDBInfo * ClusterDBData;
+	int ReplicateServerShmid;
+	int ClusterDBShmid;
+} PGR_ClusterDB_Info;
+
+/* partial replication data */
+typedef struct {
+	int PGR_Not_Replicate_Rec_Num;
+	PGR_Not_Replicate_Type * PGR_Not_Replicate;
+} PGR_Partial_Info;
+
+/* query string data */
+typedef struct {
+	const char * Query_String;
+	const char * Query_Ptr;
+	int Skip_Cnt;
+	int PGR_Status;
+	bool Transaction_Aborted;
+	bool PGR_Not_Replication_Query;
+} PGR_QueryString_Info;
+
+/*life check process pid */
+typedef struct {
+	pid_t Master_Pid;
+	pid_t SYN_Pid;
+	pid_t ACK_Pid;
+} PGR_Lifecheck_Pid_Info;
+
+/* cluster db mode */
+typedef struct {
+	bool Transaction_Mode;
+	bool Session_Authorization_Mode;
+	bool Create_Temp_Table_Mode;
+	bool PGR_Copy_Data_Need_Replicate;
+	bool PGR_Reliable_Mode_Wait;
+} PGR_ClusterDB_Mode_Info;
+
+/* replication server data */
+typedef struct {
+	ReplicateServerInfo * ReplicateServerData;
+	ReplicateServerInfo * CurrentReplicateServer;
+	ReplicateServerInfo * LastReplicateServer;
+	unsigned long * PGR_Current_Replication_Id;
+	int TransactionSock;
+	int PGR_Sock_To_Replication_Server;
+} PGR_ReplicationServer_Info;
+
+/* replicaition log */
+typedef struct {
+	uint32_t PGR_Replicate_ID;
+	uint32_t PGR_Request_ID;
+} PGR_ReplicationLog_Info;
+
+/* Cluster DB global */
+typedef struct {
+	/* common data */
+	PGR_Com_Info Com_Info;
+	/* recovery option data */
+	char * RsyncPath;
+	char * RsyncOption;
+	bool PGR_Recovery_Option;
+	/* query buffer */
+	CopyData * PGRCopyData;
+	PGR_Retry_Query_Type PGR_Retry_Query;
+	/* status flag */
+	PGR_Stand_Alone_Type * PGR_Stand_Alone;
+	bool PGR_Is_Replicated_Query;
+	/* check & notice lock conflict */
+	bool PGR_Need_Notice;
+	bool PGR_Lock_Noticed;
+	PGR_Check_Lock_Type PGR_Check_Lock;
+	/* sync data */
+	ReplicateNow * ReplicateCurrentTime;
+} PGR_PGCluster_Info;
+
+extern PGR_PGCluster_Info *PGCluster_Info;
+
+/* in backend/utiles/pgcluster/replicate.c */
+extern int PGR_Init_Replicate_Server_Data(char * path);
+extern int PGR_Set_Replicate_Server_Socket(void);
+extern char * PGR_Send_Replicate_Command(const char * query_string, int query_len, char cmdSts ,char cmdType);
+extern bool PGR_Is_Replicated_Command(const char * query);
+extern int Xlog_Check_Replicate(int operation);
+extern int PGR_Replicate_Function_Call(void);
+extern void PGR_delete_shm(void);
+extern ReplicateServerInfo * PGR_get_replicate_server_info(void);
+extern bool PGR_Is_System_Command(const char * query);
+extern int PGR_Call_System_Command(char * command);
+extern int PGR_GetTimeOfDay(struct timeval *tp, struct timezone *tpz);
+extern long PGR_Random(void);
+extern int PGR_Set_Current_Time(char * sec, char * usec);
+extern int PGR_Send_Copy(CopyData * copy,int end);
+extern CopyData * PGR_Set_Copy_Data(CopyData * copy, char * str, int len, int end);
+extern char * PGR_scan_terminate(const char * str);
+extern bool PGR_Is_Stand_Alone(void);
+extern void PGR_Send_Message_To_Frontend(char * msg);
+extern void PGR_Notice_Transaction_Query_Done(void);
+extern void PGR_Notice_Transaction_Query_Aborted(void);
+extern int PGR_Notice_Conflict(void);
+extern int PGR_Recv_Trigger (int user_timeout);
+extern bool PGR_Check_DeadLock(LOCKMETHODTABLE *lockMethodTable, LOCKMODE lockmode, LOCK *lock, PROCLOCK *holder);
+extern void PGR_Set_Replication_Server_Status( ReplicateServerInfo * sp, int status);
+extern int PGR_Is_Skip_Replication(const char * query);
+extern bool PGR_Did_Commit_Transaction(void);
+extern bool PGR_Set_Transaction_Mode(bool mode,const char * commandTag);
+extern char * PGR_Remove_Comment(const char * str);
+extern void PGR_Force_Replicate_Query(void);
+extern void PGR_Notice_DeadLock(void);
+extern void PGR_Set_Cluster_Status(int status);
+extern int PGR_Get_Cluster_Status(void);
+extern int PGR_lo_create(int flags);
+extern int PGR_lo_open(Oid lobjId,int32 mode);
+extern int PGR_lo_close(int32 fd);
+extern int PGR_lo_write(int fd, char *buf, int len);
+extern int PGR_lo_lseek(int32 fd, int32 offset, int32 whence);
+extern int PGR_lo_unlink(Oid lobjId);
+extern void PGR_init_replication(const char * query, int len);
+extern void PGR_init_each_query(void);
+extern int PGR_exec_replication(const char * commandTag,CommandDest dest);
+extern int PGR_startup_lifecheck(void);
+extern void PGR_finish_lifecheck(int sig);
+extern int PGR_Wait_Reliable_Trigger(const char * commandTag);
+extern void PGR_Set_Replication_Flag(Node * parsetree);
+extern int PGR_Init_PGCluster_Info(void);
+extern int PGR_Get_Cluster_Conf_Data(char * path);
+extern void PGR_Clear_Children(int sig);
+extern void PGR_Recovery_Failed(void);
+extern void PGR_Elog_Abort_Copy(void);
+extern void PGR_Elog_Abort_Proc(int timeout);
+extern void PGR_Elog_Warn_Proc(char * msg, char * fix);
+extern void PGR_ExceptionalCondition(void);
+extern bool PGR_Is_This_Transaction_Committed(void);
+extern void PGR_Set_Copy_Char(int ch);
+
+/* in backend/utiles/pgcluster/recovery.c */
+extern int PGR_Master_Main(void);
+extern int PGR_Recovery_Main(void);
+extern int PGR_recovery_error_send(void);
+extern int PGR_recovery_finish_send(void);
+
+/* in backend/access/transam/xact.c */
+extern void PGR_Reload_Start_Time(void);
+#endif /* REPLICATE_H */
diff -ruN postgresql-7.4.13-old/src/include/replicate_com.h postgresql-7.4.13/src/include/replicate_com.h
--- postgresql-7.4.13-old/src/include/replicate_com.h	1970-01-01 01:00:00.000000000 +0100
+++ postgresql-7.4.13/src/include/replicate_com.h	2006-08-05 16:53:43.000000000 +0200
@@ -0,0 +1,494 @@
+/*-------------------------------------------------------------------------
+ *
+ * replicate.h
+ *	  Primary include file for replicate server .c files
+ *
+ * This should be the first file included by replicate modules.
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef REPLICATE_COM_H
+#define	REPLICATE_COM_H 1
+
+#ifndef _SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifndef _INTTYPES_H
+#include <inttypes.h>
+#endif
+#ifndef _NETINET_IN_H
+#include <netinet/in.h>
+#endif
+
+/* default values */
+#define DEFAULT_PGLB_PORT	(6001)
+#define DEFAULT_PGLB_RECOVERY_PORT	(6101)
+#define DEFAULT_PGLB_LIFECHECK_PORT	(6201)
+#define DEFAULT_CLUSTER_PORT	(5432)
+#define DEFAULT_CLUSTER_RECOVERY_PORT	(7101)
+#define DEFAULT_CLUSTER_LIFECHECK_PORT	(7201)
+#define DEFAULT_PGRP_PORT	(8001)
+#define DEFAULT_PGRP_RECOVERY_PORT	(8101)
+#define DEFAULT_PGRP_LIFECHECK_PORT	(8201)
+#define DEFAULT_PGRP_RLOG_PORT	(8301)
+#define MAX_DB_SERVER	(32)
+/**************************
+*                         *
+*   Packet ID definition  *
+*                         *
+***************************/
+/*=========================
+	Replication packet id
+===========================*/
+#define	CMD_SYS_REPLICATE	'R'
+/*-------------------------
+	Simple Query
+--------------------------*/
+#define CMD_STS_SET_SESSION_AUTHORIZATION	'S'
+#define	CMD_STS_TRANSACTION	'T'
+#define	CMD_STS_TEMP_TABLE	'E'
+#define	CMD_STS_QUERY	'Q'
+#define	CMD_STS_OTHER	'O'
+
+#define CMD_TYPE_VACUUM	'V'
+#define CMD_TYPE_ANALYZE	'A'
+#define CMD_TYPE_REINDEX	'N'
+#define CMD_TYPE_SELECT	'S'
+#define CMD_TYPE_EXPLAIN	'X'
+#define CMD_TYPE_SET	'T'
+#define CMD_TYPE_RESET	't'
+#define CMD_TYPE_INSERT	'I'
+#define CMD_TYPE_DELETE	'D'
+#define CMD_TYPE_EXECUTE	'U'
+#define CMD_TYPE_UPDATE	'U'
+#define CMD_TYPE_BEGIN	'B'
+#define CMD_TYPE_COMMIT	'E'
+#define CMD_TYPE_ROLLBACK	'R'
+#define CMD_TYPE_SESSION_AUTHORIZATION_BEGIN	'a'
+#define CMD_TYPE_SESSION_AUTHORIZATION_END	'b'
+#define CMD_TYPE_OTHER	'O'
+
+/*----------------------------
+	Copy Command
+------------------------------*/
+#define	CMD_STS_COPY	'C'
+
+#define CMD_TYPE_COPY	'C'
+#define CMD_TYPE_COPY_DATA	'd'
+#define CMD_TYPE_COPY_DATA_END	'e'
+
+/*----------------------------
+	Large Object
+------------------------------*/
+#define	CMD_STS_LARGE_OBJECT	'L'
+
+#define CMD_TYPE_LO_CREATE	'C'
+#define CMD_TYPE_LO_OPEN	'O'
+#define CMD_TYPE_LO_WRITE	'W'
+#define CMD_TYPE_LO_LSEEK	'S'
+#define CMD_TYPE_LO_CLOSE	'X'
+#define CMD_TYPE_LO_UNLINK	'U'
+
+/*=========================
+	System call packet id
+===========================*/
+#define CMD_SYS_CALL		'S'
+
+#define	CMD_STS_NOTICE	'N'
+#define	CMD_STS_RESPONSE	'R'
+#define	CMD_STS_TRANSACTION_ABORT	'A'
+#define	CMD_STS_QUERY_SUSPEND	'P'
+#define	CMD_STS_QUERY_DONE	'D'
+
+#define CMD_TYPE_COMMIT_CONFIRM	'c'
+#define CMD_TYPE_QUERY_CONFIRM	'q'
+#define CMD_TYPE_DEADLOCK_DETECT	'd'
+#define CMD_TYPE_FRONTEND_CLOSED	'x'
+
+#define PGR_TRANSACTION_SOCKET	(0)
+#define PGR_QUERY_SOCKET	(1)
+
+#define	DATA_FREE	(0)
+#define	DATA_INIT	(1)
+#define	DATA_USE	(2)
+#define	DATA_STOP	(3)
+#define	DATA_TOP	(10)
+#define	DATA_END	(11)
+#define	DATA_TEMP_USE	(13)
+#define	DATA_NEW	(14)
+#define	DATA_ACCEPT	(20)
+#define	DATA_ERR_NOTICE	(98)
+#define	DATA_ERR	(99)
+#define HOSTNAME_MAX_LENGTH     (128)
+#define DBNAME_MAX_LENGTH       (128)
+#define USERNAME_MAX_LENGTH     (128)
+#define TABLENAME_MAX_LENGTH     (128)
+#define PATH_MAX_LENGTH        (256)
+#define MAX_SERVER_NUM         (128)
+#define MAX_RETRY_TIMES	(3)
+#define MAX_SOCKET_QUEUE	(10000)
+#define TRANSACTION_ERROR_RESULT	"TRANSACTION_ERROR"
+#define REPLICATE_SERVER_SHM_KEY (1020)
+/* target -> replicate */
+#define RECOVERY_PREPARE_REQ	(1)
+/* replicate  -> master */
+#define RECOVERY_PGDATA_REQ	(2)
+/* master -> replicate */
+#define RECOVERY_PGDATA_ANS	(3)
+/* replicate -> target */
+#define RECOVERY_PREPARE_ANS	(4)
+/* target -> replicate */
+#define RECOVERY_START_REQ	(5)
+/* replicate  -> master */
+#define RECOVERY_FSYNC_REQ	(6)
+/* master -> replicate */
+#define RECOVERY_FSYNC_ANS	(7)
+/* replicate -> target */
+#define RECOVERY_START_ANS	(8)
+/* target -> replicate */
+#define RECOVERY_FINISH	(9)
+#define RECOVERY_ERROR_OCCUPIED	(100)
+#define RECOVERY_ERROR_CONNECTION	(101)
+#define RECOVERY_ERROR_ANS	(200)
+#define REPLICATION_SERVER_INFO_TAG "Replicate_Server_Info"
+#define HOST_NAME_TAG	"Host_Name"
+#define PORT_TAG	"Port"
+#define RECOVERY_PORT_TAG	"Recovery_Port"
+#define LIFECHECK_PORT_TAG  "LifeCheck_Port"
+#define RSYNC_PATH_TAG	"Rsync_Path"
+#define RSYNC_OPTION_TAG	"Rsync_Option"
+#define STATUS_LOG_FILE_TAG	"Status_Log_File"
+#define ERROR_LOG_FILE_TAG	"Error_Log_File"
+#define RECOVERY_INIT	(0)
+#define RECOVERY_PREPARE_START	(1)
+#define RECOVERY_START	(2)
+#define RECOVERY_ERROR	(99)
+
+/* response mode */
+#define PGR_FAST_MODE	(0)
+#define PGR_NORMAL_MODE	(1)
+#define PGR_RELIABLE_MODE	(2)
+
+#define RECOVERY_TIMEOUT	(600)
+#ifndef COMPLETION_TAG_BUFSIZE
+#define	COMPLETION_TAG_BUFSIZE (128)
+#endif
+
+/* replicate log type */
+#define FROM_R_LOG_TYPE	(1)
+#define FROM_C_DB_TYPE	(2)
+#define CONNECTION_SUSPENDED_TYPE	(3)
+
+#define PGR_SYSTEM_COMMAND_FUNC	"PGR_SYSTEM_COMMAND_FUNCTION"
+#define PGR_STARTUP_REPLICATION_SERVER_FUNC_NO	(1)
+#define PGR_CHANGE_REPLICATION_SERVER_FUNC_NO	(2)
+#define PGR_SET_CURRENT_TIME_FUNC_NO	(3)
+#define PGR_NOTICE_DEADLOCK_DETECTION_FUNC_NO	(4)
+#define PGR_TRANSACTION_CONFIRM_ANSWER_FUNC_NO	(5)
+#define PGR_QUERY_CONFIRM_ANSWER_FUNC_NO	(6)
+#define PGR_RELIABLE_MODE_DONE_FUNC_NO		(7)
+#define PGR_NOTICE_ABORT_FUNC_NO		(8)
+#define PGR_GET_OID_FUNC_NO		(9)
+#define PGR_SET_OID_FUNC_NO		(10)
+#define PGR_CMD_ARG_NUM	(10)
+#define PGR_LOCK_CONFLICT_NOTICE_CMD	"PGR_LOCK_CONFLICT_NOTICE_CMD"
+#define PGR_DEADLOCK_DETECT_NOTICE_CMD	"PGR_DEADLOCK_DETECT_NOTICE_CMD"
+#define PGR_QUERY_DONE_NOTICE_CMD		"PGR_QUERY_DONE_NOTICE_CMD"
+#define PGR_QUERY_ABORTED_NOTICE_CMD	"PGR_QUERY_ABORTED_NOTICE_CMD"
+#define PGR_RETRY_LOCK_QUERY_CMD	"PGR_RETRY_LOCK_QUERY_CMD"
+#define PGR_NOT_YET_REPLICATE_NOTICE_CMD	"PGR_NOT_YET_REPLICATE_NOTICE_CMD"
+#define PGR_ALREADY_REPLICATED_NOTICE_CMD	"PGR_ALREADY_REPLICATED_NOTICE_CMD"
+#define PGR_NOT_YET_COMMIT		(0)
+#define PGR_ALREADY_COMMITTED	(1)
+
+#define COPYBUFSIZ	(4096)
+#define MAX_WORDS	(24)
+#define MAX_WORD_LETTERS	(48)
+#define PGR_MESSAGE_BUFSIZE	(256)
+#define INT_LENGTH	(12)
+#define PGR_MAX_COUNTER	(0x0FFFFFFF)
+#define PGR_GET_OVER_FLOW_FILTER	(0xF0000000)
+#define PGR_GET_DATA_FILTER	(0x0FFFFFFF)
+#define PGR_SET_OVER_FLOW	(0x10000000)
+#define PGR_MIN_COUNTER (0x0000000F)
+
+#define STRCMP(x,y)	(strncmp(x,y,strlen(y)))
+
+/* life check target */
+#define SYN_TO_LOAD_BALANCER	(0)
+#define SYN_TO_CLUSTER_DB		(1)
+#define SYN_TO_REPLICATION_SERVER	(2)
+#define LIFE_CHECK_TRY_COUNT	(2)
+#define LIFE_CHECK_STOP		(0)
+#define LIFE_CHECK_START	(1)
+
+#ifndef HAVE_UNION_SEMUN
+union semun {
+	int val;
+	struct semid_ds *buf;
+	unsigned short int *array;
+	struct seminfo *__buf;
+};
+#endif
+
+typedef struct ReplicateHeaderType
+{
+	char cmdSys;	/*
+					R: replication
+					S: system call
+					C: cascade connection
+					L: replication log
+					*/
+	char cmdSts;	/*
+					-- with replication --
+						S: session in set session authorization
+						E: session in temp table
+						C: session in copy
+						L: session in large object
+						T: session in transaction
+						Q: session in simple query
+						O: session in others
+					-- with system call -- 
+						N: notice 
+						R: response 
+						A: transaction abort
+						P: query suspend
+						D: query done
+					-- with cascade connection -- 
+						U: to upper
+						L: to lower
+					-- with replication log -- 
+						q: delete query log
+						t: delete transaction log
+						r: update query log
+						u: update transaction log
+					*/
+	char cmdType;	/*
+					-- with replication --
+						-- session in simple query --
+						V: vacuum
+						A: analyze
+						N: reindex
+						S: select
+						X: explain
+						T: set
+						t: reset
+						I: insert
+						D: delete
+						U: update/execute
+						O: others
+						-- session in transaction --
+						B: begin
+						E: commit/end
+						R: rollback
+						-- session in set session authorization --
+						a: session authorization begin
+						b: session authorization end
+						-- session in copy --
+						C: copy
+						d: copy data
+						e: copy data end
+						-- session in large object --
+						C: create lo
+						O: open lo
+						W: write lo
+						S: lseek lo
+						X: close lo
+						U: unlink lo
+					-- with system call -- 
+						c: confrim commit done
+						q: confrim query done
+						d: detect deadlock
+						x: front end closed
+					-- with cascade connection -- 
+						A: add cascade
+						D: delete cascade
+						F: update all
+					*/
+	char rlog;		/*
+					-- kind of replication log --
+						1: send from replication log
+						2: send from cluster db (should be retry)
+						3: connection suspended
+					*/
+	uint16_t port;
+	uint16_t pid;
+	uint32_t query_size;
+	char from_host[HOSTNAME_MAX_LENGTH];
+	char dbName[DBNAME_MAX_LENGTH];
+	char userName[USERNAME_MAX_LENGTH];
+	struct timeval tv;
+	uint32_t query_id;
+	uint32_t request_id;
+	uint32_t replicate_id;
+} ReplicateHeader;
+
+typedef struct RecoveryPacketType
+{
+	uint16_t packet_no;	/*	
+					1:start recovery prepare
+					2:ask pgdata
+					3:ans pgdata
+					4:send master info
+					5:start queueing query
+					6:requst fsync
+					7:ready to fsync
+					8:pepared master
+					9:finished rsync
+					*/
+	uint16_t max_connect;
+	uint16_t port;
+	uint16_t recoveryPort;
+	char hostName[HOSTNAME_MAX_LENGTH];
+	char pg_data[PATH_MAX_LENGTH]; 
+	char userName[USERNAME_MAX_LENGTH];
+} RecoveryPacket;
+
+typedef struct
+{
+	char table[128];
+	int rec_no;
+	char key[128];
+	char value[128];
+	char * last;
+	char * next;
+} ConfDataType;
+
+typedef struct ReplicateServerInfoType
+{
+	uint32_t useFlag;
+	char hostName[HOSTNAME_MAX_LENGTH];
+	uint16_t portNumber;
+	uint16_t recoveryPortNumber;
+	uint16_t lifecheckPortNumber;
+	uint16_t RLogPortNumber;
+	uint32_t sock;
+	uint32_t rlog_sock;
+	uint32_t replicate_id;
+	uint16_t response_mode;
+} ReplicateServerInfo;
+
+typedef struct ReplicateNowType
+{
+	int useFlag;
+	int use_seed;
+	int use_time;
+	int offset_sec;
+	int offset_usec;
+	struct timeval tp;
+} ReplicateNow;
+
+typedef struct ClusterDBInfoType
+{
+	int status;
+} ClusterDBInfo;
+
+typedef struct
+{
+	uint32_t arg1;
+	uint32_t arg2;
+	uint32_t arg3;
+	char * buf;
+} LOArgs;
+
+/*
+ * cluster server table
+ */
+typedef struct {
+	uint32_t useFlag;
+	char hostName[HOSTNAME_MAX_LENGTH];
+	uint16_t port;
+	uint16_t recoveryPort;
+	uint16_t lifecheckPort;
+	uint32_t hostNum;
+}HostTbl;
+
+/*
+ * host table for recovery request and
+ * load balancer table
+ */
+typedef struct {
+	uint32_t useFlag;
+	char hostName[HOSTNAME_MAX_LENGTH];
+	uint16_t port;
+	uint16_t recoveryPort;
+	uint16_t lifecheckPort;
+	int sock;
+	int recovery_sock;
+} RecoveryTbl;
+
+typedef struct MapTableType
+{
+	uint32_t *useFlag;
+	char *hostName;
+	uint16_t  *port;
+	uint16_t  *lifecheckPort;
+	int sock;
+	int status;
+	int rec_no;
+	pid_t pid;
+} MapTable;
+
+/* for watch dog */
+typedef struct {
+	int SynSemID;
+	int MapTableShmid;
+	int LifeCheckStartShmid;
+	char * LifeCheckStartFlag;
+	MapTable * Map_Table;
+	int LifeCheckTimeOut;
+}PGR_WatchDog_Info;
+
+typedef struct {
+	ConfDataType * ConfData_Top;
+	ConfDataType * ConfData_End;
+	uint16_t LifeCheck_Port_Number;
+	uint16_t Recovery_Port_Number;
+}PGR_ConfData_Info;
+
+/* for logs */
+typedef struct {
+	FILE * StatusFp;
+	FILE * LogFp;
+	char * PGRStatusFileName;
+	char * PGRLogFileName;
+	int Log_Print;
+	int Debug_Print;
+}PGR_Log_Info;
+
+/* PGCluster global */
+typedef struct {
+	PGR_ConfData_Info ConfData_Info;
+	PGR_Log_Info Log_Info;
+}PGR_Com_Info;
+
+/* in backend/libpq/replicate_com.c */
+extern int PGR_Create_Socket_Connect(int * fdP, char * hostName , unsigned short portNumber);
+extern void PGR_Close_Sock(int * sock);
+extern int PGR_Create_Socket_Bind(int * fdP, char * hostName , unsigned short portNumber);
+extern int PGR_Create_Acception(int fd, int * sockP, char * hostName , unsigned short portNumber);
+extern int PGR_Free_Conf_Data(void);
+extern int PGR_Get_Conf_Data(char * dir , char * fname);
+extern void PGRset_recovery_packet_no(RecoveryPacket * packet, int packet_no);
+extern unsigned int PGRget_ip_by_name(char * host);
+extern void PGRsem_unlock( int semid, int sem_num );
+extern void PGRsem_lock( int semid, int sem_num );
+extern void PGRwrite_log_file(FILE * fp, const char * fmt,...);
+extern void show_debug(const char * fmt,...);
+extern void show_error(const char * fmt,...);
+extern void PGR_Init_Com_Info(PGR_Com_Info * com_info);
+
+/* in backend/libpq/watch_dog.c */
+extern int PGRsyn_init(void);
+extern void PGRsyn_quit(void);
+extern int PGRmap_to_cluster_tbl(HostTbl * ptr);
+extern int PGRmap_to_replication_server_tbl(ReplicateServerInfo * ptr);
+extern int PGRmap_to_load_balancer_tbl(RecoveryTbl * ptr);
+extern pid_t PGR_ACK_Main(uint16_t port);
+extern pid_t PGR_SYN_Main(int syn_target, void * status_tbl);
+extern void PGRset_start_life_check(void);
+extern void PGRexit_life_check(int sig);
+extern void PGRquit_lifecheck_child(int sig);
+extern void PGRchild_wait(int sig);
+
+#endif /* REPLICATE_COM_H */
diff -ruN postgresql-7.4.13-old/src/makefiles/Makefile.aix postgresql-7.4.13/src/makefiles/Makefile.aix
--- postgresql-7.4.13-old/src/makefiles/Makefile.aix	2002-10-09 18:21:54.000000000 +0200
+++ postgresql-7.4.13/src/makefiles/Makefile.aix	2006-08-05 16:53:43.000000000 +0200
@@ -31,3 +31,7 @@
 	$(CC) $(LDFLAGS) $(LDFLAGS_SL) -o $@ $*.o -Wl,-bI:$(top_builddir)/src/backend/$(POSTGRES_IMP) -Wl,-bE:$*$(EXPSUFF) $(LIBS)
 
 sqlmansect = 7
+
+# add for pgcluster
+CFLAGS += -pthread
+LDFLAGS += -L/usr/lib/threads
diff -ruN postgresql-7.4.13-old/src/makefiles/Makefile.freebsd postgresql-7.4.13/src/makefiles/Makefile.freebsd
--- postgresql-7.4.13-old/src/makefiles/Makefile.freebsd	2001-08-29 21:14:40.000000000 +0200
+++ postgresql-7.4.13/src/makefiles/Makefile.freebsd	2006-08-05 16:53:43.000000000 +0200
@@ -23,3 +23,6 @@
 endif
 
 sqlmansect = 7
+
+# add for pgcluster
+LIBS += -lc_r
diff -ruN postgresql-7.4.13-old/src/makefiles/Makefile.hpux postgresql-7.4.13/src/makefiles/Makefile.hpux
--- postgresql-7.4.13-old/src/makefiles/Makefile.hpux	2003-05-29 20:08:42.000000000 +0200
+++ postgresql-7.4.13/src/makefiles/Makefile.hpux	2006-08-05 16:53:43.000000000 +0200
@@ -41,3 +41,6 @@
 	$(LD) -b -o $@ $<
 
 sqlmansect = 5
+
+# add for pgcluster
+LIBS += -lpthread
diff -ruN postgresql-7.4.13-old/src/makefiles/Makefile.linux postgresql-7.4.13/src/makefiles/Makefile.linux
--- postgresql-7.4.13-old/src/makefiles/Makefile.linux	2003-06-05 18:07:25.000000000 +0200
+++ postgresql-7.4.13/src/makefiles/Makefile.linux	2006-08-05 16:53:43.000000000 +0200
@@ -15,3 +15,6 @@
 	$(CC) -shared -o $@ $<
 
 sqlmansect = 7
+
+# add for pgcluster
+LIBS += -lpthread
diff -ruN postgresql-7.4.13-old/src/makefiles/Makefile.netbsd postgresql-7.4.13/src/makefiles/Makefile.netbsd
--- postgresql-7.4.13-old/src/makefiles/Makefile.netbsd	2001-08-29 21:14:40.000000000 +0200
+++ postgresql-7.4.13/src/makefiles/Makefile.netbsd	2006-08-05 16:53:43.000000000 +0200
@@ -26,3 +26,6 @@
 endif
 
 sqlmansect = 7
+
+# add for pgcluster
+LIBS += -lpthread
diff -ruN postgresql-7.4.13-old/src/makefiles/Makefile.openbsd postgresql-7.4.13/src/makefiles/Makefile.openbsd
--- postgresql-7.4.13-old/src/makefiles/Makefile.openbsd	2001-08-29 21:14:40.000000000 +0200
+++ postgresql-7.4.13/src/makefiles/Makefile.openbsd	2006-08-05 16:53:43.000000000 +0200
@@ -24,3 +24,6 @@
 endif
 
 sqlmansect = 7
+
+# add for pgcluster
+LIBS += -lc_r
diff -ruN postgresql-7.4.13-old/src/makefiles/Makefile.solaris postgresql-7.4.13/src/makefiles/Makefile.solaris
--- postgresql-7.4.13-old/src/makefiles/Makefile.solaris	2002-09-05 00:54:18.000000000 +0200
+++ postgresql-7.4.13/src/makefiles/Makefile.solaris	2006-08-05 16:53:43.000000000 +0200
@@ -21,3 +21,6 @@
 	$(LD) -G -Bdynamic -o $@ $<
 
 sqlmansect = 5sql
+
+# add for pgcluster
+LIBS += -lpthread
diff -ruN postgresql-7.4.13-old/src/makefiles/Makefile.sunos4 postgresql-7.4.13/src/makefiles/Makefile.sunos4
--- postgresql-7.4.13-old/src/makefiles/Makefile.sunos4	2002-09-05 00:54:18.000000000 +0200
+++ postgresql-7.4.13/src/makefiles/Makefile.sunos4	2006-08-05 16:53:43.000000000 +0200
@@ -11,3 +11,6 @@
 	$(LD) -assert pure-text -Bdynamic -o $@ $<
 
 sqlmansect = 7
+
+# add for pgcluster
+LIBS += -lpthread
diff -ruN postgresql-7.4.13-old/src/pgcluster/Makefile postgresql-7.4.13/src/pgcluster/Makefile
--- postgresql-7.4.13-old/src/pgcluster/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ postgresql-7.4.13/src/pgcluster/Makefile	2006-08-05 16:53:43.000000000 +0200
@@ -0,0 +1,17 @@
+#-------------------------------------------------------------------------
+#
+# Makefile for src/pgcluster (client programs)
+#
+#-------------------------------------------------------------------------
+
+subdir = src/pgcluster
+top_builddir = ../..
+include $(top_builddir)/src/Makefile.global
+
+DIRS := pgrp pglb tool
+
+all install installdirs uninstall depend distprep:
+	@for dir in $(DIRS); do $(MAKE) -C $$dir $@ || exit; done
+
+clean distclean maintainer-clean:
+	-@for dir in $(DIRS); do $(MAKE) -C $$dir $@; done
diff -ruN postgresql-7.4.13-old/src/pgcluster/pglb/AUTHORS postgresql-7.4.13/src/pgcluster/pglb/AUTHORS
--- postgresql-7.4.13-old/src/pgcluster/pglb/AUTHORS	1970-01-01 01:00:00.000000000 +0100
+++ postgresql-7.4.13/src/pgcluster/pglb/AUTHORS	2006-08-05 16:53:43.000000000 +0200
@@ -0,0 +1,3 @@
+Authors of pglb
+
+pglb was written by Atsushi Mitani
diff -ruN postgresql-7.4.13-old/src/pgcluster/pglb/COPYING postgresql-7.4.13/src/pgcluster/pglb/COPYING
--- postgresql-7.4.13-old/src/pgcluster/pglb/COPYING	1970-01-01 01:00:00.000000000 +0100
+++ postgresql-7.4.13/src/pgcluster/pglb/COPYING	2006-08-05 16:53:43.000000000 +0200
@@ -0,0 +1,14 @@
+Copyright (c) 2003	Atsushi Mitani
+
+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.
+
+Portions copyright (c) 2003, Tatsuo Ishii
diff -ruN postgresql-7.4.13-old/src/pgcluster/pglb/Makefile postgresql-7.4.13/src/pgcluster/pglb/Makefile
--- postgresql-7.4.13-old/src/pgcluster/pglb/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ postgresql-7.4.13/src/pgcluster/pglb/Makefile	2006-08-05 16:53:43.000000000 +0200
@@ -0,0 +1,39 @@
+#-------------------------------------------------------------------------
+#
+# Makefile for src/pgcluster/pgrp
+#
+#-------------------------------------------------------------------------
+
+subdir = src/pgcluster/pglb
+top_builddir = ../../..
+include $(top_builddir)/src/Makefile.global
+
+confdir := ${exec_prefix}/etc
+
+OBJS= child.o cluster_table.o load_balance.o main.o pool_auth.o \
+	pool_connection_pool.o pool_process_query.o pool_stream.o \
+	pool_params.o recovery.o socket.o
+
+EXTRA_OBJS = $(top_builddir)/src/backend/libpq/pgcluster.o
+
+override CPPFLAGS := -I$(libpq_srcdir) $(CPPFLAGS) -DBINDIR=\"$(bindir)\" -DPRINT_DEBUG
+
+all: pglb
+
+pglb: $(OBJS) $(libpq_builddir)/libpq.a 
+	$(CC) $(CFLAGS) $(OBJS) $(EXTRA_OBJS) $(libpq) $(LDFLAGS) $(LIBS) -o $@
+
+install: all installdirs
+	$(INSTALL_PROGRAM) pglb$(X) $(DESTDIR)$(bindir)/pglb$(X)
+	$(INSTALL_DATA) pglb.conf.sample $(DESTDIR)$(confdir)/pglb.conf.sample
+
+installdirs:
+	$(mkinstalldirs) $(DESTDIR)$(bindir)
+	$(mkinstalldirs) $(DESTDIR)$(confdir)
+
+uninstall:
+	rm -f $(addprefix $(DESTDIR)$(bindir)/, pglb$(X))
+	rm -f $(DESTDIR)$(confdir)/pglb.conf.sample
+
+clean distclean maintainer-clean:
+	rm -f pglb$(X) $(OBJS) 
diff -ruN postgresql-7.4.13-old/src/pgcluster/pglb/README postgresql-7.4.13/src/pgcluster/pglb/README
--- postgresql-7.4.13-old/src/pgcluster/pglb/README	1970-01-01 01:00:00.000000000 +0100
+++ postgresql-7.4.13/src/pgcluster/pglb/README	2006-08-05 16:53:43.000000000 +0200
@@ -0,0 +1,276 @@
+PGCluster Installation Instructions
+
+=============================================================
+1. Installation
+=============================================================
+
+1-1. Install Cluster DB Server, Replication Server & Load Balancer
+----------------------------------------------------------------
+$ cd $source_dir 
+$ ./configure
+$ gmake
+$ su
+# gmake install
+# chown -R postgres /usr/local/pgsql
+----------------------------------------------------------------
+
+=============================================================
+2. Initialize DB
+=============================================================
+$ su
+# adduser postgres
+# mkdir /usr/local/pgsql/data
+# chown postgres /usr/local/pgsql/data
+# su - postgres
+$ /usr/local/pgsql/bin/initdb -D /usr/local/pgsql/data
+
+
+=============================================================
+3. Configuration
+=============================================================
+(EX.System Composition)
+
+                        |
+             ((Load Balance Server))
+             ( hostname: lb.hoo.com)
+             ( receive port:5432   )
+             ( recovery port:6001  )
+                        |
+----------+-------------+------------+----------
+          |                          |
+ ((  Cluster DB 1    ))    ((  Cluster DB 2    ))
+ ( hostname:c1.hoo.com)    ( hostname:c2.hoo.com)
+ ( receive port: 5432 )    ( receive port:5432  )
+ ( recovery port:7001 )    ( recovery port 7002 )
+          |                          |
+----------+-------------+------------+----------
+                        |
+             ((Replication Server))
+             ( hostname:pgr.hoo.com)
+             ( receive port:8001   )
+             ( recovery port:8101  )
+
+
+3-1. Load Balance Server
+
+The setup file of load balance server is copied from the sample file and edited.
+(the sample file is installed '/usr/local/pgsql/etc' in default)
+----------------------------------------------------------------
+$cd /usr/local/pgsql/etc
+$cp pglb.conf.sample pglb.conf
+----------------------------------------------------------------
+
+In the case of the above system composition example,
+the setup example of pglb.conf file is as the following 
+
+#============================================================
+#          Load Balance Server configuration file
+#-------------------------------------------------------------
+# file: pglb.conf
+#-------------------------------------------------------------
+# This file controls:
+#       o which hosts are db cluster server
+#       o which port  use connect to db cluster server
+#       o how many connections are allowed on each DB server
+#============================================================
+#-------------------------------------------------------------
+# set cluster DB server information
+#		o Host_Name : hostname
+#		o Port : connection for postmaster
+#		o Max_Connection : maximun number of connection to postmaster
+#-------------------------------------------------------------
+<Cluster_Server_Info>
+    <Host_Name>   c1.hoo.com  </Host_Name>
+    <Port>        5432                </Port>
+    <Max_Connect> 32                   </Max_Connect>
+</Cluster_Server_Info>
+<Cluster_Server_Info>
+    <Host_Name>   c2.hoo.com  </Host_Name>
+    <Port>        5432                </Port>
+    <Max_Connect> 32                   </Max_Connect>
+</Cluster_Server_Info>
+#-------------------------------------------------------------
+# set Load Balance server information
+#		o Receive_Port : connection from client
+#		o Recovery_Port : connection for recovery process
+#		o Max_Cluster_Num : maximun number of cluster DB servers
+#		o Use_Connection_Pooling : use connection pool [yes/no] 
+#		o Max_Pool_Each_Server : number of pool connections/DB server
+#-------------------------------------------------------------
+<Receive_Port>    5432                </Receive_Port>
+<Recovery_Port>   6001                </Recovery_Port>
+<Max_Cluster_Num> 128                 </Max_Cluster_Num>
+<Use_Connection_Pooling> yes          </Use_Connection_Pooling>
+<Max_Pool_Each_Server> 1              </Max_Pool_Each_Server>
+
+3-2. Cluster DB Server
+
+The Cluster DB server need edit two configuration files
+('pg_hba.conf' and 'cluster.conf').
+These files are create under the $PG_DATA directory after 'initdb'.
+
+A. pg_hba.conf
+Permission to connect DB via IP connectoins is need for this system.
+
+B. cluster.conf
+In the case of the above system composition example,
+the setup example of cluster.conf file is as the following 
+
+#============================================================
+#          Cluster DB Server configuration file
+#-------------------------------------------------------------
+# file: cluster.conf
+#-------------------------------------------------------------
+# This file controls:
+#       o which hosts & port are replication server
+#       o which port use for replication request to replication server
+#       o which command use for recovery function
+#
+#============================================================
+#-------------------------------------------------------------
+# set cluster DB server information
+#		o Host_Name : hostname
+#		o Port : connection for postmaster
+#		o Recovery_Port : connection for recovery process
+#-------------------------------------------------------------
+<Replicate_Server_Info>
+	<Host_Name> pgr.hoo.com </Host_Name>
+	<Port> 8001 </Port>
+	<Recovery_Port> 8101 </Recovery_Port>
+</Replicate_Server_Info>
+#-------------------------------------------------------------
+# set Cluster DB Server information
+#		o Recovery_Port : connection for recovery
+#		o Rsync_Path : path of rsync command 
+#		o Rsync_Option : file transfer option for rsync
+#       o When_Stand_Alone : When all replication servers fell,
+#                            you can set up two kinds of permittion,
+#                            "real_only" or "read_write".
+#-------------------------------------------------------------
+<Recovery_Port>    7001           </Recovery_Port>
+<Rsync_Path>       /usr/bin/rsync </Rsync_Path>
+<Rsync_Option>     ssh -1         </Rsync_Option>
+<When_Stand_Alone> read_only      </When_Stand_Alone>
+#-------------------------------------------------------------
+# set partitional replicate control information
+#     set DB name and Table name to stop reprication
+#       o DB_Name : DB name
+#       o Table_Name : table name
+#-------------------------------------------------------------
+#<Not_Replicate_Info>
+#    <DB_Name>     test_db      </DB_Name>
+#    <Table_Name>  log_table    </Table_Name>
+#</Not_Replicate_Info>
+
+3-3. Replication Server
+
+The setup file of replication server is copied from the sample file and edited.
+(the sample file is installed '/usr/local/pgsql/etc' in default)
+----------------------------------------------------------------
+$cd /usr/local/pgsql/etc
+$cp pgreplicate.conf.sample pgreplicate.conf
+----------------------------------------------------------------
+In the case of the above system composition example,
+the setup example of pgreplicate.conf file is as the following 
+
+#============================================================
+#                 PGReplicate configuration file
+#-------------------------------------------------------------
+# file: pgreplicate.conf
+#-------------------------------------------------------------
+# This file controls:
+#       o which hosts & port are cluster server
+#       o which port use for replication request from cluster server
+#============================================================
+#-------------------------------------------------------------
+# set cluster DB server information
+#		o Host_Name : hostname
+#		o Port : connection for postmaster
+#		o Recovery_Port : connection for recovery
+#-------------------------------------------------------------
+<Cluster_Server_Info>
+    <Host_Name>      c1.hoo.com    </Host_Name>
+    <Port>           5432          </Port>
+    <Recovery_Port>  7001          </Recovery_Port>
+</Cluster_Server_Info>
+<Cluster_Server_Info>
+    <Host_Name>      c2.hoo.com    </Host_Name>
+    <Port>           5432          </Port>
+    <Recovery_Port>  7001          </Recovery_Port>
+</Cluster_Server_Info>
+#-------------------------------------------------------------
+# set Load Balance server information
+#		o Host_Name : hostname
+#		o Recovery_Port : connection for recovery
+#-------------------------------------------------------------
+<LoadBalance_Server_Info>
+    <Host_Name>       lb.hoo.com   </Host_Name>
+    <Recovery_Port>   6001         </Recovery_Port>
+</LoadBalance_Server_Info>
+#-------------------------------------------------------------
+# set PGReplicate server information
+#		o Replicate_Port : connection for reprication
+#		o Recovery_Port : connection for recovery
+#-------------------------------------------------------------
+<Replication_Port>    8001         </Replication_Port>
+<Recovery_Port>       8101         </Recovery_Port>
+
+
+=============================================================
+4. Start Up / Stop
+=============================================================
+
+4-1. replication server
+
+A. Start replication server
+----------------------------------------------------------------
+$ /usr/local/pgsql/bin/pgreplicate -D /usr/local/pgsql/etc
+----------------------------------------------------------------
+
+B. Stop replication server
+----------------------------------------------------------------
+$ /usr/local/pgsql/bin/pgreplicate -D /usr/local/pgsql/etc stop
+----------------------------------------------------------------
+
+usage: pgreplicate [-D path_of_config_file] [-W path_of_work_files] [-U login us
+er][-l][-n][-v][-h][stop]
+    -l: print error logs in the log file.
+    -n: don't run in daemon mode.
+    -v: debug mode. need '-n' flag
+    -h: print this help
+    stop: stop pgreplicate
+(config file default path: ./pgreplicate.conf)
+
+4-2. cluster DB server
+$PG_HOME = /usr/local/pgsql
+$PG_DATA = /usr/local/pgsql/data
+
+A. Start cluster DB server
+----------------------------------------------------------------
+$ /usr/local/pgsql/bin/pg_ctl -D /usr/local/pgsql/data -o "-i" start
+----------------------------------------------------------------
+
+B. Stop cluster DB server
+----------------------------------------------------------------
+$ /usr/local/pgsql/bin/pg_ctl -D /usr/local/pgsql/data stop
+----------------------------------------------------------------
+
+4-3. load balance server
+
+A. Start load balance server
+----------------------------------------------------------------
+$ /usr/local/pgsql/bin/pglb -D /usr/local/pgsql/etc
+----------------------------------------------------------------
+
+B. Stop load balance server
+----------------------------------------------------------------
+$ /usr/local/pgsql/bin/pglb -D /usr/local/pgsql/etc stop
+----------------------------------------------------------------
+
+usage: pglb [-D path_of_config_file] [-W path_of_work_files] [-n][-v][-h][stop]
+    -l: print error logs in the log file.
+    -n: don't run in daemon mode.
+    -v: debug mode. need '-n' flag
+    -h: print this help
+    stop: stop pglb
+    (config file default path: ./pglb.conf)
diff -ruN postgresql-7.4.13-old/src/pgcluster/pglb/child.c postgresql-7.4.13/src/pgcluster/pglb/child.c
--- postgresql-7.4.13-old/src/pgcluster/pglb/child.c	1970-01-01 01:00:00.000000000 +0100
+++ postgresql-7.4.13/src/pgcluster/pglb/child.c	2006-08-05 16:53:43.000000000 +0200
@@ -0,0 +1,1185 @@
+/*--------------------------------------------------------------------
+ * FILE:
+ *     child.c
+ *
+ * NOTE:
+ *     This file is composed of the functions to call with the source
+ *     at child process of pglb.
+ *
+ * Portions Copyright (c) 2003, Atsushi Mitani
+ * Portions Copyright (c) 2003, Tatsuo Ishii
+ *--------------------------------------------------------------------
+ */
+/*
+ * 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.
+ *
+*/
+#ifdef USE_REPLICATION
+
+#include "postgres.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sys/wait.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/ipc.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/time.h>
+#include <time.h>
+#include <sys/param.h>
+#include <arpa/inet.h>
+#include <sys/file.h>
+
+#ifdef HAVE_NETINET_TCP_H
+#include <netinet/tcp.h>
+#endif
+
+#ifdef HAVE_CRYPT_H
+#include <crypt.h>
+#endif
+
+#include "postgres_fe.h"
+#include "libpq/pqcomm.h"
+
+#include "replicate_com.h"
+#include "pglb.h"
+
+/*--------------------------------------
+ * GLOBAL VARIABLE DECLARATION
+ *--------------------------------------
+ */
+POOL_CONNECTION * Frontend = NULL;
+
+/*--------------------------------------
+ * PROTOTYPE DECLARATION
+ *--------------------------------------
+ */
+int PGRpre_fork_children(ClusterTbl * ptr);
+int PGRpre_fork_child(ClusterTbl * ptr);
+int PGRdo_child( int use_pool);
+int PGRcreate_child(ClusterTbl * cluster_p);
+pid_t PGRscan_child_tbl(ClusterTbl * cluster_p);
+void notice_backend_error(void);
+void do_pooling_child(int sig);
+int PGRset_status_to_child_tbl(pid_t pid, int status);
+int PGRadd_child_tbl(ClusterTbl * cluster_p, pid_t pid, int status);
+int PGRget_child_status(pid_t pid);
+void PGRreturn_connection_full_error(void);
+void PGRquit_children_on_cluster(int rec_no);
+
+#ifdef NONE_BLOCK
+static void set_nonblock(int fd);
+#endif
+static void unset_nonblock(int fd);
+static POOL_CONNECTION *do_accept(int unix_fd, int inet_fd);
+static PGR_StartupPacket *read_startup_packet(POOL_CONNECTION *cp);
+static int send_startup_packet(POOL_CONNECTION_POOL_SLOT *cp);
+static void cancel_request(CancelPacket *sp, int secondary_backend);
+static POOL_CONNECTION_POOL *connect_backend(PGR_StartupPacket *sp, POOL_CONNECTION *frontend);
+static int send_params(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend);
+static void child_end(int sig);
+
+/*--------------------------------------------------------------------
+ * SYMBOL
+ *    PGRpre_fork_children()
+ * NOTES
+ *    pre forked child precesses
+ * ARGS
+ *    ClusterTbl * ptr: pointer of cluster server table (I)
+ * RETURN
+ *    OK: STATUS_OK
+ *    NG: STATUS_ERROR
+ *--------------------------------------------------------------------
+ */
+int
+PGRpre_fork_children(ClusterTbl * ptr)
+{
+	int cnt;
+
+	if (ptr == NULL)
+	{
+		return STATUS_ERROR;
+	}
+	cnt = 0 ;
+	while ((ptr->useFlag != TBL_END) && (cnt < ClusterNum))
+	{
+		PGRpre_fork_child(ptr);
+		cnt ++;
+		ptr ++;
+	}
+	return STATUS_OK;
+}
+
+/*--------------------------------------------------------------------
+ * SYMBOL
+ *    PGRpre_fork_child()
+ * NOTES
+ *    pre forked child precess
+ * ARGS
+ *    ClusterTbl * ptr: pointer of cluster server table (I)
+ * RETURN
+ *    OK: STATUS_OK
+ *    NG: STATUS_ERROR
+ *--------------------------------------------------------------------
+ */
+int
+PGRpre_fork_child(ClusterTbl * ptr)
+{
+	pid_t pid = 0;
+	int i;
+
+	if (ptr == NULL)
+	{
+		return STATUS_ERROR;
+	}
+	if (ptr->useFlag == TBL_END)
+	{
+		return STATUS_ERROR;
+	}
+	for ( i = 0 ; i < ptr->max_connect * Max_Pool ; i ++)
+	{
+		pid = PGRcreate_child(ptr);		
+	}
+	return STATUS_OK;
+}
+/*--------------------------------------------------------------------
+ * SYMBOL
+ *    PGRdo_child()
+ * NOTES
+ *    execute child process
+ * ARGS
+ *    int use_pool: usage flag of connection pooling (I)
+ * RETURN
+ *    OK: STATUS_OK
+ *    NG: STATUS_ERROR
+ *--------------------------------------------------------------------
+ */
+int
+PGRdo_child( int use_pool)
+{
+	char * func = "PGRdo_child()";
+	pid_t pid = 0;
+	PGR_StartupPacket *sp = NULL;
+	POOL_CONNECTION *frontend = NULL;
+	POOL_CONNECTION_POOL *backend = NULL;
+	int status = 0;
+	int connection_reuse = 1;
+	int ssl_request = 0;
+	int count = 0;
+	ClusterTbl * cluster_p = NULL;
+
+	pid = getpid();
+#ifdef PRINT_DEBUG
+	show_debug("%s:I am %d",func, pid);
+#endif			
+
+	/* set up signal handlers */
+	signal(SIGALRM, SIG_IGN);
+	signal(SIGTERM, child_end);
+	signal(SIGHUP, child_end);
+	signal(SIGINT, child_end);
+	signal(SIGUSR1, SIG_IGN);
+	signal(SIGUSR2, SIG_IGN);
+
+#ifdef NONE_BLOCK
+	/* set listen fds to none block */
+	set_nonblock(Frontend_FD.unix_fd);
+	set_nonblock(Frontend_FD.inet_fd);
+#endif
+
+	/* perform accept() */
+	frontend = do_accept(Frontend_FD.unix_fd,Frontend_FD.inet_fd);
+	if (frontend == NULL)
+	{
+		/* accept() failed. return to the accept() loop */
+		PGRset_status_to_child_tbl(pid,TBL_ERROR);
+		return STATUS_ERROR;
+	}
+
+	/* unset frontend fd tp none block */
+	unset_nonblock(frontend->fd);
+
+	/* read the startup packet */
+	sp = 0;
+retry_startup:
+	if (sp)
+	{
+		free(sp->startup_packet);
+		free(sp->database);
+		free(sp->user);
+		free(sp);
+	}
+
+	sp = read_startup_packet(frontend);
+	if (sp == NULL)
+	{
+		/* failed to read the startup packet. return to the
+		   accept() loop */
+		pool_close(frontend);
+		PGRset_status_to_child_tbl(pid,TBL_ERROR);
+		return STATUS_ERROR;
+	}
+	PGRset_status_to_child_tbl(pid,TBL_ACCEPT);
+
+	/* cancel request? */
+	if (sp->major == 1234 && sp->minor == 5678)
+	{
+		cancel_request((CancelPacket *)sp->startup_packet, 0);
+		pool_close(frontend);
+		return STATUS_ERROR;
+	}
+
+	/* SSL? */
+	if (sp->major == 1234 && sp->minor == 5679)
+	{
+		/* SSL not supported */
+#ifdef PRINT_DEBUG
+		show_debug("%s:SSLRequest: sent N; retry startup",func);
+#endif			
+		if (ssl_request)
+		{
+			pool_close(frontend);
+			return STATUS_ERROR;
+		}
+
+		/*
+		 * say to the frontend "we do not suppport SSL"
+		 * note that this is not a NOTICE response despite it's an 'N'!
+		 */
+		pool_write_and_flush(frontend, "N", 1);
+		ssl_request = 1;
+		goto retry_startup;
+	}
+
+	/*
+	 * Ok, negotiaton with frontend has been done. Let's go to the next step.
+	 */
+	/*
+	 * if there's no connection associated with user and database,
+	 * we need to connect to the backend and send the startup packet.
+	 */
+	count = 0;
+	if ((backend = pool_get_cp(sp->user, sp->database, sp->major)) == NULL)
+	{
+		connection_reuse = 0;
+
+reconnect_backend:
+		if ((backend = connect_backend(sp, frontend)) == NULL)
+		{
+			if (use_pool)
+			{
+				show_error("under use_pool return error");
+				return STATUS_ERROR;
+			}
+			PGRset_status_on_cluster_tbl(TBL_ERROR,CurrentCluster);
+			cluster_p = PGRscan_cluster();
+			if (cluster_p == NULL)
+			{
+				show_error("there is no usable clusterdb");
+				return STATUS_ERROR;
+			}
+			CurrentCluster = cluster_p;
+			pool_clear();
+			goto reconnect_backend;
+		}
+	}
+	else
+	{
+		/* reuse existing connection to backend */
+
+		if (pool_do_reauth(frontend, backend))
+		{
+			pool_close(frontend);
+			return STATUS_ERROR;
+		}
+
+		if (MAJOR(backend) == 3)
+		{
+			if (send_params(frontend, backend))
+			{
+				pool_close(frontend);
+				return STATUS_ERROR;
+			}
+		}
+
+		/* send ReadyForQuery to frontend */
+		pool_write(frontend, "Z", 1);
+
+		if (MAJOR(backend) == 3)
+		{
+			int len;
+			char tstate;
+
+			len = htonl(5);
+			pool_write(frontend, &len, sizeof(len));
+			tstate = TSTATE(backend);
+			pool_write(frontend, &tstate, 1);
+		}
+
+		if (pool_flush(frontend) < 0)
+		{
+			pool_close(frontend);
+			return STATUS_ERROR;
+		}
+
+	}
+
+	/* query process loop */
+	for (;;)
+	{
+		POOL_STATUS status;
+
+		status = pool_process_query(frontend, backend, 0);
+
+		switch (status)
+		{
+			/* client exits */
+			case POOL_END:
+				/* do not cache connection to template0, template1, regression */
+				if (!strcmp(sp->database, "template0") || !strcmp(sp->database, "template1") ||
+					!strcmp(sp->database, "regression"))
+				{
+					pool_close(frontend);
+					pool_send_frontend_exits(backend);
+					pool_discard_cp(sp->user, sp->database, sp->major);
+				}
+				else
+				{
+					POOL_STATUS status1;
+
+					/* send reset request to backend */
+					status1 = pool_process_query(frontend, backend, 1);
+					pool_close(frontend);
+
+					/* if we detect errors on resetting connection, we need to discard
+					 * this connection since it might be in unknown status
+					 */
+					if (status1 != POOL_CONTINUE)
+						pool_discard_cp(sp->user, sp->database, sp->major);
+					else
+						pool_connection_pool_timer(backend);
+				}
+				break;
+			
+			/* error occured. discard backend connection pool
+			   and disconnect connection to the frontend */
+			case POOL_ERROR:
+				show_error("%s:do_child: exits with status 1 due to error",func);
+				break;
+
+			/* fatal error occured. just exit myself... */
+			case POOL_FATAL:
+				notice_backend_error();
+				break;
+
+			/* not implemented yet */
+			case POOL_IDLE:
+				do_accept(Frontend_FD.unix_fd,Frontend_FD.inet_fd);
+#ifdef PRINT_DEBUG
+				show_debug("%s:accept while idle",func);
+#endif			
+				break;
+
+			default:
+				break;
+		}
+
+		if (status != POOL_CONTINUE)
+			break;
+	}
+	if ((status == POOL_ERROR) || 
+		(status == POOL_FATAL))
+	{
+		PGRset_status_to_child_tbl(pid,TBL_ERROR);
+		return STATUS_ERROR;
+	}
+	PGRset_status_to_child_tbl(pid,TBL_INIT);
+	return STATUS_OK;
+}
+
+/*--------------------------------------------------------------------
+ * SYMBOL
+ *    PGRcreate_child()
+ * NOTES
+ *    create child process
+ * ARGS
+ *    ClusterTbl * ptr: pointer of cluster server table (I)
+ * RETURN
+ *    OK: STATUS_OK
+ *    NG: STATUS_ERROR
+ *--------------------------------------------------------------------
+ */
+int 
+PGRcreate_child(ClusterTbl * cluster_p)
+{
+	char * func = "PGRcreate_child()";
+	pid_t pid,pgid;
+
+	if (cluster_p == NULL)
+		return STATUS_ERROR;
+
+#ifdef PRINT_DEBUG
+	show_debug("%s:create child [%d@%s]",func,cluster_p->port,cluster_p->hostName);
+#endif			
+	signal(SIGCHLD,PGRrecreate_child);
+	pgid = getpgid((pid_t)0);
+	pid = fork();
+	if (pid < 0)
+	{
+		show_error("%s:fork() failed. (%s)",func,strerror(errno));
+		return STATUS_ERROR;
+	}
+	if (pid == 0)
+	{
+		CurrentCluster = cluster_p;
+		if (pool_init_cp())
+		{
+			show_error("%s:pool_init_cp failed",func);
+			exit(1);
+		}
+		signal(SIGCHLD,PGRchild_wait);
+		signal(SIGTERM, child_end);
+		signal(SIGHUP, child_end);
+		signal(SIGINT, child_end);
+		signal(SIGUSR1,do_pooling_child);
+		setpgid((pid_t)0,pgid);
+		for (;;)
+		{
+			pause();
+			signal(SIGUSR1,do_pooling_child);
+		}
+#ifdef PRINT_DEBUG
+		show_debug("%s:create child end [%d@%s]",func,cluster_p->port,cluster_p->hostName);
+#endif			
+		child_end(SIGTERM);
+	}
+	else
+	{
+		PGRadd_child_tbl(cluster_p,pid,TBL_INIT);
+	}
+	return pid;
+}
+
+/*--------------------------------------------------------------------
+ * SYMBOL
+ *    PGRscan_child_tbl()
+ * NOTES
+ *    get a child process id that is waiting for connection 
+ *    with the cluster server
+ * ARGS
+ *    ClusterTbl * ptr: pointer of cluster server table (I)
+ * RETURN
+ *    OK: child process id
+ *    NG: 0
+ *--------------------------------------------------------------------
+ */
+pid_t
+PGRscan_child_tbl(ClusterTbl * cluster_p)
+{
+	char * func = "PGRscan_child_tbl()";
+	ChildTbl * p;
+
+	if ( cluster_p == NULL)
+	{
+		show_error("%s:Cluster_Tbl is not initialize",func);
+		return STATUS_ERROR;
+	}
+	p = Child_Tbl;
+	if ( p == NULL)
+	{
+		show_error("%s:Child_Tbl is not initialize",func);
+		return STATUS_ERROR;
+	}
+	while(p->useFlag != TBL_END)
+	{
+		if (p->pid <= 0)
+		{
+			p++;
+			continue;
+		}
+		if ((p->useFlag == TBL_INIT) &&
+			(p->rec_no == cluster_p->rec_no))
+		{
+			p->useFlag = TBL_USE;
+			return (p->pid);
+		}
+		p++;
+	}
+	return 0;
+}
+
+/* notice backend connection error using SIGUSR2 */
+void
+notice_backend_error(void)
+{
+	pid_t pid = getpid();
+	pid_t parent = getppid();
+	PGRset_status_to_child_tbl(pid,TBL_ERROR);
+	PGRset_status_on_cluster_tbl(TBL_ERROR_NOTICE,CurrentCluster);
+
+	kill(parent, SIGUSR2);
+	sleep(1);
+}
+
+
+/*
+ * start up pooling child process
+ */
+void
+do_pooling_child(int sig)
+{
+	char * func = "do_pooling_child()";
+	int rtn;
+
+#ifdef PRINT_DEBUG
+	pid_t pid;
+	pid = getpid();
+	show_debug("%s:pid[%d] called",func,pid);
+#endif
+
+	rtn = PGRdo_child(USE_CONNECTION_POOL);
+	if (rtn != STATUS_OK)
+	{
+		show_error("%s:PGRdo_child failed",func);
+		notice_backend_error();
+	}
+	PGRrelease_connection(CurrentCluster);
+	return ;
+}
+
+/*
+ * set status in child process table
+ */
+int
+PGRset_status_to_child_tbl(pid_t pid, int status)
+{
+	char * func = "PGRset_status_to_child_tbl()";
+	ChildTbl * p;
+
+	p = Child_Tbl;
+	if ( p == NULL)
+	{
+		show_error("%s:Child_Tbl is not initialize",func);
+		return STATUS_ERROR;
+	}
+	while(p->useFlag != TBL_END)
+	{
+		if (p->pid == pid)
+		{
+			p->useFlag = status;
+			return STATUS_OK;
+		}
+		p++;
+	}
+	return STATUS_ERROR;
+}
+
+/*
+ * add child process data in child process table
+ */
+int
+PGRadd_child_tbl(ClusterTbl * cluster_p, pid_t pid, int status)
+{
+	char * func = "PGRadd_child_tbl()";
+	ChildTbl * p;
+
+	p = Child_Tbl;
+	if ( cluster_p == NULL)
+	{
+		show_error("%s:Cluster_Tbl is not initialize",func);
+		return STATUS_ERROR;
+	}
+	if ( p == NULL)
+	{
+		show_error("%s:Child_Tbl is not initialize",func);
+		return STATUS_ERROR;
+	}
+	while(p->useFlag != TBL_END)
+	{
+		if ((p->useFlag == TBL_FREE) ||
+			(p->useFlag == TBL_ERROR))
+		{
+			p->useFlag = status;
+			p->rec_no = cluster_p->rec_no;
+			p->pid = pid;
+			return STATUS_OK;
+		}
+		p++;
+	}
+	return STATUS_ERROR;
+}
+
+int
+PGRget_child_status(pid_t pid)
+{
+	char * func = "PGRget_child_status()";
+	ChildTbl * p;
+
+	p = Child_Tbl;
+	if ( p == NULL)
+	{
+		show_error("%s:Child_Tbl is not initialize",func);
+		return STATUS_ERROR;
+	}
+
+	while (p->useFlag != TBL_END)
+	{
+		if (p->pid == pid)
+		{
+			return p->useFlag;
+		}
+		p++;
+	}
+	return STATUS_ERROR;
+}
+
+void 
+PGRreturn_connection_full_error(void)
+{
+	PGR_StartupPacket *sp = NULL;
+	POOL_CONNECTION *frontend = NULL;
+	static char *msg = "Sorry, backend connection is full";
+
+	/* perform accept() */
+	frontend = do_accept(Frontend_FD.unix_fd,Frontend_FD.inet_fd);
+	if (frontend == NULL)
+	{
+		/* accept() failed. return to the accept() loop */
+		return ;
+	}
+	sp = read_startup_packet(frontend);
+	if (sp == NULL)
+	{
+		/* failed to read the startup packet. return to the
+		   accept() loop */
+		pool_close(frontend);
+		return ;
+	}
+	pool_write_and_flush(frontend, "E", 1);
+	pool_write_and_flush(frontend, msg, strlen(msg)+1);
+	pool_close(frontend);
+	return ;
+}
+
+void
+PGRquit_children_on_cluster(int rec_no)
+{
+	char * func = "PGRquit_children_on_cluster()";
+	ChildTbl * p;
+
+	if (Child_Tbl == NULL)
+	{
+		return;
+	}
+	signal(SIGCHLD,SIG_IGN);
+	p = Child_Tbl;
+	while(p->useFlag != TBL_END)
+	{
+		if (p->rec_no == rec_no) 
+		{
+			if (kill (p->pid,SIGTERM) == -1)
+			{
+				show_error("%s:could not stop pid: %d (%s)",func,p->pid,strerror(errno));
+				return;
+			}
+			PGRchild_wait(SIGTERM);
+			p->useFlag = DATA_FREE;
+		}
+		p++;
+	}
+	if (Use_Connection_Pool)
+	{
+		signal(SIGCHLD,PGRrecreate_child);
+	}
+	else
+	{
+		signal(SIGCHLD,PGRchild_wait);
+	}
+}
+
+/* -------------------------------------------------------------------
+ * private functions
+ * -------------------------------------------------------------------
+ */
+
+#ifdef NONE_BLOCK
+/*
+ * set non-block flag
+ */
+static void set_nonblock(int fd)
+{
+	char* func = "set_nonblock()";
+	int var;
+
+	/* set fd to none blocking */
+	var = fcntl(fd, F_GETFL, 0);
+	if (var == -1)
+	{
+		show_error("%s:fcntl failed. %s", func,strerror(errno));
+		child_end(SIGTERM);
+	}
+	if (fcntl(fd, F_SETFL, var | O_NONBLOCK) == -1)
+	{
+		show_error("%s:fcntl failed. %s", func,strerror(errno));
+		child_end(SIGTERM);
+	}
+}
+#endif
+
+/*
+ * unset non-block flag
+ */
+static void unset_nonblock(int fd)
+{
+	char * func = "unset_nonblock()";
+	int var;
+
+	/* set fd to none blocking */
+	var = fcntl(fd, F_GETFL, 0);
+	if (var == -1)
+	{
+		show_error("%s,fcntl failed. %s", func,strerror(errno));
+		child_end(SIGTERM);
+	}
+	if (fcntl(fd, F_SETFL, var & ~O_NONBLOCK) == -1)
+	{
+		show_error("%s,fcntl failed. %s", func,strerror(errno));
+		child_end(SIGTERM);
+	}
+}
+
+
+/*
+* perform accept() and returns new fd
+*/
+static POOL_CONNECTION *do_accept(int unix_fd, int inet_fd)
+{
+	char * func = "do_accept()";
+    fd_set	readmask;
+    int fds;
+	struct sockaddr addr;
+	socklen_t addrlen;
+	int fd = 0;
+	int afd;
+	int inet = 0;
+	POOL_CONNECTION *cp;
+#ifdef ACCEPT_PERFORMANCE
+	struct timeval now1, now2;
+	static long atime;
+	static int cnt;
+#endif
+
+	FD_ZERO(&readmask);
+	FD_SET(unix_fd, &readmask);
+	if (inet_fd)
+		FD_SET(inet_fd, &readmask);
+
+	fds = select(Max(unix_fd, inet_fd)+1, &readmask, NULL, NULL, NULL);
+	if (fds == -1)
+	{
+		if (errno == EAGAIN || errno == EINTR)
+			return NULL;
+
+		show_error("%s:select() failed. reason %s",func, strerror(errno));
+		return NULL;
+	}
+
+	if (fds == 0)
+		return NULL;
+
+	if (FD_ISSET(unix_fd, &readmask))
+	{
+		fd = unix_fd;
+	}
+
+	if (FD_ISSET(inet_fd, &readmask))
+	{
+		fd = inet_fd;
+		inet++;
+	}
+
+	/*
+	 * Note that some SysV systems do not work here. For those
+	 * systems, we need some locking mechanism for the fd.
+	 */
+	addrlen = sizeof(addr);
+
+#ifdef ACCEPT_PERFORMANCE
+	gettimeofday(&now1,0);
+#endif
+	afd = accept(fd, &addr, &addrlen);
+	if (afd < 0)
+	{
+		/*
+		 * "Resource temporarily unavailable" (EAGAIN or EWOULDBLOCK)
+		 * can be silently ignored.
+		 */
+		if (errno != EAGAIN && errno != EWOULDBLOCK)
+			show_error("%s:accept() failed. reason: %s",func, strerror(errno));
+		return NULL;
+	}
+#ifdef ACCEPT_PERFORMANCE
+	gettimeofday(&now2,0);
+	atime += (now2.tv_sec - now1.tv_sec)*1000000 + (now2.tv_usec - now1.tv_usec);
+	cnt++;
+	if (cnt % 100 == 0)
+	{
+		show_error("%s:cnt: %d atime: %ld",func, cnt, atime);
+	}
+#endif
+#ifdef PRINT_DEBUG
+	show_debug("%s:I am %d accept fd %d",func, getpid(), afd);
+#endif			
+
+	/* set NODELAY and KEEPALIVE options if INET connection */
+	if (inet)
+	{
+		int on = 1;
+
+		if (setsockopt(afd, IPPROTO_TCP, TCP_NODELAY,
+					   (char *) &on,
+					   sizeof(on)) < 0)
+		{
+			show_error("%s:do_accept: setsockopt() failed: %s",func, strerror(errno));
+			close(afd);
+			return NULL;
+		}
+		if (setsockopt(afd, SOL_SOCKET, SO_KEEPALIVE,
+					   (char *) &on,
+					   sizeof(on)) < 0)
+		{
+			show_error("%s:do_accept: setsockopt() failed: %s", func,strerror(errno));
+			close(afd);
+			return NULL;
+		}
+	}
+
+	if ((cp = pool_open(afd)) == NULL)
+	{
+		close(afd);
+		return NULL;
+	}
+	return cp;
+}
+
+/*
+* read startup packet
+*/
+static PGR_StartupPacket *read_startup_packet(POOL_CONNECTION *cp)
+{
+	char * func = "read_startup_packet()";
+	PGR_StartupPacket *sp;
+	PGR_StartupPacket_v2 *sp2;
+	int protov;
+	int len;
+	char *p;
+
+	sp = (PGR_StartupPacket *)malloc(sizeof(PGR_StartupPacket));
+	if (!sp)
+	{
+		show_error("%s:read_startup_packet: out of memory",func);
+		return NULL;
+	}
+
+	/* read startup packet length */
+	if (pool_read(cp, &len, sizeof(len)))
+	{
+		return NULL;
+	}
+	len = ntohl(len);
+	len -= sizeof(len);
+
+	if (len <= 0)
+	{
+		show_error("%s:read_startup_packet: incorrect packet length (%d)", func,len);
+	}
+
+	sp->startup_packet = calloc(len, 1);
+	if (!sp->startup_packet)
+	{
+		show_error("%s:read_startup_packet: out of memory",func);
+		return NULL;
+	}
+
+	/* read startup packet */
+	if (pool_read(cp, sp->startup_packet, len))
+	{
+		return NULL;
+	}
+
+	sp->len = len;
+	memcpy(&protov, sp->startup_packet, sizeof(protov));
+	sp->major = ntohl(protov)>>16;
+	sp->minor = ntohl(protov) & 0x0000ffff;
+	p = sp->startup_packet;
+
+	switch(sp->major)
+	{
+		case PROTO_MAJOR_V2: /* V2 */
+			sp2 = (PGR_StartupPacket_v2 *)(sp->startup_packet);
+
+			sp->database = calloc(SM_DATABASE+1, 1);
+			if (!sp->database)
+			{
+				show_error("%s:read_startup_packet: out of memory",func);
+				return NULL;
+			}
+			strncpy(sp->database, sp2->database, SM_DATABASE);
+
+			sp->user = calloc(SM_USER+1, 1);
+			if (!sp->user)
+			{
+				show_error("%s:read_startup_packet: out of memory",func);
+				return NULL;
+			}
+			strncpy(sp->user, sp2->user, SM_USER);
+
+			break;
+
+		case PROTO_MAJOR_V3: /* V3 */
+			p += sizeof(int);	/* skip protocol version info */
+
+			while(*p)
+			{
+				if (!strcmp("user", p))
+				{
+					p += (strlen(p) + 1);
+					sp->user = strdup(p);
+					if (!sp->user)
+					{
+						show_error("%s:read_startup_packet: out of memory",func);
+						return NULL;
+					}
+				}
+				else if (!strcmp("database", p))
+				{
+					p += (strlen(p) + 1);
+					sp->database = strdup(p);
+					if (!sp->database)
+					{
+						show_error("%s:read_startup_packet: out of memory",func);
+						return NULL;
+					}
+				}
+				p += (strlen(p) + 1);
+			}
+			break;
+
+		case 1234:		/* cancel or SSL request */
+			/* set dummy database, user info */
+			sp->database = calloc(1, 1);
+			if (!sp->database)
+			{
+				show_error("%s:read_startup_packet: out of memory",func);
+				return NULL;
+			}
+			sp->user = calloc(1, 1);
+			if (!sp->user)
+			{
+				show_error("%s:read_startup_packet: out of memory",func);
+				return NULL;
+			}
+			break;
+
+		default:
+			show_error("%s:read_startup_packet: invalid major no: %d",func, sp->major);
+			return NULL;
+	}
+
+#ifdef PRINT_DEBUG
+	show_debug("%s:Protocol Major: %d Minor: %d database: %s user: %s", 
+			   func,sp->major, sp->minor, sp->database, sp->user);
+#endif			
+
+	return sp;
+}
+
+/*
+* send startup packet
+*/
+static int send_startup_packet(POOL_CONNECTION_POOL_SLOT *cp)
+{
+	int len;
+
+	len = htonl(cp->sp->len + sizeof(len));
+	pool_write(cp->con, &len, sizeof(len)); 
+	return pool_write_and_flush(cp->con, cp->sp->startup_packet, cp->sp->len);
+}
+
+/*
+ * process cancel request
+ */
+static void cancel_request(CancelPacket *sp, int secondary_backend)
+{
+	char * func = "cancel_request()";
+	int	len;
+	int fd;
+	POOL_CONNECTION *con;
+	char hostName[128];
+
+#ifdef PRINT_DEBUG
+	show_debug("%s:Cancel request received",func);
+#endif			
+
+	if (CurrentCluster == NULL)
+	{
+		return;
+	}
+	if (gethostname(hostName,sizeof(hostName)) < 0)
+	{
+		show_error("%s:gethostname() failed. (%s)",func,strerror(errno));
+		return ;
+	}
+	if (secondary_backend)
+	{
+		if (PGRis_same_host(hostName,CurrentCluster->hostName))
+			fd = connect_unix_domain_socket(1);
+		else
+			fd = connect_inet_domain_socket(1);
+	}
+	else
+	{
+		if (PGRis_same_host(hostName,CurrentCluster->hostName))
+			fd = connect_unix_domain_socket(0);
+		else
+			fd = connect_inet_domain_socket(0);
+	}
+
+	if (fd < 0)
+	{
+		show_error("%s:Could not create socket for sending cancel request",func);
+		return;
+	}
+
+	con = pool_open(fd);
+	if (con == NULL)
+		return;
+
+	len = htonl(sizeof(len) + sizeof(CancelPacket));
+	pool_write(con, &len, sizeof(len));
+
+	if (pool_write_and_flush(con, sp, sizeof(CancelPacket)) < 0)
+		show_error("%s:Could not send cancel request packet",func);
+	pool_close(con);
+}
+
+static POOL_CONNECTION_POOL *connect_backend(PGR_StartupPacket *sp, POOL_CONNECTION *frontend)
+{
+	char * func = "connect_backend()";
+	POOL_CONNECTION_POOL *backend;
+
+	/* connect to the backend */
+	backend = pool_create_cp();
+	if (backend == NULL)
+	{
+		pool_send_error_message(frontend, sp->major, "XX000", "connection cache is full", "",
+								"increace max_pool", __FILE__, __LINE__);
+		pool_close(frontend);
+		return NULL;
+	}
+
+	/* mark this is a backend connection */
+	backend->slots[0]->con->isbackend = 1;
+	/*
+	 * save startup packet info
+	 */
+	backend->slots[0]->sp = sp;
+
+	if (pool_config_replication_enabled)
+	{
+		backend->slots[1]->con->isbackend = 1;
+		backend->slots[1]->con->issecondary_backend = 1;
+		/*
+		 * save startup packet info
+		 */
+		backend->slots[1]->sp = sp;
+	}
+
+	/* send startup packet */
+	if (send_startup_packet(backend->slots[0]) < 0)
+	{
+		show_error("%s:do_child: fails to send startup packet to the backend",func);
+		pool_close(frontend);
+		return NULL;
+	}
+
+	/* send startup packet */
+	if (pool_config_replication_enabled)
+	{
+		if (send_startup_packet(backend->slots[1]) < 0)
+		{
+			show_error("%s:do_child: fails to send startup packet to the secondary backend",func);
+			pool_close(frontend);
+			return NULL;
+		}
+	}
+
+	/*
+	 * do authentication stuff
+	 */
+	if (pool_do_auth(frontend, backend))
+	{
+		pool_close(frontend);
+		pool_discard_cp(sp->user, sp->database, sp->major);
+		return NULL;
+	}
+	return backend;
+}
+
+static int send_params(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend)
+{
+	char * func = "send_params()";
+	int index;
+	char *name, *value;
+	int len, sendlen;
+
+	index = 0;
+	while (pool_get_param(&MASTER(backend)->params, index++, &name, &value) == 0)
+	{
+		pool_write(frontend, "S", 1);
+		len = sizeof(sendlen) + strlen(name) + 1 + strlen(value) + 1;
+		sendlen = htonl(len);
+		pool_write(frontend, &sendlen, sizeof(sendlen));
+		pool_write(frontend, name, strlen(name) + 1);
+		pool_write(frontend, value, strlen(value) + 1);
+	}
+
+	if (pool_flush(frontend))
+	{
+		show_error("%s:pool_send_params: pool_flush() failed",func);
+		return -1;
+	}
+	return 0;
+}
+
+/*
+ * ending function of child process
+ */
+static void
+child_end(int sig)
+{
+	signal(sig,SIG_IGN);
+
+	pool_finish();
+	exit(0);
+}
+
+
+#endif /* USE_REPLICATION */
diff -ruN postgresql-7.4.13-old/src/pgcluster/pglb/cluster_table.c postgresql-7.4.13/src/pgcluster/pglb/cluster_table.c
--- postgresql-7.4.13-old/src/pgcluster/pglb/cluster_table.c	1970-01-01 01:00:00.000000000 +0100
+++ postgresql-7.4.13/src/pgcluster/pglb/cluster_table.c	2006-08-05 16:53:43.000000000 +0200
@@ -0,0 +1,321 @@
+/*--------------------------------------------------------------------
+ * FILE:
+ *     cluster_tbl.c
+ *
+ * NOTE:
+ *     This file is composed of the functions to use a cluster table.
+ *
+ * Portions Copyright (c) 2003, Atsushi Mitani
+ *--------------------------------------------------------------------
+ */
+/*
+ * 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.
+ *
+*/
+#ifdef USE_REPLICATION
+
+#include "postgres.h"
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sys/wait.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <sys/sem.h>
+#include <sys/msg.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/time.h>
+#include <time.h>
+#include <sys/param.h>
+#include <sys/select.h>
+#include <arpa/inet.h>
+#include <sys/file.h>
+
+#ifdef HAVE_NETINET_TCP_H
+#include <netinet/tcp.h>
+#endif
+
+#include "replicate_com.h"
+#include "pglb.h"
+
+
+/*--------------------------------------
+ * PROTOTYPE DECLARATION
+ *--------------------------------------
+ */
+ClusterTbl * PGRscan_cluster(void);
+void PGRset_key_of_cluster(ClusterTbl * ptr, RecoveryPacket * packet);
+ClusterTbl * PGRadd_cluster_tbl (ClusterTbl * conf_data);
+ClusterTbl * PGRset_status_on_cluster_tbl (int status, ClusterTbl * ptr);
+ClusterTbl * PGRsearch_cluster_tbl(ClusterTbl * conf_data);
+
+static int set_cluster_tbl(ClusterTbl * ptr , ClusterTbl * conf_data);
+static ClusterTbl * search_free_cluster_tbl(void );
+static void write_cluster_status_file(ClusterTbl * ptr);
+
+
+ClusterTbl * 
+PGRscan_cluster(void)
+{
+	char * func = "PGRscan_cluster";
+	ClusterTbl * ptr = NULL;
+	ClusterTbl * rtn = NULL;
+	int min_use_rate = 100;
+	int use_rate = 0;
+	int cnt = 0;
+
+
+	ptr = Cluster_Tbl;
+	if (ptr == NULL)
+	{
+		show_error("%s:Cluster Table is not initialize",func);
+		return (ClusterTbl *)NULL;
+	}
+#ifdef PRINT_DEBUG
+	show_debug("%s:%d ClusterDB can be used",func,ClusterNum);
+#endif			
+	PGRsem_lock(ClusterSemid,MAX_DB_SERVER);
+	while ((cnt <= ClusterNum) && (ptr->useFlag != TBL_END))
+	{
+#ifdef PRINT_DEBUG
+		show_debug("%s:%s [%d],useFlag->%d max->%d use_num->%d\n",
+			func, ptr->hostName,ptr->port,ptr->useFlag,ptr->max_connect,ptr->use_num);
+#endif			
+		if (ptr->useFlag != TBL_USE)
+		{
+			ptr ++;
+			continue;
+		}
+		cnt ++;
+		if (ptr->max_connect <= ptr->use_num)
+		{
+			ptr ++;
+			continue;
+		}
+		if (ptr->use_num > 0)
+		{
+			use_rate = ptr->use_num * 100 / ptr->max_connect ;
+		}
+		else
+		{
+			use_rate = 0;
+			rtn = ptr;
+			break;
+		}
+		if (min_use_rate > use_rate)
+		{
+			min_use_rate = use_rate;
+			rtn = ptr;
+		}
+		ptr ++;
+	}
+	if (rtn != NULL)
+	{
+		rtn->use_num ++;
+	}
+	PGRsem_unlock(ClusterSemid,MAX_DB_SERVER);
+	return rtn;
+}
+
+void
+PGRset_key_of_cluster(ClusterTbl * ptr, RecoveryPacket * packet)
+{
+	int max_connect = 0;
+	int port = 0;
+
+	memset(ptr,0,sizeof(ClusterTbl));
+	strncpy(ptr->hostName,packet->hostName,sizeof(ptr->hostName));
+	max_connect = ntohs(packet->max_connect);
+	if (max_connect >= 0)
+	{
+		ptr->max_connect = max_connect;
+	}
+	else
+	{
+		ptr->max_connect = DEFAULT_CONNECT_NUM;
+	}
+	port = ntohs(packet->port);
+	if ( port >= 0)
+	{
+		ptr->port = port;
+	}
+	else
+	{
+		ptr->port = DEFAULT_PORT;
+	}
+}
+
+ClusterTbl *
+PGRadd_cluster_tbl (ClusterTbl * conf_data)
+{
+	char * func = "PGRadd_cluster_tbl()";
+	ClusterTbl * ptr;
+
+	ptr = PGRsearch_cluster_tbl(conf_data);
+	if ((ptr != NULL) && (ptr->useFlag == TBL_USE ))
+	{
+		ptr->max_connect = conf_data->max_connect;
+		ptr->use_num = 0;
+		ptr->rate = 0;
+		return ptr;
+	}
+	ptr = search_free_cluster_tbl();
+	if (ptr == (ClusterTbl *) NULL)
+	{
+		show_error("%s:no more free space in cluster table",func);
+		return (ClusterTbl *)NULL;
+	}
+	if (ClusterNum <= Max_DB_Server)
+	{
+		set_cluster_tbl( ptr, conf_data);
+		return ptr;
+	}
+	return (ClusterTbl *)NULL;
+}
+
+ClusterTbl *
+PGRset_status_on_cluster_tbl (int status, ClusterTbl * ptr)
+{
+#ifdef PRINT_DEBUG
+	char * func = "PGRset_status_on_cluster_tbl()";
+#endif			
+
+	if (ptr != (ClusterTbl*)NULL)
+	{
+		if (ptr->useFlag != status)
+		{
+#ifdef PRINT_DEBUG
+			show_debug("%s:host:%s port:%d max:%d use:%d status%d",
+				func, ptr->hostName,ptr->port,ptr->max_connect,ptr->useFlag,status);
+#endif			
+			ptr->useFlag = status;
+			write_cluster_status_file(ptr);
+			if (status == TBL_USE)
+			{
+				if (ClusterNum < Max_DB_Server)
+					ClusterNum ++ ;
+			}
+			else if (status != TBL_STOP)
+			{
+				if (ClusterNum > 0)
+					ClusterNum -- ;
+			}
+		}
+	}
+	return ptr;
+}
+
+static void
+write_cluster_status_file(ClusterTbl * ptr)
+{
+	switch( ptr->useFlag)
+	{
+		case TBL_FREE:
+			PGRwrite_log_file(Com_Info.Log_Info.StatusFp,"port(%d) host:%s free",
+					ptr->port,
+					ptr->hostName);
+			break;
+		case TBL_INIT:
+			PGRwrite_log_file(Com_Info.Log_Info.StatusFp,"port(%d) host:%s initialize",
+					ptr->port,
+					ptr->hostName);
+			break;
+		case TBL_USE:
+			PGRwrite_log_file(Com_Info.Log_Info.StatusFp,"port(%d) host:%s start use",
+					ptr->port,
+					ptr->hostName);
+			break;
+		case TBL_ERROR:
+			PGRwrite_log_file(Com_Info.Log_Info.StatusFp,"port(%d) host:%s error",
+					ptr->port,
+					ptr->hostName);
+			break;
+		case TBL_END:
+			PGRwrite_log_file(Com_Info.Log_Info.StatusFp,"port(%d) host:%s end",
+					ptr->port,
+					ptr->hostName);
+			break;
+	}
+}
+
+ClusterTbl *
+PGRsearch_cluster_tbl(ClusterTbl * conf_data)
+{
+	ClusterTbl *ptr;
+	int cnt = 0;
+	int rec_num = 0;
+
+	ptr = Cluster_Tbl;
+	while ((cnt <= ClusterNum) && (rec_num < Max_DB_Server))
+	{
+		if ((!strcmp(ptr->hostName,conf_data->hostName)) &&
+			(ptr->port == conf_data->port))
+		{
+			return ptr;
+		}
+		if (ptr->useFlag == TBL_USE)
+		{
+			cnt ++;
+		}
+		ptr ++;
+		rec_num ++;
+	}
+	return (ClusterTbl *)NULL;
+}
+
+static int
+set_cluster_tbl(ClusterTbl * ptr , ClusterTbl * conf_data)
+{
+	int rec_no;
+
+	rec_no = ptr->rec_no;
+	strncpy(ptr->hostName,conf_data->hostName,sizeof(ptr->hostName));
+	ptr->max_connect = conf_data->max_connect;
+	ptr->port = conf_data->port;
+	ptr->use_num = conf_data->use_num;
+	ptr->rate = conf_data->rate;
+	PGRset_status_on_cluster_tbl (TBL_USE, ptr);
+
+	return STATUS_OK;
+}
+
+static ClusterTbl *
+search_free_cluster_tbl(void )
+{
+	ClusterTbl *ptr;
+	int cnt = 0;
+
+	ptr = Cluster_Tbl;
+	while ((cnt <= ClusterNum ) && (cnt < Max_DB_Server))
+	{
+		if (ptr->useFlag != TBL_USE)
+		{
+			return ptr;
+		}
+		cnt ++;
+		ptr ++;
+	}
+	return (ClusterTbl *)NULL;
+}
+
+#endif /* USE_REPLICATION */
diff -ruN postgresql-7.4.13-old/src/pgcluster/pglb/load_balance.c postgresql-7.4.13/src/pgcluster/pglb/load_balance.c
--- postgresql-7.4.13-old/src/pgcluster/pglb/load_balance.c	1970-01-01 01:00:00.000000000 +0100
+++ postgresql-7.4.13/src/pgcluster/pglb/load_balance.c	2006-08-05 16:53:43.000000000 +0200
@@ -0,0 +1,242 @@
+/*--------------------------------------------------------------------
+ * FILE:
+ *     load_balance.c
+ *
+ * NOTE:
+ *     This file is composed of the functions of load balance modules
+ *     with connection pooling or not
+ *
+ * Portions Copyright (c) 2003, Atsushi Mitani
+ *--------------------------------------------------------------------
+ */
+/*
+ * 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.
+ *
+*/
+#ifdef USE_REPLICATION
+
+#include "postgres.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sys/wait.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/ipc.h>
+#include <sys/sem.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/time.h>
+#include <time.h>
+#include <sys/param.h>
+#include <sys/select.h>
+#include <arpa/inet.h>
+#include <sys/file.h>
+
+#ifdef HAVE_NETINET_TCP_H
+#include <netinet/tcp.h>
+#endif
+
+#include "replicate_com.h"
+#include "pglb.h"
+
+/*--------------------------------------
+ * PROTOTYPE DECLARATION
+ *--------------------------------------
+ */
+int PGRload_balance(void);
+int PGRload_balance_with_pool(void);
+char PGRis_connection_full(ClusterTbl * ptr);
+void PGRrelease_connection(ClusterTbl * ptr);
+void PGRchild_wait(int sig);
+
+/*--------------------------------------------------------------------
+ * SYMBOL
+ *    PGRload_balance()
+ * NOTES
+ *    load balance module that normal connection is used
+ * ARGS
+ *    void
+ * RETURN
+ *    OK: STATUS_OK
+ *    NG: STATUS_ERROR
+ *--------------------------------------------------------------------
+ */
+int
+PGRload_balance(void)
+{
+	char * func = "PGRload_balance()";
+	pid_t pid,pgid;
+	int count;
+	int status;
+	ClusterTbl * cluster_p = NULL;
+
+	signal(SIGCHLD, PGRchild_wait);
+	/* get the least locaded cluster server info */
+	cluster_p = PGRscan_cluster();
+	count = 0;
+	while (cluster_p == NULL )
+	{
+		if ( count > PGLB_CONNECT_RETRY_TIME)
+		{
+			show_error("%s:no cluster available",func);
+			return STATUS_ERROR;
+		}
+		cluster_p = PGRscan_cluster();
+		count ++;
+	}
+
+	pgid = getpgid((pid_t)0);
+	pid = fork();
+	if (pid < 0)
+	{
+		show_error("%s:fork() failed. (%s)",func,strerror(errno));
+		exit(1);
+	}
+	if (pid == 0)
+	{
+		setpgid((pid_t)0,pgid);
+		CurrentCluster = cluster_p;
+
+		if (pool_init_cp())
+		{
+			show_error("%s:pool_init_cp failed",func);
+			exit(1);
+		}
+		PGRsem_lock(ClusterSemid,cluster_p->rec_no);
+		if (PGRget_child_status(getpid()) == STATUS_ERROR)
+		{
+			PGRadd_child_tbl(cluster_p, getpid(), TBL_USE);
+		}
+		PGRsem_unlock(ClusterSemid,cluster_p->rec_no);
+		PGRdo_child(NOT_USE_CONNECTION_POOL );
+		PGRrelease_connection(cluster_p);
+		PGRset_status_to_child_tbl(getpid(), TBL_FREE);
+		pool_finish();
+		exit(0);
+	}
+	else if (pid > 0)
+	{
+		PGRsem_lock(ClusterSemid,cluster_p->rec_no);
+		if (PGRget_child_status(pid) == STATUS_ERROR)
+		{
+			PGRadd_child_tbl(cluster_p, pid, TBL_USE);
+		}
+		PGRsem_unlock(ClusterSemid,cluster_p->rec_no);
+		status = PGRget_child_status(pid);
+		while (status == TBL_USE)
+		{
+			status = PGRget_child_status(pid);
+			usleep(20);
+		}
+		return STATUS_OK;
+	}
+	else
+	{
+		return STATUS_ERROR;
+	}
+}
+
+/*--------------------------------------------------------------------
+ * SYMBOL
+ *    PGRload_balance_with_pool()
+ * NOTES
+ *    load balance module that connection pooling system is used
+ * ARGS
+ *    void
+ * RETURN
+ *    OK: STATUS_OK
+ *    NG: STATUS_ERROR
+ *--------------------------------------------------------------------
+ */
+int
+PGRload_balance_with_pool(void)
+{
+	char * func = "PGRload_balance_with_pool()";
+	int count;
+	pid_t pid;
+	ClusterTbl * cluster_p = NULL;
+	int status = TBL_USE;
+
+	/* get the least locaded cluster server info */
+	cluster_p = PGRscan_cluster();
+	count = 0;
+	while (cluster_p == NULL )
+	{
+		if ( count > PGLB_CONNECT_RETRY_TIME)
+		{
+			show_error("%s:no cluster available",func);
+			PGRreturn_connection_full_error();
+			return STATUS_ERROR;
+		}
+		cluster_p = PGRscan_cluster();
+		count ++;
+	}
+	pid = PGRscan_child_tbl(cluster_p);
+	if ((pid == 0) || (pid == STATUS_ERROR))
+	{
+		show_error("%s:no child process available",func);
+		return STATUS_ERROR;
+	}
+	kill(pid,SIGUSR1);
+
+	status = PGRget_child_status(pid);
+	while (status == TBL_USE)
+	{
+		status = PGRget_child_status(pid);
+		usleep(20);
+	}
+
+	return STATUS_OK;
+
+}
+
+char
+PGRis_connection_full(ClusterTbl * ptr)
+{
+	char rtn = 1;
+
+	if (ptr == NULL)
+	{
+		return rtn;
+	}
+	PGRsem_lock(ClusterSemid,ptr->rec_no);
+	if (ptr->max_connect > ptr->use_num)
+	{
+		rtn = 0;
+	}
+	PGRsem_unlock(ClusterSemid,ptr->rec_no);
+	return rtn;
+}
+
+void
+PGRrelease_connection(ClusterTbl * ptr)
+{
+	if (ptr == NULL)
+	{
+		return;
+	}
+	PGRsem_lock(ClusterSemid,MAX_DB_SERVER);
+	if (ptr->use_num > 0)
+	{
+		ptr->use_num --;
+	}
+	PGRsem_unlock(ClusterSemid,MAX_DB_SERVER);
+}
+#endif /* USE_REPLICATION */
diff -ruN postgresql-7.4.13-old/src/pgcluster/pglb/main.c postgresql-7.4.13/src/pgcluster/pglb/main.c
--- postgresql-7.4.13-old/src/pgcluster/pglb/main.c	1970-01-01 01:00:00.000000000 +0100
+++ postgresql-7.4.13/src/pgcluster/pglb/main.c	2006-08-05 16:53:43.000000000 +0200
@@ -0,0 +1,1022 @@
+/*--------------------------------------------------------------------
+ * FILE:
+ *     main.c
+ *
+ * NOTE:
+ *     This file is composed of the main function of pglb.
+ *
+ * Portions Copyright (c) 2003, Atsushi Mitani
+ *--------------------------------------------------------------------
+ */
+/*
+ * 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.
+ *
+*/
+#ifdef USE_REPLICATION
+
+#include "postgres.h"
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sys/wait.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <sys/sem.h>
+#include <sys/msg.h>
+#include <netdb.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/time.h>
+#include <time.h>
+#include <sys/param.h>
+#include <sys/select.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/file.h>
+#include <arpa/inet.h>
+
+#ifdef HAVE_NETINET_TCP_H
+#include <netinet/tcp.h>
+#endif
+
+#ifdef HAVE_CRYPT_H
+#include <crypt.h>
+#endif
+
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#endif
+
+#include "replicate_com.h"
+#include "pglb.h"
+
+#define IPC_NMAXSEM (32)
+/*--------------------------------------
+ * GLOBAL VARIABLE DECLARATION
+ *--------------------------------------
+ */
+
+/* for replicate_com.h */
+PGR_Com_Info Com_Info;
+
+int Recv_Port_Number = 0;
+int Use_Connection_Pool = 0;
+int Max_Pool = 1;
+int Connection_Life_Time = 0;
+int Max_DB_Server = 0;
+int MaxBackends = 0;
+ClusterTbl * Cluster_Tbl = (ClusterTbl *)NULL;
+int ClusterNum = 0;
+int ClusterShmid = 0;
+int ClusterSemid = 0;
+ChildTbl * Child_Tbl = (ChildTbl *)NULL;
+int ChildShmid = 0;
+char * PGR_Data_Path = NULL;
+char * PGR_Write_Path = NULL;
+char * Backend_Socket_Dir = NULL;
+FrontSocket Frontend_FD;
+ClusterTbl * CurrentCluster = NULL;
+
+extern char *optarg;
+
+/*--------------------------------------
+ * PROTOTYPE DECLARATION
+ *--------------------------------------
+ */
+int init_pglb(char * path);
+static void pglb_exit(int signal_args);
+static void load_balance_main(void);
+static void daemonize(void);
+static void write_pid_file(void);
+static void stop_pglb(void);
+static int is_exist_pid_file(void);
+static ClusterTbl * scan_cluster_by_pid(pid_t pid);
+static void usage(void);
+static void close_child(int signal_args);
+
+void PGRrecreate_child(int signal_args);
+
+/*--------------------------------------------------------------------
+ * SYMBOL
+ *    init_pglb()
+ * NOTES
+ *    Reading of the setup file
+ *    and the initialization of the memory area.
+ * ARGS
+ *    char * path: path of the setup file (I)
+ * RETURN
+ *    OK: STATUS_OK
+ *    NG: STATUS_ERROR
+ *--------------------------------------------------------------------
+ */
+int
+init_pglb(char * path)
+{
+	char * func = "init_pglb()";
+
+	ConfDataType * conf;
+	ClusterTbl cluster_tbl[MAX_DB_SERVER];
+	int size = 0;
+	int rec_no = 0;
+	int i;
+	int max_connect = 0;
+	union semun sem_arg;
+	char fname[256];
+
+	/*
+	 * read configuration file
+	 */
+	if (path == NULL)
+	{
+		path = ".";
+	}
+	if (PGR_Get_Conf_Data(path,PGLB_CONF_FILE) != STATUS_OK)
+	{
+		show_error("%s:PGR_Get_Conf_Data failed",func);
+		return STATUS_ERROR;
+	}
+	
+	/* cluster db status file open */
+	if (Com_Info.Log_Info.PGRStatusFileName == NULL)
+	{
+		snprintf(fname,sizeof(fname),"%s/%s",PGR_Write_Path,PGLB_STATUS_FILE);
+	}
+	else
+	{
+		strncpy(fname,Com_Info.Log_Info.PGRStatusFileName,sizeof(fname));
+	}
+	Com_Info.Log_Info.StatusFp = fopen(fname, "a");
+	if (Com_Info.Log_Info.StatusFp == NULL)
+	{
+		show_error("%s:open() %s file failed. (%s)",
+				   func,fname, strerror(errno));
+		exit(1);
+	}
+	/* pglb log file open */
+	if (Com_Info.Log_Info.Log_Print)
+	{
+		if (Com_Info.Log_Info.PGRLogFileName == NULL)
+		{
+			snprintf(fname,sizeof(fname),"%s/%s",PGR_Write_Path,PGLB_LOG_FILE);
+		}
+		else
+		{
+			strncpy(fname,Com_Info.Log_Info.PGRLogFileName,sizeof(fname));
+		}
+		Com_Info.Log_Info.LogFp = fopen(fname,"a");
+		if (Com_Info.Log_Info.LogFp == NULL)
+		{
+			show_error("%s:fopen failed: (%s)",func,strerror(errno));
+			exit(1);
+		}
+#ifdef PRINT_DEBUG
+		show_debug("%s:%s open ok",func,fname);
+#endif			
+	}
+
+	Backend_Socket_Dir = malloc(128);
+	if (Backend_Socket_Dir == NULL)
+	{
+		show_error("%s:malloc() failed. (%s)",func,strerror(errno));
+		return STATUS_ERROR;
+	}
+	memset(Backend_Socket_Dir,0,128);
+	/* set initiarize data */
+	strcpy(Backend_Socket_Dir,"/tmp");
+	Max_Pool = 1;
+	Connection_Life_Time = 0;
+	Use_Connection_Pool = 0;
+
+	conf = Com_Info.ConfData_Info.ConfData_Top;
+	while (conf != (ConfDataType *)NULL) 
+	{
+		/* get cluster db servers name */
+		if (!strcmp(conf->table,CLUSTER_SERVER_TAG))
+		{
+			rec_no = conf->rec_no;
+			if (!strcmp(conf->key,HOST_NAME_TAG))
+			{
+				strncpy(cluster_tbl[rec_no].hostName,conf->value,sizeof(cluster_tbl[rec_no].hostName));
+				conf = (ConfDataType*)conf->next;
+				continue;
+			}
+			if (!strcmp(conf->key,PORT_TAG))
+			{
+				cluster_tbl[rec_no].port = atoi(conf->value);
+				conf = (ConfDataType*)conf->next;
+				continue;
+			}
+			if (!strcmp(conf->key,MAX_CONNECT_TAG))
+			{
+				cluster_tbl[rec_no].max_connect = atoi(conf->value);
+				conf = (ConfDataType*)conf->next;
+				continue;
+			}
+		}
+		else
+		{
+			/* get port number for receive querys */
+			if (!strcmp(conf->key,RECV_PORT_TAG))
+			{
+				Recv_Port_Number = atoi(conf->value);
+				conf = (ConfDataType*)conf->next;
+				continue;
+			}
+			/* get port number for recovery session */
+			if (!strcmp(conf->key,RECOVERY_PORT_TAG))
+			{
+				Com_Info.ConfData_Info.Recovery_Port_Number = atoi(conf->value);
+				conf = (ConfDataType*)conf->next;
+				continue;
+			}
+			if (!STRCMP(conf->key,LIFECHECK_PORT_TAG))
+			{
+				Com_Info.ConfData_Info.LifeCheck_Port_Number = atoi(conf->value);
+				conf = (ConfDataType*)conf->next;
+				continue;
+			}
+			if (!STRCMP(conf->key,STATUS_LOG_FILE_TAG))
+			{
+				Com_Info.Log_Info.PGRStatusFileName = strdup(conf->value);
+				conf = (ConfDataType*)conf->next;
+				continue;
+			}
+			if (!STRCMP(conf->key,ERROR_LOG_FILE_TAG))
+			{
+				Com_Info.Log_Info.PGRLogFileName = strdup(conf->value);
+				conf = (ConfDataType*)conf->next;
+				continue;
+			}
+			if (!strcmp(conf->key,MAX_CLUSTER_TAG))
+			{
+				Max_DB_Server = atoi(conf->value);
+				conf = (ConfDataType*)conf->next;
+				continue;
+			}
+			if (!strcmp(conf->key,USE_CONNECTION_POOL_TAG))
+			{
+				if (!strcmp(conf->value,"yes"))
+				{
+					Use_Connection_Pool = 1;
+				}
+				conf = (ConfDataType*)conf->next;
+				continue;
+			}
+			if (!strcmp(conf->key,MAX_POOL_TAG))
+			{
+				Max_Pool = atoi(conf->value);
+				if (Max_Pool < 0)
+					Max_Pool = 1;
+				conf = (ConfDataType*)conf->next;
+				continue;
+			}
+			if (!strcmp(conf->key,CONNECTION_LIFE_TIME))
+			{
+				Connection_Life_Time = atoi(conf->value);
+				if (Connection_Life_Time < 0)
+					Connection_Life_Time = 0;
+				conf = (ConfDataType*)conf->next;
+				continue;
+			}
+			if (!strcmp(conf->key,BACKEND_SOCKET_DIR_TAG))
+			{
+				strncpy(Backend_Socket_Dir,conf->value,128);
+				conf = (ConfDataType*)conf->next;
+				continue;
+			}
+		}
+		conf = (ConfDataType*)conf->next;
+	}
+	if (Max_DB_Server <= 0)
+	{
+		show_error("%s:Max_DB_Server is wrong value. %s/%s file should be broken",func, path, PGLB_CONF_FILE);
+		exit(1);
+	}
+	/* shared memory allocation for cluster table */
+	size = sizeof(ClusterTbl) * Max_DB_Server;
+
+	ClusterShmid = shmget(IPC_PRIVATE,size,IPC_CREAT | IPC_EXCL | 0600);
+	if (ClusterShmid < 0)
+	{
+		show_error("%s:ClusterShm shmget() failed. (%s)", func,strerror(errno));
+		return STATUS_ERROR;
+	}
+	Cluster_Tbl = (ClusterTbl *)shmat(ClusterShmid,0,0);
+	if (Cluster_Tbl == (ClusterTbl *)-1)
+	{
+		show_error("%s:shmat() failed. (%s)", func,strerror(errno));
+		return STATUS_ERROR;
+	}
+	if ((ClusterSemid = semget(IPC_PRIVATE,MAX_DB_SERVER+1,IPC_CREAT | IPC_EXCL | 0600)) < 0)
+	{
+		show_error("%s:semget() failed. (%s)",func,strerror(errno));
+		return STATUS_ERROR;
+	}
+	for ( i = 0 ; i <= MAX_DB_SERVER ; i ++)
+	{
+		semctl(ClusterSemid, i, GETVAL, sem_arg);
+		sem_arg.val = 1;
+		semctl(ClusterSemid, i, SETVAL, sem_arg);
+	}
+	ClusterNum = 0;
+	/* set cluster db server name into cluster db server table */
+	for ( i = 0 ; i < Max_DB_Server ; i ++)
+	{
+		(Cluster_Tbl + i)->rec_no = i;
+	}
+	(Cluster_Tbl + i)->useFlag = TBL_END;
+	max_connect = 0;
+	for ( i = 0 ; i <= rec_no ; i ++)
+	{
+		cluster_tbl[i].use_num = 0;
+		cluster_tbl[i].rate = 0;
+		if (cluster_tbl[i].max_connect < 0)
+		{
+			cluster_tbl[i].max_connect = 0;
+		}
+		if (max_connect < cluster_tbl[i].max_connect)
+		{
+			max_connect = cluster_tbl[i].max_connect;
+		}
+		PGRadd_cluster_tbl(&cluster_tbl[i]);
+	}
+
+	/* shared memory allocation for children table */
+	size = sizeof(ChildTbl) * (Max_DB_Server + 1) * max_connect * Max_Pool;
+#ifdef PRINT_DEBUG
+	show_debug("%s:Child_Tbl size is[%d]",func,size);
+#endif			
+
+	ChildShmid = shmget(IPC_PRIVATE,size,IPC_CREAT | IPC_EXCL | 0600);
+	if (ChildShmid < 0)
+	{
+		show_error("%s:ChildShm shmget() failed. (%s)",func, strerror(errno));
+		return STATUS_ERROR;
+	}
+	Child_Tbl = (ChildTbl *)shmat(ChildShmid,0,0);
+	if (Child_Tbl == (ChildTbl *)-1)
+	{
+		show_error("%s:shmat() failed. (%s)", func,strerror(errno));
+		return STATUS_ERROR;
+	}
+	memset(Child_Tbl, 0, size);
+	(Child_Tbl + ( Max_DB_Server * max_connect * Max_Pool) -1)->useFlag = TBL_END;
+
+	PGR_Free_Conf_Data();
+
+	return STATUS_OK;
+}
+
+/*--------------------------------------------------------------------
+ * SYMBOL
+ *    pglb_exit()
+ * NOTES
+ *    Closing of pglb process
+ * ARGS
+ *    int signal_args: signal number (I)
+ * RETURN
+ *    none
+ *--------------------------------------------------------------------
+ */
+static void
+pglb_exit(int signal_args)
+{
+	char fname[256];
+	int rtn;
+	
+	Child_Tbl->useFlag = TBL_END;
+	signal(SIGCHLD,SIG_IGN);
+	signal(signal_args,SIG_IGN);
+	kill (0,signal_args);
+	while (wait(NULL) > 0 )
+		;
+
+	if (ClusterShmid > 0)
+	{
+		rtn = shmdt(Cluster_Tbl);
+		shmctl(ClusterShmid,IPC_RMID,(struct shmid_ds *)NULL);
+		ClusterShmid = 0;
+		Cluster_Tbl = NULL;
+	}
+	if (ChildShmid > 0)
+	{
+		rtn = shmdt(Child_Tbl);
+		shmctl(ChildShmid,IPC_RMID,(struct shmid_ds *)NULL);
+		ChildShmid = 0;
+		Child_Tbl = NULL;
+	}
+	if (ClusterSemid > 0)
+	{
+		semctl(ClusterSemid, 0, IPC_RMID);
+	}
+	snprintf(fname, sizeof(fname), "%s/%s", PGR_Write_Path, PGLB_PID_FILE);
+	unlink(fname);
+	
+	if (Com_Info.Log_Info.StatusFp != NULL)
+	{
+		fflush(Com_Info.Log_Info.StatusFp);
+		fclose(Com_Info.Log_Info.StatusFp);
+	}
+	if (Com_Info.Log_Info.LogFp != NULL)
+	{
+		fflush(Com_Info.Log_Info.LogFp);
+		fclose(Com_Info.Log_Info.LogFp);
+	}
+	if (Frontend_FD.unix_fd != 0)
+	{
+		close(Frontend_FD.unix_fd);
+		snprintf(fname, sizeof(fname), "%s/.s.PGSQL.%d", Backend_Socket_Dir,Recv_Port_Number);
+		unlink(fname);
+	}
+	if (Frontend_FD.inet_fd != 0)
+	{
+		close(Frontend_FD.inet_fd);
+	}
+	PGRsyn_quit();
+	snprintf(fname, sizeof(fname), "%s/%s", PGR_Write_Path, PGLB_PID_FILE);
+	unlink(fname);
+
+	exit(0);
+}
+
+/*--------------------------------------------------------------------
+ * SYMBOL
+ *    load_balance_main()
+ * NOTES
+ *    This is a main module of load balance function
+ * ARGS
+ *    void
+ * RETURN
+ *    none
+ *--------------------------------------------------------------------
+ */
+static void
+load_balance_main(void)
+{
+	char * func = "load_balance_main()";
+	int status;
+	int rtn;
+	int count = 0;
+
+	Frontend_FD.unix_fd = PGRcreate_unix_domain_socket(Backend_Socket_Dir, Recv_Port_Number);
+	if (Frontend_FD.unix_fd < 0)
+	{
+		show_error("%s:PGRcreate_unix_domain_socket failed",func);
+		pglb_exit(SIGTERM);
+	}
+	Frontend_FD.inet_fd = PGRcreate_recv_socket("", Recv_Port_Number);
+	if (Frontend_FD.inet_fd < 0)
+	{
+		show_error("%s:PGRcreate_recv_socket failed",func);
+		pglb_exit(SIGTERM);
+	}
+	if (Use_Connection_Pool)
+	{
+		signal(SIGCHLD,PGRrecreate_child);
+		rtn = PGRpre_fork_children(Cluster_Tbl);
+		if (rtn != STATUS_OK)
+		{
+			show_error("%s:PGRpre_fork_children failed",func);
+			pglb_exit(SIGTERM);
+		}
+	}
+	
+	for (;;)
+	{
+		fd_set	  rmask;
+		struct timeval timeout;
+
+		timeout.tv_sec = 60;
+		timeout.tv_usec = 0;
+
+		/*
+		 * Wait for something to happen.
+		 */
+		FD_ZERO(&rmask);
+		FD_SET(Frontend_FD.unix_fd,&rmask);
+		if(Frontend_FD.inet_fd)
+			FD_SET(Frontend_FD.inet_fd,&rmask);
+		rtn = select(Max(Frontend_FD.unix_fd, Frontend_FD.inet_fd) + 1, &rmask, (fd_set *)NULL, (fd_set *)NULL, &timeout);
+		if (rtn > 0)
+		{
+			if (Use_Connection_Pool)
+			{
+				status = PGRload_balance_with_pool();
+			}
+			else
+			{
+				status = PGRload_balance();
+			}
+			if (status != STATUS_OK)
+			{
+				show_error("%s:load balance process failed",func);
+				if ( count > PGLB_CONNECT_RETRY_TIME)
+				{
+					show_error("%s:no cluster available",func);
+					PGRreturn_connection_full_error();
+					count = 0;
+				}
+				count ++;
+			}
+			else
+			{
+				count = 0;
+			}
+		}
+	}
+}
+
+/*--------------------------------------------------------------------
+ * SYMBOL
+ *    daemonize()
+ * NOTES
+ *    Daemonize this process
+ * ARGS
+ *    void
+ * RETURN
+ *    none
+ *--------------------------------------------------------------------
+ */
+static void 
+daemonize(void)
+{
+	char *  func = "daemonize()";
+	int		i;
+	pid_t		pid;
+
+	pid = fork();
+	if (pid == (pid_t) -1)
+	{
+		show_error("%s:fork() failed. (%s)",func, strerror(errno));
+		exit(1);
+		return;					/* not reached */
+	}
+	else if (pid > 0)
+	{			/* parent */
+		exit(0);
+	}
+
+#ifdef HAVE_SETSID
+	if (setsid() < 0)
+	{
+		show_error("%s:setsid() failed. (%s)", func,strerror(errno));
+		exit(1);
+	}
+#endif
+
+	i = open("/dev/null", O_RDWR);
+	dup2(i, 0);
+	dup2(i, 1);
+	dup2(i, 2);
+	close(i);
+}
+
+
+/*--------------------------------------------------------------------
+ * SYMBOL
+ *    write_pid_file()
+ * NOTES
+ *    The process ID is written in the file.
+ *    This process ID is used when finish pglb.
+ * ARGS
+ *    void
+ * RETURN
+ *    none
+ *--------------------------------------------------------------------
+ */
+static void 
+write_pid_file(void)
+{
+	char * func = "write_pid_file()";
+	FILE *fd;
+	char fname[256];
+	char pidbuf[128];
+
+	snprintf(fname, sizeof(fname), "%s/%s", PGR_Write_Path, PGLB_PID_FILE);
+	fd = fopen(fname, "w");
+	if (!fd)
+	{
+		show_error("%s:open() %s file failed. (%s)",
+				   func,fname, strerror(errno));
+		exit(1);
+	}
+	snprintf(pidbuf, sizeof(pidbuf), "%d", getpid());
+	fwrite(pidbuf, strlen(pidbuf), 1, fd);
+	if (fclose(fd))
+	{
+		show_error("%s:fwrite() %s file failed. (%s)",
+				   func,fname, strerror(errno));
+		exit(1);
+	}
+}
+
+
+/*--------------------------------------------------------------------
+ * SYMBOL
+ *    stop_pglb()
+ * NOTES
+ *    Stop the pglb process
+ * ARGS
+ *    void
+ * RETURN
+ *    none
+ *--------------------------------------------------------------------
+ */
+static void 
+stop_pglb(void)
+{
+	char * func = "stop_pglb()";
+	FILE *fd;
+	char fname[256];
+	char pidbuf[128];
+	pid_t pid;
+
+	if (PGR_Write_Path == NULL)
+	{
+		PGR_Write_Path = ".";
+	}
+	snprintf(fname, sizeof(fname), "%s/%s", PGR_Write_Path, PGLB_PID_FILE);
+	fd = fopen(fname, "r");
+	if (!fd)
+	{
+		show_error("%s:open() %s file failed. (%s)",
+				   func,fname, strerror(errno));
+		exit(1);
+	}
+	memset(pidbuf,0,sizeof(pidbuf));
+	fread(pidbuf, sizeof(pidbuf), 1, fd);
+	fclose(fd);
+	pid = atoi(pidbuf);
+	if (kill (pid,SIGTERM) == -1)
+	{
+		show_error("%s:could not stop pid: %d (%s)",func,pid,strerror(errno));
+		exit(1);
+	}
+}
+
+
+/*--------------------------------------------------------------------
+ * SYMBOL
+ *    is_exist_pid_file()
+ * NOTES
+ *    Check existence of pid file.
+ * ARGS
+ *    void
+ * RETURN
+ *    1: the pid file is exist
+ *    0: the pid file is not exist
+ *--------------------------------------------------------------------
+ */
+static int
+is_exist_pid_file(void)
+{
+	char fname[256];
+	struct stat buf;
+
+	snprintf(fname, sizeof(fname), "%s/%s", PGR_Write_Path, PGLB_PID_FILE);
+	if (stat(fname,&buf) == 0)
+	{
+		/* pid file is exist */
+		return 1;
+	}
+	else
+	{
+		/* pid file is not exist */
+		return 0;
+	}
+}
+
+
+/*--------------------------------------------------------------------
+ * SYMBOL
+ *    PGRrecreate_child()
+ * NOTES
+ *    create the child process again which it hunged up
+ * ARGS
+ *    int signal_args: signal number (expecting the SIGCHLD)
+ * RETURN
+ *    none
+ *--------------------------------------------------------------------
+ */
+void
+PGRrecreate_child(int signal_args)
+{
+	pid_t pid = 0;
+	int status;
+	ClusterTbl * cluster_p;
+
+#ifdef HAVE_WAITPID
+	while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
+	{
+#else
+	while ((pid = wait3(&status, WNOHANG, NULL)) > 0)
+	{
+#endif
+		cluster_p = scan_cluster_by_pid(pid);
+		pid = PGRcreate_child(cluster_p);	
+	}
+}
+
+/*--------------------------------------------------------------------
+ * SYMBOL
+ *    close_child()
+ * NOTES
+ *    Hung up child process 
+ * ARGS
+ *    int signal_args: signal number (expecting the SIGUSR2)
+ * RETURN
+ *    none
+ *--------------------------------------------------------------------
+ */
+static void
+close_child(int signal_args)
+{
+	char * func = "close_child()";
+	ChildTbl * child;
+	ClusterTbl * cluster;
+	int rec_no = -1;
+
+	if (( Cluster_Tbl == NULL) || (Child_Tbl == NULL))
+	{
+		show_error("%s:Cluster_Tbl or Child_Tbl is not initialize",func);
+		return ;
+	}
+	cluster = Cluster_Tbl;
+	signal(SIGCHLD,SIG_IGN);
+	while(cluster->useFlag != TBL_END)
+	{
+		if (cluster->useFlag == TBL_ERROR_NOTICE) 
+		{
+			rec_no = cluster->rec_no;
+			PGRset_status_on_cluster_tbl(TBL_ERROR,cluster);
+			break;
+		}
+		cluster++;
+	}
+	if (rec_no < 0)
+	{
+		return;
+	}
+	child = Child_Tbl;
+	while(child->useFlag != TBL_END)
+	{
+		if ((child->rec_no == rec_no) && (child->pid > 0)) 
+		{
+			if (kill (child->pid,SIGTERM) == -1)
+			{
+				show_error("%s:could not stop pid: %d (%s)",func,child->pid,strerror(errno));
+				return;
+			}
+			PGRchild_wait(signal_args);
+			child->useFlag = DATA_FREE;
+			child->pid = 0;
+		}
+		child++;
+	}
+}
+
+/*--------------------------------------------------------------------
+ * SYMBOL
+ *    scan_cluster_by_pid()
+ * NOTES
+ *    get cluster server record from child process id
+ * ARGS
+ *    pid_t pid: child process id (I)
+ * RETURN
+ *    OK: pointer of cluster table
+ *    NG: NULL
+ *--------------------------------------------------------------------
+ */
+static ClusterTbl *
+scan_cluster_by_pid(pid_t pid)
+{
+	char * func = "scan_cluster_by_pid()";
+	ChildTbl * child_p;
+	ClusterTbl * cluster_p;
+	int cnt;
+
+	child_p = Child_Tbl;
+	if (child_p == NULL)
+	{
+		show_error("%s:Child Table is not initialize",func);
+		return NULL;
+	}
+	cluster_p = Cluster_Tbl;
+	if (cluster_p == NULL)
+	{
+		show_error("%s:Cluster Table is not initialize",func);
+		return NULL;
+	}
+	
+	while (child_p->useFlag != TBL_END)
+	{
+		if (child_p->pid == pid)
+		{
+			break;
+		}
+		child_p++;
+	}
+	if (child_p->useFlag == TBL_END)
+	{
+		show_error("%s:pid:%d not found in child table",func,pid);
+		return NULL;
+	}
+
+	cnt = 0;
+	while ((cluster_p->useFlag != TBL_END) && (cnt < ClusterNum))
+	{
+		if (cluster_p->rec_no == child_p->rec_no)
+		{
+			return cluster_p;
+		}
+		cluster_p++;
+		cnt ++;
+	}
+	return NULL;
+}
+
+/*--------------------------------------------------------------------
+ * SYMBOL
+ *    usage()
+ * NOTES
+ *    show usage of pglb
+ * ARGS
+ *    void
+ * RETURN
+ *    none
+ *--------------------------------------------------------------------
+ */
+static void
+usage(void)
+{
+	char * path;
+
+	path = getenv("PGDATA");
+	if (path == NULL)
+		path = ".";
+	fprintf(stderr,"pglb version [%s]\n",PGLB_VERSION);
+	fprintf(stderr,"A load balancer for PostgreSQL\n\n");
+	fprintf(stderr,"usage: pglb [-D path_of_config_file] [-W path_of_work_files] [-n][-v][-h][stop]\n");
+	fprintf(stderr,"    config file default path: %s/%s\n",path, PGLB_CONF_FILE);
+	fprintf(stderr,"    -l: print error logs in the log file.\n");
+	fprintf(stderr,"    -n: don't run in daemon mode.\n");
+	fprintf(stderr,"    -v: debug mode. need '-n' flag\n");
+	fprintf(stderr,"    -h: print this help\n");
+	fprintf(stderr,"    stop: stop pglb\n");
+}
+
+/*--------------------------------------------------------------------
+ * SYMBOL
+ *    main()
+ * NOTES
+ *    main module of pglb
+ * ARGS
+ *    int argc: number of parameter
+ *    char ** argv: value of parameter
+ * RETURN
+ *    none
+ *--------------------------------------------------------------------
+ */
+int
+main(int argc, char ** argv)
+{
+	int opt = 0;
+	pid_t pid,pgid;
+	char * r_path = NULL;
+	char * w_path = NULL;
+	int detach = 1;
+
+	/* init global variables */
+	PGR_Init_Com_Info(&Com_Info);
+
+	signal(SIGHUP, pglb_exit);
+	signal(SIGINT, pglb_exit);	
+	signal(SIGQUIT, pglb_exit);
+	signal(SIGTERM, pglb_exit);
+	signal(SIGALRM, SIG_IGN); /* ignored */
+	signal(SIGPIPE, SIG_IGN); /* ignored */
+	signal(SIGTTIN, SIG_IGN); /* ignored */
+	signal(SIGTTOU, SIG_IGN); /* ignored */
+	signal(SIGCHLD,PGRchild_wait);
+	signal(SIGUSR1, SIG_IGN); /* ignored */
+	signal(SIGUSR2, close_child); /* close child process */
+	r_path = getenv("PGDATA");
+	if (r_path == NULL)
+		r_path = ".";
+
+	while ((opt = getopt(argc, argv, "D:W:lvnh")) != -1)
+	{
+		switch (opt)
+		{
+			case 'D':
+				if (!optarg)
+				{
+					usage();
+					exit(1);
+				}
+				r_path = optarg;
+				break;
+			case 'W':
+				if (!optarg)
+				{
+					usage();
+					exit(1);
+				}
+				w_path = optarg;
+				break;
+			case 'l':
+				Com_Info.Log_Info.Log_Print = 1;
+				break;
+			case 'v':
+				Com_Info.Log_Info.Debug_Print = 1;
+				break;
+			case 'n':
+				detach = 0;
+				break;
+			case 'h':
+				usage();
+				exit(0);
+				break;
+			default:
+				usage();
+				exit(1);
+		}
+	}
+	PGR_Data_Path = r_path;
+	if (w_path == NULL)
+	{
+		PGR_Write_Path = PGR_Data_Path;
+	}
+	else
+	{
+		PGR_Write_Path = w_path;
+	}
+
+	if (optind == (argc-1) && !strcmp(argv[optind],"stop"))
+	{
+		stop_pglb();
+		exit(0);
+	}
+	else if (optind == argc)
+	{
+		if (is_exist_pid_file())
+		{
+			fprintf(stderr,"pid file %s/%s found. is another pglb running?", PGR_Write_Path, PGLB_PID_FILE);
+			exit(1);
+		}
+	}
+	else if (optind < argc)
+	{
+		usage();
+		exit(1);
+	}
+
+	if (detach)
+	{
+		daemonize();
+	}
+	write_pid_file();
+	
+	if (init_pglb(PGR_Data_Path) != STATUS_OK)
+	{
+		exit(0);
+	}
+
+	pgid = getpgid((pid_t)0);
+	pid = fork();
+	if (pid < 0)
+	{
+		pglb_exit(0);
+	}
+	if (pid == 0)
+	{
+		setpgid((pid_t)0,pgid);
+		PGRrecovery_main();
+		exit(0);
+	}
+	else
+	{
+		load_balance_main();
+	}
+	pglb_exit(0);
+	return STATUS_OK;
+}
+#else
+void main(){}
+#endif /* USE_REPLICATION */
diff -ruN postgresql-7.4.13-old/src/pgcluster/pglb/pglb.conf.sample postgresql-7.4.13/src/pgcluster/pglb/pglb.conf.sample
--- postgresql-7.4.13-old/src/pgcluster/pglb/pglb.conf.sample	1970-01-01 01:00:00.000000000 +0100
+++ postgresql-7.4.13/src/pgcluster/pglb/pglb.conf.sample	2006-08-05 16:53:43.000000000 +0200
@@ -0,0 +1,48 @@
+#============================================================
+#          Load Balance Server configuration file
+#-------------------------------------------------------------
+# file: pglb.conf
+#-------------------------------------------------------------
+# This file controls:
+#       o which hosts are db cluster server
+#       o which port  use connect to db cluster server
+#       o how many connections are allowed on each DB server
+#============================================================
+#-------------------------------------------------------------
+# set cluster DB server information
+#		o Host_Name : hostname
+#		o Port : connection for postmaster
+#		o Max_Connection : maximun number of connection to postmaster
+#-------------------------------------------------------------
+#<Cluster_Server_Info>
+#    <Host_Name>   master.postgres.jp  </Host_Name>
+#    <Port>        5432                </Port>
+#    <Max_Connect> 0                   </Max_Connect>
+#</Cluster_Server_Info>
+#<Cluster_Server_Info>
+#    <Host_Name>   post2.postgres.jp   </Host_Name>
+#    <Port>        5432                </Port>
+#    <Max_Connect> 32                  </Max_Connect>
+#</Cluster_Server_Info>
+#<Cluster_Server_Info>
+#    <Host_Name>   post3.postgres.jp   </Host_Name>
+#    <Port>        5432                </Port>
+#    <Max_Connect> 32                  </Max_Connect>
+#</Cluster_Server_Info>
+#-------------------------------------------------------------
+# set Load Balance server information
+#		o Backend_Socket_Dir : Unix domain socket path for the backend
+#		o Receive_Port : connection from client
+#		o Recovery_Port : connection for recovery process
+#		o LifeCheck_Port : connection for life check process
+#		o Max_Cluster_Num : maximun number of cluster DB servers
+#		o Use_Connection_Pooling : use connection pool [yes/no] 
+#		o Max_Pool_Each_Server : number of pool connections/DB server
+#-------------------------------------------------------------
+<Backend_Socket_Dir>    /tmp     </Backend_Socket_Dir>
+<Receive_Port>          5432     </Receive_Port>
+<Recovery_Port>         6101     </Recovery_Port>
+<LifeCheck_Port>        6201     </LifeCheck_Port>
+<Max_Cluster_Num>        128     </Max_Cluster_Num>
+<Use_Connection_Pooling>  no     </Use_Connection_Pooling>
+
diff -ruN postgresql-7.4.13-old/src/pgcluster/pglb/pglb.h postgresql-7.4.13/src/pgcluster/pglb/pglb.h
--- postgresql-7.4.13-old/src/pgcluster/pglb/pglb.h	1970-01-01 01:00:00.000000000 +0100
+++ postgresql-7.4.13/src/pgcluster/pglb/pglb.h	2006-08-05 16:53:43.000000000 +0200
@@ -0,0 +1,447 @@
+/*--------------------------------------------------------------------
+ * FILE:
+ *     pglb.h
+ *
+ * Portions Copyright (c) 2003-2005  Atsushi Mitani
+ *--------------------------------------------------------------------
+ */
+#ifndef PGLB_H
+#define PGLB_H
+
+#define PGLB_VERSION	"1.1.1a"
+
+extern PGR_Com_Info Com_Info;
+
+/*
+ * from pool.h
+ */
+
+/* 
+ * define this if you do not want to issue RESET ALL at each new
+ * connection.  Also you need to define this for 7.1 or prior
+ * PostgreSQL since they do not support RESET ALL
+ */
+#undef NO_RESET_ALL
+
+/* undef this if you have problems with non blocking accept() */
+#define NONE_BLOCK
+
+#define POOLMAXPATHLEN 8192
+
+/* configuration file name */
+#define POOL_CONF_FILE_NAME "pgpool.conf"
+
+/* pid file directory */
+#define DEFAULT_LOGDIR "/tmp"
+
+/* Unix domain socket directory */
+#define DEFAULT_SOCKET_DIR "/tmp"
+
+/* pid file name */
+#define PID_FILE_NAME "pgpool.pid"
+
+/* strict mode comment in SQL */
+#define STRICT_MODE_STR "/*STRICT*/"
+#define STRICT_MODE(s) (strncasecmp((s), STRICT_MODE_STR, strlen(STRICT_MODE_STR)) == 0)
+
+typedef enum {
+    POOL_CONTINUE = 0,
+	POOL_IDLE,
+    POOL_END,
+    POOL_ERROR,
+    POOL_FATAL
+} POOL_STATUS;
+
+/* protocol major version numbers */
+#define PROTO_MAJOR_V2	2
+#define PROTO_MAJOR_V3	3
+
+/*
+ * startup packet definitions (v2) stolen from PostgreSQL
+ */
+#define SM_DATABASE		64
+#define SM_USER			32
+#define SM_OPTIONS		64
+#define SM_UNUSED		64
+#define SM_TTY			64
+
+typedef struct PGR_StartupPacket_v2
+{
+	int			protoVersion;		/* Protocol version */
+	char		database[SM_DATABASE];	/* Database name */
+	char		user[SM_USER];	/* User name */
+	char		options[SM_OPTIONS];	/* Optional additional args */
+	char		unused[SM_UNUSED];		/* Unused */
+	char		tty[SM_TTY];	/* Tty for debug output */
+} PGR_StartupPacket_v2;
+
+/* startup packet info */
+typedef struct
+{
+	char *startup_packet;		/* raw startup packet without packet length (malloced area) */
+	int len;					/* raw startup packet length */
+	int major;	/* protocol major version */
+	int minor;	/* protocol minor version */
+	char *database;	/* database name in startup_packet (malloced area) */
+	char *user;	/* user name in startup_packet (malloced area) */
+} PGR_StartupPacket;
+
+typedef struct CancelPacket
+{
+	int			protoVersion;		/* Protocol version */
+	int			pid;	/* bcckend process id */
+	int			key;	/* cancel key */
+} CancelPacket;
+
+/*
+ * configuration paramters
+ */
+typedef struct {
+    int	inetdomain;	/* should we make an INET domain socket too? */
+    int	port;	/* port # to bind */
+	char *socket_dir;		/* pgpool socket directory */
+    char	*backend_host_name;	/* backend host name */
+    int	backend_port;	/* backend port # */
+    char	*secondary_backend_host_name;	/* secondary backend host name */
+    int	secondary_backend_port;	/* secondary backend port # */
+    int	num_init_children;	/* # of children initially pre-forked */
+    int	child_life_time;	/* if idle for this seconds, child exits */
+    int	connection_life_time;	/* if idle for this seconds, connection closes */
+    int	max_pool;	/* max # of connection pool per child */
+    char *logdir;		/* logging directory */
+    char *backend_socket_dir;	/* Unix domain socket directory for the PostgreSQL server */
+	int replication_mode;		/* replication mode */
+	int replication_strict;	/* if non 0, wait for completion of the
+                               query sent to master to avoid deadlock */
+	/*
+	 * if secondary does not respond in this milli seconds, abort this session.
+	 * this is not compatible with replication_strict = 1. 0 means no timeout.
+	 */
+	int replication_timeout;
+
+	int load_balance_mode;		/* load balance mode */
+
+	/* followings do not exist in the configuration file */
+    char	*current_backend_host_name;	/* current backend host name */
+    int	current_backend_port;	/* current backend port # */
+	int replication_enabled;		/* replication mode enabled */
+
+	int replication_stop_on_mismatch;		/* if there's a data mismatch between master and secondary
+											 * start degenration to stop replication mode
+											 */
+} POOL_CONFIG;
+
+#define MAX_PASSWORD_SIZE		(1024)
+
+typedef struct {
+	int num;	/* number of entries */
+	char **names;		/* parameter names */
+	char **values;		/* values */
+} ParamStatus;
+
+/*
+ * stream connection structure
+ */
+typedef struct {
+	int fd;		/* fd for connection */
+	FILE *write_fd;	/* stream write connection */
+
+	char *hp;	/* pending data buffer head address */
+	int po;		/* pending data offset */
+	int bufsz;	/* pending data buffer size */
+	int len;	/* pending data length */
+
+	char *sbuf;	/* buffer for pool_read_string */
+	int sbufsz;	/* its size in bytes */
+
+	char *buf2;	/* buffer for pool_read2 */
+	int bufsz2;	/* its size in bytes */
+
+	int isbackend;		/* this connection is for backend if non 0 */
+	int issecondary_backend;		/* this connection is for secondary backend if non 0 */
+
+	char tstate;		/* transaction state (V3 only) */
+
+	/*
+	 * following are used to remember when re-use the authenticated connection
+	 */
+	int auth_kind;		/* 3: clear text password, 4: crypt password, 5: md5 password */
+	int pwd_size;		/* password (sent back from frontend) size in host order */
+	char password[MAX_PASSWORD_SIZE];		/* password (sent back from frontend) */
+	char salt[4];		/* password salt */
+
+	/*
+	 * following are used to remember current session paramter status.
+	 * re-used connection will need them (V3 only)
+	 */
+	ParamStatus params;
+
+	int no_forward;		/* if non 0, do not write to frontend */
+
+} POOL_CONNECTION;
+
+/*
+ * connection pool structure
+ */
+typedef struct {
+	PGR_StartupPacket *sp;	/* startup packet info */
+    int pid;	/* backend pid */
+    int key;	/* cancel key */
+    POOL_CONNECTION	*con;
+	time_t closetime;	/* absolute time in second when the connection closed
+						 * if 0, that means the connection is under use.
+						 */
+} POOL_CONNECTION_POOL_SLOT;
+
+#define MAX_CONNECTION_SLOTS 2
+
+typedef struct {
+    int num;	/* number of slots */
+    POOL_CONNECTION_POOL_SLOT	*slots[MAX_CONNECTION_SLOTS];
+} POOL_CONNECTION_POOL;
+
+#define MASTER_CONNECTION(p) ((p)->slots[0])
+#define SECONDARY_CONNECTION(p) ((p)->slots[1])
+#define MASTER(p) MASTER_CONNECTION(p)->con
+#define SECONDARY(p) SECONDARY_CONNECTION(p)->con
+#define MAJOR(p) MASTER_CONNECTION(p)->sp->major
+#define TSTATE(p) MASTER(p)->tstate
+
+#define Max(x, y)		((x) > (y) ? (x) : (y))
+#define Min(x, y)		((x) < (y) ? (x) : (y))
+
+/*
+ * pglb
+ */
+
+typedef struct {
+	int useFlag;
+	int sock;
+}SocketTbl;
+
+typedef struct {
+	int useFlag;
+	char hostName[HOSTNAME_MAX_LENGTH];
+	unsigned short port;
+	short max_connect;
+	int use_num;
+	int rate;
+	int rec_no;
+}ClusterTbl;
+
+typedef struct {
+	long mtype;
+	char mdata[1];
+}MsgData;
+
+typedef struct {
+	int useFlag;
+	int rec_no;
+	pid_t pid;
+}ChildTbl;
+
+#define UNIX_DOMAIN_FD	(0)
+#define INET_DOMAIN_FD	(1)
+typedef struct {
+	int unix_fd;
+	int inet_fd;
+}FrontSocket;
+
+#define pool_config_inetdomain	(0)
+#define pool_config_replication_mode	(0)
+#define pool_config_replication_strict	(0)
+#define pool_config_replication_timeout	(0)
+#define pool_config_replication_enabled	(0)
+#define pool_config_load_balance_mode	(0)
+#define pool_config_replication_stop_on_mismatch	(0)
+#define pool_config_port	(Recv_Port_Number)
+#define pool_config_socket_dir	(Backend_Socket_Dir)
+#define pool_config_backend_host_name	(CurrentCluster->hostName)
+#define pool_config_backend_port	(CurrentCluster->port)
+#define pool_config_secondary_backend_host_name	(CurrentCluster->hostName)
+#define pool_config_secondary_backend_port	(CurrentCluster->port)
+#define pool_config_num_init_children	(CurrentCluster->max_connect)
+#define pool_config_child_life_time	(Connection_Life_Time)
+#define pool_config_connection_life_time	(Connection_Life_Time)
+#define pool_config_max_pool	(Max_Pool)
+#define pool_config_logdir	"./"
+#define pool_config_backend_socket_dir	(Backend_Socket_Dir)
+#define pool_config_current_backend_host_name	(CurrentCluster->hostName)
+#define pool_config_current_backend_port	(CurrentCluster->port)
+#define REPLICATION (0)
+#define IN_LOAD_BALANCE (0)
+
+/*
+ * for pglb
+ */
+#define MAX_DB_SERVER	(32)
+#define PGLB_MAX_SOCKET_QUEUE (10000)
+#define	CLUSTER_TBL_SHM_KEY	(1010)
+#define PGLB_CONNECT_RETRY_TIME  (3)
+#define DEFAULT_CONNECT_NUM	(32)
+#define DEFAULT_PORT	(5432)
+#define BUF_SIZE	(16384)
+#define TBL_FREE	(0)
+#define TBL_INIT	(1)
+#define TBL_USE		(2)
+#define TBL_STOP	(3)
+#define TBL_ACCEPT	(10)
+#define TBL_ERROR_NOTICE	(98)
+#define TBL_ERROR	(99)
+#define TBL_END	(-1)
+#define STATUS_OK	(0)
+#define STATUS_ERROR	(-1)
+#ifdef	RECOVERY_PREPARE_REQ
+#define ADD_DB		RECOVERY_PREPARE_REQ
+#else
+#define ADD_DB		(1)
+#endif
+#ifdef	RECOVERY_PGDATA_ANS
+#define STOP_DB		RECOVERY_PGDATA_ANS
+#else
+#define STOP_DB		(3)
+#endif
+#ifdef	RECOVERY_FINISH
+#define START_DB	RECOVERY_FINISH
+#else
+#define START_DB	(9)
+#endif
+#define DELETE_DB	(99)
+#define QUERY_TERMINATE	(0x00)
+#define RESPONSE_TERMINATE	(0x5a)
+#define PGLB_CONF_FILE	"pglb.conf"
+#define PGLB_PID_FILE	"pglb.pid"
+#define PGLB_STATUS_FILE "pglb.sts"
+#define PGLB_LOG_FILE "pglb.log"
+#define CLUSTER_SERVER_TAG	"Cluster_Server_Info"
+#define MAX_CONNECT_TAG	"Max_Connect"
+#define RECOVERY_PORT_TAG	"Recovery_Port"
+#define RECV_PORT_TAG	"Receive_Port"
+#define MAX_CLUSTER_TAG	"Max_Cluster_Num"
+#define USE_CONNECTION_POOL_TAG "Use_Connection_Pooling"
+#define MAX_POOL_TAG	"Max_Pool_Each_Server"
+#define BACKEND_SOCKET_DIR_TAG	"Backend_Socket_Dir"
+#define CONNECTION_LIFE_TIME	"Connection_Life_Time"
+#define NOT_USE_CONNECTION_POOL	(0)
+#define USE_CONNECTION_POOL	(1)
+
+extern int Recv_Port_Number;
+extern uint16_t LifeCheck_Port_Number;
+extern int Use_Connection_Pool;
+extern int Max_Pool;
+extern int Connection_Life_Time;
+extern int Msg_Id;
+extern ClusterTbl * Cluster_Tbl;
+extern int Max_DB_Server;
+extern int MaxBackends;
+extern char * Backend_Socket_Dir;
+extern int ClusterShmid;
+extern int ClusterSemid;
+extern int ChildShmid;
+extern int ClusterNum;
+extern ChildTbl * Child_Tbl;
+extern char * PGR_Data_Path;
+extern char * PGR_Write_Path;
+extern char * Backend_Socket_Dir;
+extern FrontSocket Frontend_FD;
+
+/* for child.c */
+extern POOL_CONNECTION * Frontend;
+extern ClusterTbl * CurrentCluster;
+
+extern char * Function;
+
+extern POOL_CONNECTION_POOL *pool_connection_pool;	/* connection pool */
+
+/* extern of main.c */
+extern void PGRrecreate_child(int signal_args);
+
+/* extern of child.c */
+extern int PGRpre_fork_children(ClusterTbl * ptr);
+extern int PGRpre_fork_child(ClusterTbl * ptr);
+extern int PGRdo_child( int use_pool);
+extern int PGRcreate_child(ClusterTbl * cluster_p);
+extern pid_t PGRscan_child_tbl(ClusterTbl * cluster_p);
+extern void notice_backend_error(void);
+extern void do_pooling_child(int sig);
+extern int PGRset_status_to_child_tbl(pid_t pid, int status);
+extern int PGRadd_child_tbl(ClusterTbl * cluster_p, pid_t pid, int status);
+extern int PGRget_child_status(pid_t pid);
+extern void PGRreturn_connection_full_error(void);
+extern void PGRquit_children_on_cluster(int rec_no);
+
+/* extern of cluster_table.c */
+extern ClusterTbl * PGRscan_cluster(void);
+extern void PGRset_key_of_cluster(ClusterTbl * ptr, RecoveryPacket * packet);
+extern ClusterTbl * PGRadd_cluster_tbl (ClusterTbl * conf_data);
+extern ClusterTbl * PGRset_status_on_cluster_tbl (int status, ClusterTbl * ptr);
+extern ClusterTbl * PGRsearch_cluster_tbl(ClusterTbl * conf_data);
+
+/* extern of load_balance.c */
+extern int PGRload_balance(void);
+extern int PGRload_balance_with_pool(void);
+extern char PGRis_connection_full(ClusterTbl * ptr);
+extern void PGRuse_connection(ClusterTbl * ptr);
+extern void PGRrelease_connection(ClusterTbl * ptr);
+
+/* extern of recovery.c */
+extern void PGRrecovery_main(void);
+
+/* extern of socket.c */
+extern int PGRcreate_unix_domain_socket(char * sock_dir, unsigned short port);
+extern int PGRcreate_recv_socket(char * hostName , unsigned short portNumber);
+extern int PGRcreate_acception(int fd, char * hostName , unsigned short portNumber);
+extern void PGRclose_sock(int * sock);
+extern int PGRread_byte(int sock,char * buf,int len, int flag);
+extern int PGRcreate_cluster_socket( int * sock, ClusterTbl * ptr );
+
+/* extern of pool_auth.c */
+extern int pool_do_auth(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *cp);
+extern int pool_do_reauth(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *cp);
+extern int pool_read_message_length(POOL_CONNECTION_POOL *cp);
+extern signed char pool_read_kind(POOL_CONNECTION_POOL *cp);
+
+/* extern of pool_connection_pool.c */
+extern int pool_init_cp(void);
+extern POOL_CONNECTION_POOL *pool_get_cp(char *user, char *database, int protoMajor);
+extern void pool_discard_cp(char *user, char *database, int protoMajor);
+extern POOL_CONNECTION_POOL *pool_create_cp(void);
+extern void pool_connection_pool_timer(POOL_CONNECTION_POOL *backend);
+extern void pool_backend_timer_handler(int sig);
+extern int connect_inet_domain_socket(int secondary_backend);
+extern int connect_unix_domain_socket(int secondary_backend);
+extern char PGRis_same_host(char * host1, char * host2);
+extern void pool_finish(void);
+extern void pool_clear(void);
+
+/* extern of pool_process_query.c */
+extern POOL_STATUS pool_process_query(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend, int connection_reuse);
+extern POOL_STATUS ErrorResponse(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend);
+extern void pool_enable_timeout(); 
+extern void pool_disable_timeout();
+extern int pool_check_fd(POOL_CONNECTION *cp, int notimeout);
+extern void pool_send_frontend_exits(POOL_CONNECTION_POOL *backend);
+extern POOL_STATUS SimpleForwardToFrontend(char kind, POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend);
+extern POOL_STATUS SimpleForwardToBackend(char kind, POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend);
+extern POOL_STATUS ParameterStatus(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend);
+extern void pool_send_error_message(POOL_CONNECTION *frontend, int protoMajor, char *code, char *message, char *detail, char *hint, char *file, int line);
+
+/* extern of pool_params.c */
+extern int pool_init_params(ParamStatus *params);
+extern void pool_discard_params(ParamStatus *params);
+extern char *pool_find_name(ParamStatus *params, char *name, int *pos);
+extern int pool_get_param(ParamStatus *params, int index, char **name, char **value);
+extern int pool_add_param(ParamStatus *params, char *name, char *value);
+extern void pool_param_debug_print(ParamStatus *params);
+
+/* extern of pool_stream.c */
+extern POOL_CONNECTION *pool_open(int fd);
+extern void pool_close(POOL_CONNECTION *cp);
+extern int pool_read(POOL_CONNECTION *cp, void *buf, int len);
+extern char *pool_read2(POOL_CONNECTION *cp, int len);
+extern int pool_write(POOL_CONNECTION *cp, void *buf, int len);
+extern int pool_flush(POOL_CONNECTION *cp);
+extern int pool_write_and_flush(POOL_CONNECTION *cp, void *buf, int len);
+extern char *pool_read_string(POOL_CONNECTION *cp, int *len, int line);
+
+#endif /* PGLB_H */
diff -ruN postgresql-7.4.13-old/src/pgcluster/pglb/pool_auth.c postgresql-7.4.13/src/pgcluster/pglb/pool_auth.c
--- postgresql-7.4.13-old/src/pgcluster/pglb/pool_auth.c	1970-01-01 01:00:00.000000000 +0100
+++ postgresql-7.4.13/src/pgcluster/pglb/pool_auth.c	2006-08-05 16:53:43.000000000 +0200
@@ -0,0 +1,964 @@
+/*--------------------------------------------------------------------
+ * FILE:
+ *     pool_auth.c
+ *
+ * NOTE:
+ *     authenticaton stuff
+ *
+ * Portions Copyright (c) 2003, Atsushi Mitani
+ * Portions Copyright (c) 2003, Tatsuo Ishii
+ *--------------------------------------------------------------------
+ */
+/*
+ * 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.
+ *
+*/
+#ifdef USE_REPLICATION
+
+#include "postgres.h"
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <sys/param.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/time.h>
+#include <stdio.h>
+#include "replicate_com.h"
+#include "pglb.h"
+
+int pool_do_auth(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *cp);
+int pool_do_reauth(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *cp);
+int pool_read_message_length(POOL_CONNECTION_POOL *cp);
+signed char pool_read_kind(POOL_CONNECTION_POOL *cp);
+
+static POOL_STATUS pool_send_auth_ok(POOL_CONNECTION *frontend, int pid, int key, int protoMajor);
+static int do_clear_text_password(POOL_CONNECTION *backend, POOL_CONNECTION *frontend, int reauth, int protoMajor);
+static int do_crypt(POOL_CONNECTION *backend, POOL_CONNECTION *frontend, int reauth, int protoMajor);
+static int do_md5(POOL_CONNECTION *backend, POOL_CONNECTION *frontend, int reauth, int protoMajor);
+
+/*
+* do authentication against backend. if success return 0 otherwise non 0.
+*/
+int pool_do_auth(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *cp)
+{
+	char * func = "pool_do_auth()";
+	int status;
+	signed char kind;
+	int pid, pid1;
+	int key, key1;
+	int protoMajor;
+	int length;
+
+	protoMajor = MAJOR(cp);
+
+	kind = pool_read_kind(cp);
+	if (kind < 0)
+	{
+		return -1;
+	}
+
+	/* error response? */
+	if (kind == 'E')
+	{
+		/* we assume error response at this stage is likely version
+		 * protocol mismatch (v3 frontend vs. v2 backend). So we throw
+		 * a V2 protocol error response in the hope that v3 frontend
+		 * will negotiate again using v2 protocol.
+		 */
+		show_error("%s:pool_do_auth: maybe protocol version mismatch (current version %d)",func, protoMajor);
+		ErrorResponse(frontend, cp);
+		return -1;
+	}
+	else if (kind != 'R')
+	{
+		show_error("%s:pool_do_auth: expect \"R\" got %c",func, kind);
+		return -1;
+	}
+
+	/*
+	 * message length (v3 only) */
+	if (protoMajor == PROTO_MAJOR_V3 && pool_read_message_length(cp) < 0)
+	{
+		return -1;
+	}
+
+	/*
+	 * read authentication request kind.
+	 *
+	 * 0: authentication ok
+	 * 1: kerberos v4
+	 * 2: kerberos v5
+	 * 3: clear text password
+	 * 4: crypt password
+	 * 5: md5 password
+	 * 6: scm credential
+	 *
+	 * in replication mode, we only supports  kind = 0, 3. this is because to "salt"
+	 * cannot be replicated among master and secondary.
+	 * in non replication mode, we supports  kind = 0, 3, 4, 5
+	 */
+
+	status = pool_read(MASTER(cp), &pid, sizeof(pid));
+	if (status < 0)
+	{
+		show_error("%s:pool_do_auth: read authentication kind failed",func);
+		return -1;
+	}
+
+	if (REPLICATION)
+	{
+		status = pool_read(SECONDARY(cp), &pid1, sizeof(pid1));
+
+		if (status < 0)
+		{
+			show_error("%s:pool_do_auth: read authentication kind from secondary failed",func);
+			return -1;
+		}
+	}
+
+	pid = ntohl(pid);
+
+	/* trust? */
+	if (pid == 0)
+	{
+		if (protoMajor == PROTO_MAJOR_V3)
+		{
+			int msglen;
+
+			pool_write(frontend, "R", 1);
+			msglen = htonl(8);
+			pool_write(frontend, &msglen, sizeof(msglen));
+			msglen = htonl(0);
+			if (pool_write_and_flush(frontend, &msglen, sizeof(msglen)) < 0)
+			{
+				return -1;
+			}
+		}
+		MASTER(cp)->auth_kind = 0;
+	}
+
+	/* clear text password authentication? */
+	else if (pid == 3)
+	{
+#ifdef PRINT_DEBUG
+		show_debug("%s:trying clear text password authentication",func);
+#endif			
+
+		pid = do_clear_text_password(MASTER(cp), frontend, 0, protoMajor);
+
+		if (pid >= 0 && REPLICATION)
+		{
+			pid = do_clear_text_password(SECONDARY(cp), frontend, 0, protoMajor);
+		}
+	}
+
+	/* crypt authentication? */
+	else if (pid == 4)
+	{
+#ifdef PRINT_DEBUG
+		show_debug("%s:trying crypt authentication",func);
+#endif			
+
+		pid = do_crypt(MASTER(cp), frontend, 0, protoMajor);
+
+		if (pid >= 0 && REPLICATION)
+		{
+			pid = do_crypt(SECONDARY(cp), frontend, 0, protoMajor);
+		}
+	}
+
+	/* md5 authentication? */
+	else if (pid == 5)
+	{
+#ifdef PRINT_DEBUG
+		show_debug("%s:trying md5 authentication",func);
+#endif			
+
+		pid = do_md5(MASTER(cp), frontend, 0, protoMajor);
+
+		if (pid >= 0 && REPLICATION)
+		{
+			pid = do_md5(SECONDARY(cp), frontend, 0, protoMajor);
+		}
+	}
+
+	if (pid != 0)
+	{
+		show_error("%s:pool_do_auth: backend does not return authenticaton ok",func);
+		return -1;
+	} 
+
+	/*
+	 * authentication ok. now read pid and secret key from the
+	 * backend
+	 */
+	kind = pool_read_kind(cp);
+	if (kind < 0)
+	{
+		return -1;
+	}
+
+	/* error response? */
+	if (kind == 'E')
+	{
+		if (protoMajor == PROTO_MAJOR_V2)
+			ErrorResponse(frontend, cp);
+		else
+			SimpleForwardToFrontend(kind, frontend, cp);
+		return -1;
+	}
+	else if (kind != 'K')
+	{
+		if (protoMajor == PROTO_MAJOR_V3)
+		{
+			/* process parameter status */
+			while (kind == 'S')
+			{
+				if (ParameterStatus(frontend, cp) != POOL_CONTINUE)
+						return -1;
+
+				pool_flush(frontend);
+
+				kind = pool_read_kind(cp);
+				if (kind < 0)
+				{
+					show_error("%s:pool_do_auth: failed to read kind while processing ParamterStatus",func);
+					return -1;
+				}
+			}
+		}
+		else
+		{
+			show_error("%s:pool_do_auth: expect \"K\" got %c",func, kind);
+			return -1;
+		}
+	}
+
+	/*
+	 * message length (V3 only)
+	 */
+	if (protoMajor == PROTO_MAJOR_V3 && (length = pool_read_message_length(cp)) != 12)
+	{
+		show_error("%s:pool_do_auth: invalid messages length(%d) for BackendKeyData",func, length);
+		return -1;
+	}
+
+	/*
+	 * OK, read pid and secret key
+	 */
+
+	/* pid */
+	pool_read(MASTER(cp), &pid, sizeof(pid));
+	MASTER_CONNECTION(cp)->pid = pid;
+
+	/* key */
+	pool_read(MASTER(cp), &key, sizeof(key));
+	MASTER_CONNECTION(cp)->key = key;
+
+	if (REPLICATION)
+	{
+		pool_read(SECONDARY(cp), &pid1, sizeof(pid1));
+		SECONDARY_CONNECTION(cp)->pid = pid;
+
+		/* key */
+		pool_read(SECONDARY(cp), &key1, sizeof(key1));
+		SECONDARY_CONNECTION(cp)->key = key;
+	}
+
+	return (pool_send_auth_ok(frontend, pid, key, protoMajor));
+}
+
+/*
+* do re-authentication for reused connection. if success return 0 otherwise non 0.
+*/
+int pool_do_reauth(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *cp)
+{
+	char * func = "pool_do_reauth()";
+	int status;
+	int protoMajor;
+
+	protoMajor = MAJOR(cp);
+
+	switch(MASTER(cp)->auth_kind)
+	{
+		case 0:
+			/* trust */
+			status = 0;
+			break;
+
+		case 3:
+			/* clear text password */
+			status = do_clear_text_password(MASTER(cp), frontend, 1, protoMajor);
+			break;
+			
+		case 4:
+			/* crypt password */
+			status = do_crypt(MASTER(cp), frontend, 1, protoMajor);
+			break;
+
+		case 5:
+			/* md5 password */
+			status = do_md5(MASTER(cp), frontend, 1, protoMajor);
+			break;
+
+		default:
+			show_error("%s: unknown authentication request code %d", 
+					   func,MASTER(cp)->auth_kind);
+			return -1;
+	}
+
+	if (status == 0)
+	{
+		if (protoMajor == PROTO_MAJOR_V3)
+		{
+			int msglen;
+
+			pool_write(frontend, "R", 1);
+			msglen = htonl(8);
+			pool_write(frontend, &msglen, sizeof(msglen));
+			msglen = htonl(0);
+			if (pool_write_and_flush(frontend, &msglen, sizeof(msglen)) < 0)
+			{
+				return -1;
+			}
+		}
+	}
+	else
+	{
+#ifdef PRINT_DEBUG
+		show_debug("%s: authentication failed",func);
+#endif			
+		return -1;
+	}
+
+	return (pool_send_auth_ok(frontend, MASTER_CONNECTION(cp)->pid, MASTER_CONNECTION(cp)->key, protoMajor) != POOL_CONTINUE);
+}
+
+/*
+* send authentication ok to frontend. if success return 0 otherwise non 0.
+*/
+static POOL_STATUS pool_send_auth_ok(POOL_CONNECTION *frontend, int pid, int key, int protoMajor)
+{
+	char kind;
+	int len;
+
+	if (protoMajor == PROTO_MAJOR_V2)
+	{
+		/* return "Authentication OK" to the frontend */
+		kind = 'R';
+		pool_write(frontend, &kind, 1);
+		len = htonl(0);
+		if (pool_write_and_flush(frontend, &len, sizeof(len)) < 0)
+		{
+			return -1;
+		}
+	}
+
+	/* send backend key data */
+	kind = 'K';
+	pool_write(frontend, &kind, 1);
+	if (protoMajor == PROTO_MAJOR_V3)
+	{
+		len = htonl(12);
+		pool_write(frontend, &len, sizeof(len));
+	}
+	pool_write(frontend, &pid, sizeof(pid));
+	if (pool_write_and_flush(frontend, &key, sizeof(key)) < 0)
+	{
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+ * perform clear text password authetication
+ */
+static int do_clear_text_password(POOL_CONNECTION *backend, POOL_CONNECTION *frontend, int reauth, int protoMajor)
+{
+	char * func = "do_clear_text_password()";
+	static int size;
+	static char password[MAX_PASSWORD_SIZE];
+	char response;
+	int kind;
+	int len;
+
+	/* master? */
+	if (!backend->issecondary_backend)
+	{
+		pool_write(frontend, "R", 1);	/* authenticaton */
+		if (protoMajor == PROTO_MAJOR_V3)
+		{
+			len = htonl(8);
+			pool_write(frontend, &len, sizeof(len));
+		}
+		kind = htonl(3);		/* clear text password authentication */
+		pool_write_and_flush(frontend, &kind, sizeof(kind));	/* indicating clear text password authentication */
+
+		/* read password packet */
+		if (protoMajor == PROTO_MAJOR_V2)
+		{
+			if (pool_read(frontend, &size, sizeof(size)))
+			{
+				show_error("%s: failed to read password packet size",func);
+				return -1;
+			}
+		}
+		else
+		{
+			char k;
+
+			if (pool_read(frontend, &k, sizeof(k)))
+			{
+				show_error("%s: failed to read password packet \"p\"",func);
+				return -1;
+			}
+			if (k != 'p')
+			{
+				show_error("%s:packet does not start with \"p\"",func);
+				return -1;
+			}
+			if (pool_read(frontend, &size, sizeof(size)))
+			{
+				show_error("%s: failed to read password packet size",func);
+				return -1;
+			}
+		}
+
+		if ((ntohl(size) - 4) > sizeof(password))
+		{
+			show_error("%s: password is too long (size: %d)",func, ntohl(size) - 4);
+			return -1;
+		}
+
+		if (pool_read(frontend, password, ntohl(size) - 4))
+		{
+			show_error("%s: failed to read password (size: %d)",func, ntohl(size) - 4);
+			return -1;
+		}
+	}
+
+	/* connection reusing? */
+	if (reauth)
+	{
+		if ((ntohl(size) - 4) != backend->pwd_size)
+		{
+#ifdef PRINT_DEBUG
+			show_debug("%s; password size does not match in re-authetication",func);
+#endif			
+			return -1;
+		}
+
+		if (memcmp(password, backend->password, backend->pwd_size) != 0)
+		{
+#ifdef PRINT_DEBUG
+			show_debug("%s; password does not match in re-authetication",func);
+#endif			
+			return -1;
+		}
+
+		return 0;
+	}
+
+	/* send password packet to backend */
+	if (protoMajor == PROTO_MAJOR_V3)
+		pool_write(backend, "p", 1);
+	pool_write(backend, &size, sizeof(size));
+	pool_write_and_flush(backend, password, ntohl(size) -4);
+	if (pool_read(backend, &response, sizeof(response)))
+	{
+		show_error("%s: failed to read authentication response",func);
+		return -1;
+	}
+
+	if (response != 'R')
+	{
+#ifdef PRINT_DEBUG
+		show_debug("%s: backend does not return R while processing clear text password authentication",func);
+#endif			
+		return -1;
+	}
+
+	if (protoMajor == PROTO_MAJOR_V3)
+	{
+		if (pool_read(backend, &len, sizeof(len)))
+		{
+			show_error("%s: failed to read authentication packet size",func);
+			return -1;
+		}
+
+		if (ntohl(len) != 8)
+		{
+			show_error("%s: incorrect authentication packet size (%d)",func, ntohl(len));
+			return -1;
+		}
+	}
+
+	/* expect to read "Authentication OK" response. kind should be 0... */
+	if (pool_read(backend, &kind, sizeof(kind)))
+	{
+#ifdef PRINT_DEBUG
+		show_debug("%s: failed to read Authentication OK response",func);
+#endif			
+		return -1;
+	}
+
+	/* if authenticated, save info */
+	if (!reauth && kind == 0)
+	{
+		if (!backend->issecondary_backend && protoMajor == PROTO_MAJOR_V3)
+		{
+			int msglen;
+
+			pool_write(frontend, "R", 1);
+			msglen = htonl(8);
+			pool_write(frontend, &msglen, sizeof(msglen));
+			msglen = htonl(0);
+			if (pool_write_and_flush(frontend, &msglen, sizeof(msglen)) < 0)
+			{
+				return -1;
+			}
+		}
+
+		backend->auth_kind = 3;
+		backend->pwd_size = ntohl(size) - 4;
+		memcpy(backend->password, password, backend->pwd_size);
+	}
+	return kind;
+}
+
+/*
+ * perform crypt authetication
+ */
+static int do_crypt(POOL_CONNECTION *backend, POOL_CONNECTION *frontend, int reauth, int protoMajor)
+{
+	char * func = "do_crypt()";
+	char salt[2];
+	static int size;
+	static char password[MAX_PASSWORD_SIZE];
+	char response;
+	int kind;
+	int len;
+
+	if (!reauth)
+	{
+		/* read salt */
+		if (pool_read(backend, salt, sizeof(salt)))
+		{
+			show_error("%s: failed to read salt",func);
+			return -1;
+		}
+	}
+	else
+	{
+		memcpy(salt, backend->salt, sizeof(salt));
+	}
+
+	/* master? */
+	if (!backend->issecondary_backend)
+	{
+		pool_write(frontend, "R", 1);	/* authenticaton */
+		if (protoMajor == PROTO_MAJOR_V3)
+		{
+			len = htonl(10);
+			pool_write(frontend, &len, sizeof(len));
+		}
+		kind = htonl(4);		/* crypt authentication */
+		pool_write(frontend, &kind, sizeof(kind));	/* indicating crypt authentication */
+		pool_write_and_flush(frontend, salt, sizeof(salt));		/* salt */
+
+		/* read password packet */
+		if (protoMajor == PROTO_MAJOR_V2)
+		{
+			if (pool_read(frontend, &size, sizeof(size)))
+			{
+				show_error("%s: failed to read password packet size",func);
+				return -1;
+			}
+		}
+		else
+		{
+			char k;
+
+			if (pool_read(frontend, &k, sizeof(k)))
+			{
+				show_error("%s: failed to read password packet",func);
+				return -1;
+			}
+			if (k != 'p')
+			{
+				show_error("%s: password packet does not start with \"p\"",func);
+				return -1;
+			}
+			if (pool_read(frontend, &size, sizeof(size)))
+			{
+				show_error("%s: failed to read password packet size",func);
+				return -1;
+			}
+		}
+
+		if ((ntohl(size) - 4) > sizeof(password))
+		{
+			show_error("%s: password is too long(size: %d)", func,ntohl(size) - 4);
+			return -1;
+		}
+
+		if (pool_read(frontend, password, ntohl(size) - 4))
+		{
+			show_error("%s: failed to read password (size: %d)", func,ntohl(size) - 4);
+			return -1;
+		}
+	}
+
+	/* connection reusing? */
+	if (reauth)
+	{
+#ifdef PRINT_DEBUG
+		show_debug("%s:size: %d saved_size: %d",func, (ntohl(size) - 4), backend->pwd_size);
+#endif			
+		if ((ntohl(size) - 4) != backend->pwd_size)
+		{
+#ifdef PRINT_DEBUG
+			show_debug("%s: password size does not match in re-authetication",func);
+#endif			
+			return -1;
+		}
+
+		if (memcmp(password, backend->password, backend->pwd_size) != 0)
+		{
+#ifdef PRINT_DEBUG
+			show_debug("%s: password does not match in re-authetication",func);
+#endif			
+			return -1;
+		}
+
+		return 0;
+	}
+
+	/* send password packet to backend */
+	if (protoMajor == PROTO_MAJOR_V3)
+		pool_write(backend, "p", 1);
+	pool_write(backend, &size, sizeof(size));
+	pool_write_and_flush(backend, password, ntohl(size) -4);
+	if (pool_read(backend, &response, sizeof(response)))
+	{
+		show_error("%s: failed to read authentication response",func);
+		return -1;
+	}
+
+	if (response != 'R')
+	{
+#ifdef PRINT_DEBUG
+		show_debug("%s: backend does not return R while processing crypt authentication(%02x) secondary: %d",func, response, backend->issecondary_backend);
+#endif			
+		return -1;
+	}
+
+	if (protoMajor == PROTO_MAJOR_V3)
+	{
+		if (pool_read(backend, &len, sizeof(len)))
+		{
+			show_error("%s: failed to read authentication packet size",func);
+			return -1;
+		}
+
+		if (ntohl(len) != 8)
+		{
+			show_error("%s: incorrect authentication packet size (%d)",func, ntohl(len));
+			return -1;
+		}
+	}
+
+	/* expect to read "Authentication OK" response. kind should be 0... */
+	if (pool_read(backend, &kind, sizeof(kind)))
+	{
+#ifdef PRINT_DEBUG
+		show_debug("%s: failed to read Authentication OK response",func);
+#endif			
+		return -1;
+	}
+
+	/* if authenticated, save info */
+	if (!reauth && kind == 0)
+	{
+		if (protoMajor == PROTO_MAJOR_V3)
+		{
+			int msglen;
+
+			pool_write(frontend, "R", 1);
+			msglen = htonl(8);
+			pool_write(frontend, &msglen, sizeof(msglen));
+			msglen = htonl(0);
+			if (pool_write_and_flush(frontend, &msglen, sizeof(msglen)) < 0)
+			{
+				return -1;
+			}
+		}
+		backend->auth_kind = 4;
+		backend->pwd_size = ntohl(size) - 4;
+		memcpy(backend->password, password, backend->pwd_size);
+		memcpy(backend->salt, salt, sizeof(salt));
+	}
+	return kind;
+}
+
+/*
+ * perform MD5 authetication
+ */
+static int do_md5(POOL_CONNECTION *backend, POOL_CONNECTION *frontend, int reauth, int protoMajor)
+{
+	char * func = "do_md5()";
+	char salt[4];
+	static int size;
+	static char password[MAX_PASSWORD_SIZE];
+	char response;
+	int kind;
+	int len;
+
+	if (!reauth)
+	{
+		/* read salt */
+		if (pool_read(backend, salt, sizeof(salt)))
+		{
+			show_error("%s: failed to read salt",func);
+			return -1;
+		}
+	}
+	else
+	{
+		memcpy(salt, backend->salt, sizeof(salt));
+	}
+
+	/* master? */
+	if (!backend->issecondary_backend)
+	{
+		pool_write(frontend, "R", 1);	/* authenticaton */
+		if (protoMajor == PROTO_MAJOR_V3)
+		{
+			len = htonl(12);
+			pool_write(frontend, &len, sizeof(len));
+		}
+		kind = htonl(5);
+		pool_write(frontend, &kind, sizeof(kind));	/* indicating MD5 */
+		pool_write_and_flush(frontend, salt, sizeof(salt));		/* salt */
+
+		/* read password packet */
+		if (protoMajor == PROTO_MAJOR_V2)
+		{
+			if (pool_read(frontend, &size, sizeof(size)))
+			{
+				show_error("%s: failed to read password packet size",func);
+				return -1;
+			}
+		}
+		else
+		{
+			char k;
+
+			if (pool_read(frontend, &k, sizeof(k)))
+			{
+				show_error("%s: failed to read password packet \"p\"",func);
+				return -1;
+			}
+			if (k != 'p')
+			{
+				show_error("%s: password packet does not start with \"p\"",func);
+				return -1;
+			}
+			if (pool_read(frontend, &size, sizeof(size)))
+			{
+				show_error("%s: failed to read password packet size",func);
+				return -1;
+			}
+		}
+
+		if ((ntohl(size) - 4) > sizeof(password))
+		{
+			show_error("%s: password is too long(size: %d)",func, ntohl(size) - 4);
+			return -1;
+		}
+
+		if (pool_read(frontend, password, ntohl(size) - 4))
+		{
+			show_error("%s: failed to read password (size: %d)",func, ntohl(size) - 4);
+			return -1;
+		}
+	}
+
+	/* connection reusing? */
+	if (reauth)
+	{
+		if ((ntohl(size) - 4) != backend->pwd_size)
+		{
+#ifdef PRINT_DEBUG
+			show_debug("%s; password size does not match in re-authetication",func);
+#endif			
+			return -1;
+		}
+
+		if (memcmp(password, backend->password, backend->pwd_size) != 0)
+		{
+#ifdef PRINT_DEBUG
+			show_debug("%s; password does not match in re-authetication",func);
+#endif			
+			return -1;
+		}
+
+		return 0;
+	}
+
+	/* send password packet to backend */
+	if (protoMajor == PROTO_MAJOR_V3)
+		pool_write(backend, "p", 1);
+	pool_write(backend, &size, sizeof(size));
+	pool_write_and_flush(backend, password, ntohl(size) -4);
+	if (pool_read(backend, &response, sizeof(response)))
+	{
+		show_error("%s: failed to read authentication response",func);
+		return -1;
+	}
+
+	if (response != 'R')
+	{
+#ifdef PRINT_DEBUG
+		show_debug("%s: backend does not return R while processing MD5 authentication %c", func,response);
+#endif			
+		return -1;
+	}
+
+	if (protoMajor == PROTO_MAJOR_V3)
+	{
+		if (pool_read(backend, &len, sizeof(len)))
+		{
+			show_error("%s: failed to read authentication packet size",func);
+			return -1;
+		}
+
+		if (ntohl(len) != 8)
+		{
+			show_error("%s: incorrect authentication packet size (%d)",func, ntohl(len));
+			return -1;
+		}
+	}
+
+	/* expect to read "Authentication OK" response. kind should be 0... */
+	if (pool_read(backend, &kind, sizeof(kind)))
+	{
+#ifdef PRINT_DEBUG
+		show_debug("%s: failed to read Authentication OK response",func);
+#endif			
+		return -1;
+	}
+
+	/* if authenticated, save info */
+	if (!reauth && kind == 0)
+	{
+		if (protoMajor == PROTO_MAJOR_V3)
+		{
+			int msglen;
+
+			pool_write(frontend, "R", 1);
+			msglen = htonl(8);
+			pool_write(frontend, &msglen, sizeof(msglen));
+			msglen = htonl(0);
+			if (pool_write_and_flush(frontend, &msglen, sizeof(msglen)) < 0)
+			{
+				return -1;
+			}
+		}
+		backend->auth_kind = 5;
+		backend->pwd_size = ntohl(size) - 4;
+		memcpy(backend->password, password, backend->pwd_size);
+		memcpy(backend->salt, salt, sizeof(salt));
+	}
+	return kind;
+}
+
+/*
+ * read message length (V3 only)
+ */
+int pool_read_message_length(POOL_CONNECTION_POOL *cp)
+{
+	char * func = "pool_read_message_length()";
+	int status;
+	int length, length1;
+
+	status = pool_read(MASTER(cp), &length, sizeof(length));
+	if (status < 0)
+	{
+		show_error("%s: error while reading message length",func);
+		return -1;
+	}
+	length = ntohl(length);
+
+	if (REPLICATION)
+	{
+		status = pool_read(SECONDARY(cp), &length1, sizeof(length1));
+		if (status < 0)
+		{
+			show_error("%s: error while reading message length from secondary backend",func);
+			return -1;
+		}
+		length1 = ntohl(length1);
+
+		if (length != length1)
+		{
+			show_error("%s: length does not match between backends master(%d) secondary(%d)",
+					   func,length, length1);
+			return -1;
+		}
+	}
+
+	if (length < 0)
+	{
+		show_error("%s:read_message_length: invalid message length (%d)", func, length);
+		return -1;
+	}
+
+	return length;
+}
+
+signed char pool_read_kind(POOL_CONNECTION_POOL *cp)
+{
+	char * func = "pool_read_kind()";
+	int status;
+	char kind, kind1;
+
+	status = pool_read(MASTER(cp), &kind, sizeof(kind));
+	if (status < 0)
+	{
+		show_error("%s:read_message_kind: error while reading message kind",func);
+		return -1;
+	}
+
+	if (REPLICATION)
+	{
+		status = pool_read(SECONDARY(cp), &kind1, sizeof(kind1));
+		if (status < 0)
+		{
+			show_error("%s: error while reading message kind from secondary backend",func);
+			return -1;
+		}
+
+		if (kind != kind1)
+		{
+			show_error("%s: kind does not match between backends master(%d) secondary(%d)",
+			   func, kind, kind1);
+			return -1;
+		}
+	}
+
+	return kind;
+}
+
+#endif /* USE_REPLICATION */
diff -ruN postgresql-7.4.13-old/src/pgcluster/pglb/pool_connection_pool.c postgresql-7.4.13/src/pgcluster/pglb/pool_connection_pool.c
--- postgresql-7.4.13-old/src/pgcluster/pglb/pool_connection_pool.c	1970-01-01 01:00:00.000000000 +0100
+++ postgresql-7.4.13/src/pgcluster/pglb/pool_connection_pool.c	2006-08-05 16:53:43.000000000 +0200
@@ -0,0 +1,533 @@
+/*--------------------------------------------------------------------
+ * FILE:
+ *     pool_connection_pool.c
+ *
+ * NOTE:
+ *     connection pool stuff
+ *
+ * Portions Copyright (c) 2003, Atsushi Mitani
+ * Portions Copyright (c) 2003, Tatsuo Ishii
+ *--------------------------------------------------------------------
+ */
+/*
+ * 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.
+ *
+ */
+#ifdef USE_REPLICATION
+
+#include "postgres.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <signal.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <time.h>
+
+#ifdef HAVE_NETINET_TCP_H
+#include <netinet/tcp.h>
+#endif
+
+#include "replicate_com.h"
+#include "pglb.h"
+
+POOL_CONNECTION_POOL *pool_connection_pool;	/* connection pool */
+
+int pool_init_cp(void);
+POOL_CONNECTION_POOL *pool_get_cp(char *user, char *database, int protoMajor);
+void pool_discard_cp(char *user, char *database, int protoMajor);
+POOL_CONNECTION_POOL *pool_create_cp(void);
+void pool_connection_pool_timer(POOL_CONNECTION_POOL *backend);
+void pool_backend_timer_handler(int sig);
+int connect_inet_domain_socket(int secondary_backend);
+int connect_unix_domain_socket(int secondary_backend);
+char PGRis_same_host(char * host1, char * host2);
+void pool_finish(void);
+
+
+static POOL_CONNECTION_POOL_SLOT *create_cp(POOL_CONNECTION_POOL_SLOT *cp, int secondary_backend);
+static POOL_CONNECTION_POOL *new_connection(POOL_CONNECTION_POOL *p);
+
+
+
+/*
+* initialize connection pools. this should be called once at the startup.
+*/
+int pool_init_cp(void)
+{
+	char * func = "pool_init_cp()";
+	pool_connection_pool = (POOL_CONNECTION_POOL *)malloc(sizeof(POOL_CONNECTION_POOL)*Max_Pool);
+	if (pool_connection_pool == NULL)
+	{
+		show_error("%s: malloc() failed[%s]",func,strerror(errno));
+		return -1;
+	}
+	memset(pool_connection_pool, 0, sizeof(POOL_CONNECTION_POOL)*Max_Pool);
+
+	return 0;
+}
+
+/*
+* find connection by user and database
+*/
+POOL_CONNECTION_POOL *pool_get_cp(char *user, char *database, int protoMajor)
+{
+	char * func = "pool_get_cp()";
+	int i;
+
+	POOL_CONNECTION_POOL *p = pool_connection_pool;
+
+	if (p == NULL)
+	{
+		show_error("%s: pool_connection_pool is not initialized",func);
+		return NULL;
+	}
+
+	for (i=0;i<Max_Pool;i++)
+	{
+		if (MASTER_CONNECTION(p) &&
+			MASTER_CONNECTION(p)->sp->major == protoMajor &&
+			MASTER_CONNECTION(p)->sp->user != NULL &&
+			strcmp(MASTER_CONNECTION(p)->sp->user, user) == 0 &&
+			strcmp(MASTER_CONNECTION(p)->sp->database, database) == 0)
+		{
+			/* mark this connection is under use */
+			MASTER_CONNECTION(p)->closetime = 0;
+			return p;
+		}
+		p++;
+	}
+	return NULL;
+}
+
+/*
+ * disconnect and release a connection to the database
+ */
+void pool_discard_cp(char *user, char *database, int protoMajor)
+{
+	char * func = "pool_discard_cp()";
+	POOL_CONNECTION_POOL *p = pool_get_cp(user, database, protoMajor);
+
+	if (p == NULL)
+	{
+		show_error("%s: cannot get connection pool for user %s datbase %s", func,user, database);
+		return;
+	}
+
+	free(MASTER_CONNECTION(p)->sp->user);
+	free(MASTER_CONNECTION(p)->sp->database);
+	free(MASTER_CONNECTION(p)->sp->startup_packet);
+	pool_close(MASTER_CONNECTION(p)->con);
+
+	memset(p, 0, sizeof(POOL_CONNECTION_POOL));
+}
+
+
+/*
+* create a connection pool by user and database
+*/
+POOL_CONNECTION_POOL *pool_create_cp(void)
+{
+	char * func = "pool_create_cp()";
+	int i;
+	time_t closetime;
+	POOL_CONNECTION_POOL *oldestp;
+
+	POOL_CONNECTION_POOL *p = pool_connection_pool;
+
+	if (p == NULL)
+	{
+		show_error("%s: pool_connection_pool is not initialized",func);
+		return NULL;
+	}
+
+	for (i=0; i<Max_Pool; i++)
+	{
+		if (MASTER_CONNECTION(p) == NULL)
+			return new_connection(p);
+		p++;
+	}
+
+#ifdef PRINT_DEBUG
+	show_debug("%s:no empty connection slot was found",func);
+#endif			
+
+	/*
+	 * no empty connection slot was found. look for the oldest connection and discard it.
+	 */
+	oldestp = p = pool_connection_pool;
+	closetime = MASTER_CONNECTION(p)->closetime;
+	for (i=0; i<Max_Pool; i++)
+	{
+#ifdef PRINT_DEBUG
+		show_debug("%s:user: %s database: %s closetime: %d",
+				func,
+				   MASTER_CONNECTION(p)->sp->user,
+				   MASTER_CONNECTION(p)->sp->database,
+				   MASTER_CONNECTION(p)->closetime);
+#endif			
+		if (MASTER_CONNECTION(p)->closetime < closetime)
+		{
+			closetime = MASTER_CONNECTION(p)->closetime;
+			oldestp = p;
+		}
+		p++;
+	}
+
+	p = oldestp;
+	pool_send_frontend_exits(p);
+
+#ifdef PRINT_DEBUG
+	show_debug("%s:discarding old %d th connection. user: %s database: %s", 
+			   func,
+			   oldestp - pool_connection_pool,
+			   MASTER_CONNECTION(p)->sp->user,
+			   MASTER_CONNECTION(p)->sp->database);
+#endif			
+
+	free(MASTER_CONNECTION(p)->sp->user);
+	free(MASTER_CONNECTION(p)->sp->database);
+	free(MASTER_CONNECTION(p)->sp->startup_packet);
+	pool_close(MASTER_CONNECTION(p)->con);
+
+	memset(p, 0, sizeof(POOL_CONNECTION_POOL));
+
+	return new_connection(p);
+}
+
+/*
+ * set backend connection close timer
+ */
+void pool_connection_pool_timer(POOL_CONNECTION_POOL *backend)
+{
+#ifdef PRINT_DEBUG
+	char * func = "pool_connection_pool_timer()";
+#endif			
+	POOL_CONNECTION_POOL *p = pool_connection_pool;
+	int i;
+
+#ifdef PRINT_DEBUG
+	show_debug("%s:pool_connection_pool_timer: called",func);
+#endif			
+
+	MASTER_CONNECTION(backend)->closetime = time(NULL);		/* set connection close time */
+
+	if (Connection_Life_Time == 0)
+		return;
+
+	/* look for any other timeout */
+	for (i=0;i<Max_Pool;i++, p++)
+	{
+		if (!MASTER_CONNECTION(p))
+			continue;
+		if (MASTER_CONNECTION(p)->sp->user == NULL)
+			continue;
+
+		if (p != backend && MASTER_CONNECTION(p)->closetime)
+			return;
+	}
+
+	/* no other timer found. set my timer */
+#ifdef PRINT_DEBUG
+	show_debug("%s: set alarm after %d seconds",func, Connection_Life_Time);
+#endif			
+	signal(SIGALRM, pool_backend_timer_handler);
+	alarm(Connection_Life_Time);
+}
+
+/*
+ * backend connection close timer handler
+ */
+void pool_backend_timer_handler(int sig)
+{
+#define TMINTMAX 0x7fffffff
+
+#ifdef PRINT_DEBUG
+	char * func = "pool_backend_timer_handler()";
+#endif			
+	POOL_CONNECTION_POOL *p = pool_connection_pool;
+	int i;
+	time_t now;
+	time_t nearest = TMINTMAX;
+
+	now = time(NULL);
+
+#ifdef PRINT_DEBUG
+	show_debug("%s:called at %d", func,now);
+#endif			
+
+	for (i=0;i<Max_Pool;i++, p++)
+	{
+		if (!MASTER_CONNECTION(p))
+			continue;
+		if (MASTER_CONNECTION(p)->sp->user == NULL)
+			continue;
+
+		/* timer expire? */
+		if (MASTER_CONNECTION(p)->closetime)
+		{
+#ifdef PRINT_DEBUG
+			show_debug("%s: expire time: %d",
+					   func,
+					   MASTER_CONNECTION(p)->closetime+Connection_Life_Time);
+#endif			
+
+			if (now >= (MASTER_CONNECTION(p)->closetime+Connection_Life_Time))
+			{
+				/* discard expired connection */
+#ifdef PRINT_DEBUG
+				show_debug("%s: expires user %s database %s", func, MASTER_CONNECTION(p)->sp->user, MASTER_CONNECTION(p)->sp->database);
+#endif			
+
+				pool_send_frontend_exits(p);
+
+				free(MASTER_CONNECTION(p)->sp->user);
+				free(MASTER_CONNECTION(p)->sp->database);
+				free(MASTER_CONNECTION(p)->sp->startup_packet);
+				pool_close(MASTER_CONNECTION(p)->con);
+
+				memset(p, 0, sizeof(POOL_CONNECTION_POOL));
+			}
+			else
+			{
+				/* look for nearest timer */
+				if (MASTER_CONNECTION(p)->closetime < nearest)
+					nearest = MASTER_CONNECTION(p)->closetime;
+			}
+		}
+	}
+
+	/* any remaining timer */
+	if (nearest != TMINTMAX)
+	{
+		nearest = Connection_Life_Time - (now - nearest);
+		if (nearest <= 0)
+		  nearest = 1;
+		signal(SIGALRM, pool_backend_timer_handler);
+		alarm(nearest);
+	}
+}
+
+int connect_inet_domain_socket(int secondary_backend)
+{
+	char * func = "connect_inet_domain_socket()";
+	int fd;
+	int len;
+	int on = 1;
+	struct sockaddr_in addr;
+	struct hostent *hp;
+
+	fd = socket(AF_INET, SOCK_STREAM, 0);
+	if (fd < 0)
+	{
+		show_error("%s: socket() failed: %s",func, strerror(errno));
+		return -1;
+	}
+
+	/* set nodelay */
+	if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
+				   (char *) &on,
+				   sizeof(on)) < 0)
+	{
+		show_error("%s: setsockopt() failed: %s", func, strerror(errno));
+		close(fd);
+		return -1;
+	}
+
+	memset((char *) &addr, 0, sizeof(addr));
+	((struct sockaddr *)&addr)->sa_family = AF_INET;
+
+	addr.sin_port = htons(CurrentCluster->port);
+	len = sizeof(struct sockaddr_in);
+
+	hp = gethostbyname(CurrentCluster->hostName);
+
+	if ((hp == NULL) || (hp->h_addrtype != AF_INET))
+	{
+		show_error("%s: gethostbyname() failed: %s host: %s",func, strerror(errno), CurrentCluster->hostName);
+		close(fd);
+		return -1;
+	}
+	memmove((char *) &(addr.sin_addr),
+			(char *) hp->h_addr,
+			hp->h_length);
+
+	if (connect(fd, (struct sockaddr *)&addr, len) < 0)
+	{
+		show_error("%s: connect() failed: %s",func,strerror(errno));
+		close(fd);
+		return -1;
+	}
+	return fd;
+}
+
+int connect_unix_domain_socket(int secondary_backend)
+{
+	char * func = "connect_unix_domain_socket()";
+	struct sockaddr_un addr;
+	int fd;
+	int len;
+	int port;
+
+	fd = socket(AF_UNIX, SOCK_STREAM, 0);
+	if (fd == -1)
+	{
+		show_error("%s: setsockopt() failed: %s", func,strerror(errno));
+		return -1;
+	}
+
+	port = CurrentCluster->port;
+	memset((char *) &addr, 0, sizeof(addr));
+	((struct sockaddr *)&addr)->sa_family = AF_UNIX;
+	snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/.s.PGSQL.%d", 
+			 Backend_Socket_Dir,
+			 CurrentCluster->port);
+#ifdef PRINT_DEBUG
+	show_debug("%s:postmaster Unix domain socket: %s",func, addr.sun_path);
+#endif			
+
+	len = sizeof(struct sockaddr_un);
+
+	if (connect(fd, (struct sockaddr *)&addr, len) < 0)
+	{
+		show_error("%s: connect() failed: %s",func, strerror(errno));
+		close(fd);
+		return -1;
+	}
+#ifdef PRINT_DEBUG
+	show_debug("%s:connected to postmaster Unix domain socket: %s fd: %d", func,addr.sun_path, fd);
+#endif			
+	return fd;
+}
+
+static POOL_CONNECTION_POOL_SLOT *create_cp(POOL_CONNECTION_POOL_SLOT *cp, int secondary_backend)
+{
+	char * func = "create_cp()";
+	int fd;
+	char hostName[HOSTNAME_MAX_LENGTH];
+
+	if (gethostname(hostName,sizeof(hostName)) < 0)
+	{
+		show_error("%s:gethostname() failed. (%s)",func,strerror(errno));
+		return NULL;
+	}
+	if (PGRis_same_host(hostName,CurrentCluster->hostName) == 1)
+	{
+#ifdef PRINT_DEBUG
+		show_debug("%s:[%s] [%s] is same",func,hostName,CurrentCluster->hostName);
+#endif			
+		fd = connect_unix_domain_socket(secondary_backend);
+	}
+	else
+	{
+		fd = connect_inet_domain_socket(secondary_backend);
+	}
+
+	if (fd < 0)
+	{
+		/* fatal error, notice to parent and exit */
+		/*
+		notice_backend_error();
+		exit(1);
+		*/
+		return NULL;
+	}
+
+	cp->con = pool_open(fd);
+	cp->closetime = 0;
+	return cp;
+}
+
+static POOL_CONNECTION_POOL *new_connection(POOL_CONNECTION_POOL *p)
+{
+	char * func = "new_connection()";
+	/* create master connection */
+	MASTER_CONNECTION(p) = malloc(sizeof(POOL_CONNECTION_POOL_SLOT));
+	if (MASTER_CONNECTION(p) == NULL)
+	{
+		show_error("%s: malloc() failed [%s]",func,strerror(errno));
+		return NULL;
+	}
+	create_cp(MASTER_CONNECTION(p), 0);
+
+			/* initialize Paramter Status save structure */
+	if (pool_init_params(&MASTER(p)->params))
+	{
+		return NULL;
+	}
+	p->num = 1;	/* number of slots */
+
+	return p;
+}
+
+char PGRis_same_host(char * host1, char * host2)
+{
+	unsigned int ip1, ip2;
+
+	if ((host1 == NULL) || (host2 == NULL))
+	{
+		return 0;
+	}
+	ip1 = PGRget_ip_by_name( host1);
+	ip2 = PGRget_ip_by_name( host2);
+	if (ip1 == ip2)
+	{
+		return 1;
+	}
+	return 0;
+}
+
+void pool_finish(void)
+{
+	char * func = "pool_finish()";
+	int i;
+
+	POOL_CONNECTION_POOL *p = pool_connection_pool;
+
+	if (p == NULL)
+	{
+		show_error("%s:pool_connection_pool is not initialized",func);
+		return ;
+	}
+
+	for (i=0 ; i<Max_Pool ; i++)
+	{
+		free(MASTER_CONNECTION(p)->sp->user);
+		free(MASTER_CONNECTION(p)->sp->database);
+		free(MASTER_CONNECTION(p)->sp->startup_packet);
+		pool_close(MASTER_CONNECTION(p)->con);
+		memset(p, 0, sizeof(POOL_CONNECTION_POOL));
+		p++;
+	}
+	free((char *)pool_connection_pool);
+	pool_connection_pool = NULL;
+}
+
+void pool_clear(void)
+{
+	char * func = "pool_clear()";
+	POOL_CONNECTION_POOL *p = pool_connection_pool;
+
+	if (p == NULL)
+	{
+		show_error("%s:pool_connection_pool is not initialized",func);
+		return ;
+	}
+	memset(p, 0, sizeof(POOL_CONNECTION_POOL)*Max_Pool);
+}
+#endif /* USE_REPLICATION */
diff -ruN postgresql-7.4.13-old/src/pgcluster/pglb/pool_params.c postgresql-7.4.13/src/pgcluster/pglb/pool_params.c
--- postgresql-7.4.13-old/src/pgcluster/pglb/pool_params.c	1970-01-01 01:00:00.000000000 +0100
+++ postgresql-7.4.13/src/pgcluster/pglb/pool_params.c	2006-08-05 16:53:43.000000000 +0200
@@ -0,0 +1,190 @@
+/*--------------------------------------------------------------------
+ * FILE:
+ *     pool_params.c
+ *
+ * NOTE:
+ *     connection pool stuff
+ *
+ * Portions Copyright (c) 2003, 2004 Atsushi Mitani
+ * Portions Copyright (c) 2003, 2004 Tatsuo Ishii
+ *--------------------------------------------------------------------
+ */
+/*
+ * 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.
+ *
+ */
+
+#ifdef USE_REPLICATION
+
+#include "postgres.h"
+
+#include <stdio.h>
+#include <sys/time.h>
+#include <time.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef HAVE_NETINET_TCP_H
+#include <netinet/tcp.h>
+#endif
+
+#include "replicate_com.h"
+#include "pglb.h"
+
+#define MAX_PARAM_ITEMS 128
+
+int pool_init_params(ParamStatus *params);
+void pool_discard_params(ParamStatus *params);
+char *pool_find_name(ParamStatus *params, char *name, int *pos);
+int pool_get_param(ParamStatus *params, int index, char **name, char **value);
+int pool_add_param(ParamStatus *params, char *name, char *value);
+void pool_param_debug_print(ParamStatus *params);
+
+/*
+ * initialize parameter structure
+ */
+int pool_init_params(ParamStatus *params)
+{
+	char * func = "pool_init_params()";
+
+    params->num = 0;
+    params->names = malloc(MAX_PARAM_ITEMS*sizeof(char *));
+	if (params->names == NULL)
+	{
+		show_error("%s: cannot allocate memory",func);
+		return -1;
+	}
+    params->values = malloc(MAX_PARAM_ITEMS*sizeof(char *));
+	if (params->values == NULL)
+	{
+		show_error("%s: cannot allocate memory",func);
+		return -1;
+	}
+	return 0;
+}
+
+/*
+ * discard parameter structure
+ */
+void pool_discard_params(ParamStatus *params)
+{
+    int i;
+
+    for (i=0;i<params->num;i++)
+    {
+		free(params->names[i]);
+		free(params->values[i]);
+    }
+    free(params->names);
+    free(params->values);
+}
+
+/*
+ * find param value by name. if found, its value is returned
+ * also, pos is set
+ * if not found, NULL is returned
+ */
+char *pool_find_name(ParamStatus *params, char *name, int *pos)
+{
+    int i;
+
+    for (i=0;i<params->num;i++)
+    {
+		if (!strcmp(name, params->names[i]))
+		{
+			*pos = i;
+			return params->values[i];
+		}
+    }
+    return NULL;
+}
+
+/*
+ * return name and value by index.
+ */
+int pool_get_param(ParamStatus *params, int index, char **name, char **value)
+{
+	if (index < 0 || index >= params->num)
+		return -1;
+
+	*name = params->names[index];
+	*value = params->values[index];
+
+	return 0;
+}
+
+/*
+ * add or replace name/value pair
+ */
+int pool_add_param(ParamStatus *params, char *name, char *value)
+{
+	char * func = "pool_add_param()";
+    int pos;
+
+    if (pool_find_name(params, name, &pos))
+    {
+		/* name already exists */
+		if (strlen(params->values[pos]) < strlen(value))
+		{
+			params->values[pos] = realloc(params->values[pos], strlen(value) + 1);
+			if (params->values[pos] == NULL)
+			{
+				show_error("%s: cannot allocate memory",func);
+				return -1;
+			}
+		}
+		strcpy(params->values[pos], value);
+    }
+    else
+    {
+		int num;
+
+		/* add name/value pair */
+		if (params->num >= MAX_PARAM_ITEMS)
+		{
+			show_error("%s: no more room for num",func);
+			return -1;
+		}
+		num = params->num;
+		params->names[num] = strdup(name);
+		if (params->names[num] == NULL)
+		{
+			show_error("%s: cannot allocate memory",func);
+			return -1;
+		}
+		params->values[num] = strdup(value);
+		if (params->values[num] == NULL)
+		{
+			show_error("%s: cannot allocate memory",func);
+			return -1;
+		}
+		params->num++;
+    }
+	return 0;
+}
+
+void pool_param_debug_print(ParamStatus *params)
+{
+#ifdef PRINT_DEBUG
+	char * func = "pool_param_debug_print()";
+#endif			
+	int i;
+
+    for (i=0;i<params->num;i++)
+    {
+#ifdef PRINT_DEBUG
+		show_debug("%s: No.%d: name: %s value: %s",func, i, params->names[i], params->values[i]);
+#endif			
+	}
+}
+
+#endif /* USE_REPLICATION */
diff -ruN postgresql-7.4.13-old/src/pgcluster/pglb/pool_process_query.c postgresql-7.4.13/src/pgcluster/pglb/pool_process_query.c
--- postgresql-7.4.13-old/src/pgcluster/pglb/pool_process_query.c	1970-01-01 01:00:00.000000000 +0100
+++ postgresql-7.4.13/src/pgcluster/pglb/pool_process_query.c	2006-08-05 16:53:43.000000000 +0200
@@ -0,0 +1,2085 @@
+/*--------------------------------------------------------------------
+ * FILE:
+ *     pool_process_query.c
+ *
+ * NOTE:
+ *     query processing stuff
+ *
+ * Portions Copyright (c) 2003, Atsushi Mitani
+ * Portions Copyright (c) 2003, Tatsuo Ishii
+ *--------------------------------------------------------------------
+ */
+/*
+ * 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.
+ *
+*/
+#ifdef USE_REPLICATION
+
+#include "postgres.h"
+
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <netinet/in.h>
+
+#include "postgres_fe.h"
+#include "libpq/pqcomm.h"
+
+#include "replicate_com.h"
+#include "pglb.h"
+
+POOL_STATUS pool_process_query(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend, int connection_reuse);
+POOL_STATUS ErrorResponse(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend);
+void pool_enable_timeout(void); 
+void pool_disable_timeout(void);
+int pool_check_fd(POOL_CONNECTION *cp, int notimeout);
+void pool_send_frontend_exits(POOL_CONNECTION_POOL *backend);
+POOL_STATUS SimpleForwardToFrontend(char kind, POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend);
+POOL_STATUS SimpleForwardToBackend(char kind, POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend);
+POOL_STATUS ParameterStatus(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend);
+void pool_send_error_message(POOL_CONNECTION *frontend, int protoMajor, char *code, char *message, char *detail, char *hint, char *file, int line);
+
+
+static POOL_STATUS Query(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend, char *query);
+static POOL_STATUS ReadyForQuery(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend, int send_ready);
+static POOL_STATUS CompleteCommandResponse(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend);
+static int RowDescription(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend);
+static POOL_STATUS AsciiRow(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend, short num_fields);
+static POOL_STATUS BinaryRow(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend, short num_fields);
+static POOL_STATUS CursorResponse(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend);
+static POOL_STATUS NoticeResponse(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend);
+static POOL_STATUS CopyInResponse(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend);
+static POOL_STATUS CopyOutResponse(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend);
+static POOL_STATUS CopyDataRows(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend, int copyin);
+static POOL_STATUS EmptyQueryResponse(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend);
+static POOL_STATUS NotificationResponse(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend);
+static POOL_STATUS FunctionCall(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend);
+static POOL_STATUS FunctionResultResponse(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend);
+static POOL_STATUS ProcessFrontendResponse(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend);
+static int synchronize(POOL_CONNECTION *cp);
+static void process_reporting(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend);
+static int reset_backend(POOL_CONNECTION_POOL *backend, int qcnt);
+static int load_balance_enabled(POOL_CONNECTION_POOL *backend, char *sql);
+static void start_load_balance(POOL_CONNECTION_POOL *backend);
+static void end_load_balance(POOL_CONNECTION_POOL *backend);
+
+static POOL_CONNECTION_POOL_SLOT *slots[MAX_CONNECTION_SLOTS];
+
+POOL_STATUS pool_process_query(POOL_CONNECTION *frontend, 
+							   POOL_CONNECTION_POOL *backend,
+							   int connection_reuse)
+{
+	char * func = "pool_process_query()";
+	char kind, kind1;	/* packet kind (backend) */
+	char fkind;	/* packet kind (frontend) */
+	short num_fields = 0;
+	fd_set	readmask;
+	fd_set	writemask;
+	fd_set	exceptmask;
+	int fds;
+	POOL_STATUS status;
+	int state;	/* 0: ok to issue commands 1: waiting for "ready for query" response */
+	int qcnt;
+
+	frontend->no_forward = connection_reuse;
+	qcnt = 0;
+	state = 0;
+
+	for (;;)
+	{
+		kind = kind1 = 0;
+		fkind = 0;
+
+		if (state == 0 && connection_reuse)
+		{
+			int st;
+
+			/* send query for resetting connection such as "ROLLBACK" "RESET ALL"... */
+			st = reset_backend(backend, qcnt);
+
+			if (st < 0)		/* error? */
+				return POOL_END;
+
+			else if (st == 0)	/* no query issued? */
+			{
+				qcnt++;
+				continue;
+			}
+
+			else if (st == 1)	/* more query remains */
+			{
+				state = 1;
+				qcnt++;
+				continue;
+			}
+
+			else if (st == 2)	/* no more qury */
+			{
+				frontend->no_forward = 0;
+				return POOL_CONTINUE;
+			}
+
+		}
+
+		if ((!REPLICATION && MASTER(backend)->len == 0 && frontend->len == 0) ||
+			(REPLICATION && MASTER(backend)->len == 0 &&
+			SECONDARY(backend)->len == 0
+			 && frontend->len == 0))
+		{
+
+			struct timeval timeout;
+
+			timeout.tv_sec = 1;
+			timeout.tv_usec = 0;
+
+			FD_ZERO(&readmask);
+			FD_ZERO(&writemask);
+			FD_ZERO(&exceptmask);
+			if (!connection_reuse)
+				FD_SET(frontend->fd, &readmask);
+			FD_SET(MASTER(backend)->fd, &readmask);
+			if (REPLICATION)
+				FD_SET(SECONDARY(backend)->fd, &readmask);
+			if (!connection_reuse)
+				FD_SET(frontend->fd, &exceptmask);
+			FD_SET(MASTER(backend)->fd, &exceptmask);
+
+			if (connection_reuse)
+			{
+				if (REPLICATION)
+					fds = select(Max(SECONDARY(backend)->fd, MASTER(backend)->fd) + 1,
+								 &readmask, &writemask, &exceptmask, NULL);
+				else
+					fds = select(MASTER(backend)->fd+1, &readmask, &writemask, &exceptmask, NULL);
+			}
+			else
+			{
+				if (REPLICATION)
+					fds = select(Max(SECONDARY(backend)->fd,
+									 Max(frontend->fd, MASTER(backend)->fd)+1),
+								 &readmask, &writemask, &exceptmask, NULL);
+				else
+					fds = select(Max(frontend->fd, MASTER(backend)->fd)+1,
+								 &readmask, &writemask, &exceptmask, NULL);
+			}
+
+			if (fds == -1)
+			{
+				if (errno == EINTR)
+					continue;
+
+				show_error("%s:select() failed. reason: %s",func, strerror(errno));
+				return POOL_ERROR;
+			}
+
+			if (fds == 0)
+			{
+				return POOL_CONTINUE;
+			}
+
+			if (FD_ISSET(MASTER(backend)->fd, &readmask))
+			{
+				pool_read(MASTER(backend), &kind, 1);
+#ifdef PRINT_DEBUG
+				show_debug("%s:read kind from backend %c", func,kind);
+#endif			
+			}
+
+			if (REPLICATION && FD_ISSET(SECONDARY(backend)->fd, &readmask))
+			{
+				pool_read(SECONDARY(backend), &kind1, 1);
+#ifdef PRINT_DEBUG
+				show_debug("%s:read kind from secondary backend %c", func,kind1);
+#endif			
+			}
+
+			if (!connection_reuse && FD_ISSET(frontend->fd, &exceptmask))
+			{
+				return POOL_END;
+			}
+			if (FD_ISSET(MASTER(backend)->fd, &exceptmask))
+			{
+				return POOL_ERROR;
+			}
+
+			if (!connection_reuse && FD_ISSET(frontend->fd, &readmask))
+			{
+				status = ProcessFrontendResponse(frontend, backend);
+				if (status != POOL_CONTINUE)
+					return status;
+
+				continue;
+			}
+		}
+		else
+		{
+			if (MASTER(backend)->len > 0)
+			{
+				pool_read(MASTER(backend), &kind, 1);
+				if (REPLICATION)
+				{
+					pool_read(SECONDARY(backend), &kind1, 1);
+					if (kind == '\0' || kind != kind1)
+					{
+						show_error("%s: kind does not match between backends master(%c) secondary(%c)",
+								   func, kind, kind1);
+						pool_send_error_message(frontend, MAJOR(backend), "XX000", 
+												"kind mismatch between backends", "",
+												"check data consistency between master and secondary", __FILE__, __LINE__);
+
+						if (pool_config_replication_stop_on_mismatch)
+							return POOL_FATAL;
+						else
+							return POOL_ERROR;
+					}
+				}
+#ifdef PRINT_DEBUG
+				show_debug("%s:read kind from backend pending data %c len: %d po: %d", func, kind, MASTER(backend)->len, MASTER(backend)->po);
+#endif			
+			}
+			if (frontend->len > 0)
+			{
+				status = ProcessFrontendResponse(frontend, backend);
+				if (status != POOL_CONTINUE)
+					return status;
+
+				continue;
+			}
+		}
+
+		/* this is the synchronous point */
+		if (REPLICATION)
+		{
+			if (kind == 0)
+			{
+				pool_read(MASTER(backend), &kind, 1);
+			}
+			if (kind1 == 0)
+			{
+				pool_read(SECONDARY(backend), &kind1, 1);
+			}
+			if (kind == '\0' || kind != kind1)
+			{
+				show_error("%s: kind does not match between backends master(%c) secondary(%c)",
+						   func, kind, kind1);
+				pool_send_error_message(frontend, MAJOR(backend), "XX000", 
+										"kind mismatch between backends", "",
+										"check data consistency between master and secondary", __FILE__, __LINE__);
+
+				if (pool_config_replication_stop_on_mismatch)
+					return POOL_FATAL;
+				else
+					return POOL_ERROR;
+			}
+		}
+
+		/*
+		 * Prrocess backend Response
+		 */
+
+		if (MAJOR(backend) == PROTO_MAJOR_V3)
+		{
+			switch (kind)
+			{
+				case 'G':
+					/* CopyIn response */
+					status = CopyInResponse(frontend, backend);
+					break;
+				case 'S':
+					/* Paramter Status */
+					status = ParameterStatus(frontend, backend);
+					break;
+				case 'Z':
+					/* Ready for query */
+					status = ReadyForQuery(frontend, backend, 1);
+					break;
+				default:
+					status = SimpleForwardToFrontend(kind, frontend, backend);
+					break;
+			}
+		}
+		else
+		{
+			switch (kind)
+			{
+				case 'A':
+					/* Notification  response */
+					status = NotificationResponse(frontend, backend);
+					break;
+
+				case 'B':
+					/* BinaryRow */
+					status = BinaryRow(frontend, backend, num_fields);
+					break;
+
+				case 'C':
+					/* Complete command response */
+					status = CompleteCommandResponse(frontend, backend);
+					break;
+
+				case 'D':
+					/* AsciiRow */
+					status = AsciiRow(frontend, backend, num_fields);
+					break;
+
+				case 'E':
+					/* Error Response */
+					status = ErrorResponse(frontend, backend);
+					break;
+
+				case 'G':
+					/* CopyIn Response */
+					status = CopyInResponse(frontend, backend);
+					break;
+
+				case 'H':
+					/* CopyOut Response */
+					status = CopyOutResponse(frontend, backend);
+					break;
+
+				case 'I':
+					/* Empty Query Response */
+					status = EmptyQueryResponse(frontend, backend);
+					break;
+
+				case 'N':
+					/* Notice Response */
+					status = NoticeResponse(frontend, backend);
+					break;
+
+				case 'P':
+					/* CursorResponse */
+					status = CursorResponse(frontend, backend);
+					break;
+
+				case 'T':
+					/* RowDescription */
+					status = RowDescription(frontend, backend);
+					if (status < 0)
+						return POOL_ERROR;
+
+					num_fields = status;
+					status = POOL_CONTINUE;
+					break;
+
+				case 'V':
+					/* FunctionResultResponse and FunctionVoidResponse */
+					status = FunctionResultResponse(frontend, backend);
+					break;
+				
+				case 'Z':
+					/* Ready for query */
+					status = ReadyForQuery(frontend, backend, 1);
+					break;
+				
+				default:
+					show_error("%s:Unknown message type %c(%02x)",func, kind, kind);
+					exit(1);
+			}
+		}
+
+		if (status != POOL_CONTINUE)
+			return status;
+
+		if (kind == 'Z' && frontend->no_forward && state == 1)
+		{
+			state = 0;
+		}
+
+	}
+	return POOL_CONTINUE;
+}
+
+static POOL_STATUS Query(POOL_CONNECTION *frontend, 
+						 POOL_CONNECTION_POOL *backend, char *query)
+{
+#ifdef PRINT_DEBUG
+	char * func = "Query()";
+#endif			
+	char *string;
+	int len;
+	static char *sq = "show pool_status";
+
+	if (query == NULL)
+	{
+		/* read actual query */
+		if (MAJOR(backend) == PROTO_MAJOR_V3)
+		{
+			if (pool_read(frontend, &len, sizeof(len)) < 0)
+				return POOL_END;
+			len = ntohl(len) - 4;
+			string = pool_read2(frontend, len);
+		}
+		else
+			string = pool_read_string(frontend, &len, 0);
+
+		if (string == NULL)
+			return POOL_END;
+	}
+	else
+	{
+		len = strlen(query)+1;
+		string = query;
+	}
+
+#ifdef PRINT_DEBUG
+	show_debug("%s: %s", func,string);
+#endif			
+
+	/* process status reporting? */
+	if (strncasecmp(sq, string, strlen(sq)) == 0)
+	{
+#ifdef PRINT_DEBUG
+		show_debug("%s:process reporting",func);
+#endif			
+		process_reporting(frontend, backend);
+		return POOL_CONTINUE;
+	}
+
+	/* load balance trick */
+	if (load_balance_enabled(backend, string))
+		start_load_balance(backend);
+
+	/* forward the query to the backend */
+	pool_write(MASTER(backend), "Q", 1);
+
+	if (MAJOR(backend) == PROTO_MAJOR_V3)
+	{
+		int sendlen = htonl(len + 4);
+		pool_write(MASTER(backend), &sendlen, sizeof(sendlen));
+	}
+
+	if (pool_write_and_flush(MASTER(backend), string, len) < 0)
+	{
+		return POOL_END;
+	}
+
+	if (REPLICATION)
+	{
+		/* in "strict mode" we need to wait for master completing the query */
+		if (pool_config_replication_strict || STRICT_MODE(string))
+			if (synchronize(MASTER(backend)))
+				return POOL_END;
+
+		pool_write(SECONDARY(backend), "Q", 1);
+		if (MAJOR(backend) == PROTO_MAJOR_V3)
+		{
+			int sendlen = htonl(len + 4);
+			pool_write(SECONDARY(backend), &sendlen, sizeof(sendlen));
+		}
+
+		if (pool_write_and_flush(SECONDARY(backend), string, len) < 0)
+		{
+			return POOL_END;
+		}
+	}
+	return POOL_CONTINUE;
+}
+
+static POOL_STATUS ReadyForQuery(POOL_CONNECTION *frontend, 
+								 POOL_CONNECTION_POOL *backend, int send_ready)
+{
+#ifdef PRINT_DEBUG
+	char * func = "ReadyForQuery()";
+#endif
+
+	pool_flush(frontend);
+
+	if (send_ready)
+	{
+		pool_write(frontend, "Z", 1);
+
+		if (MAJOR(backend) == PROTO_MAJOR_V3)
+		{
+			int len;
+			signed char state;
+
+			if ((len = pool_read_message_length(backend)) < 0)
+				return POOL_END;
+
+#ifdef PRINT_DEBUG
+			show_debug("%s: message length: %d", func, len);
+#endif			
+
+			len = htonl(len);
+			pool_write(frontend, &len, sizeof(len));
+
+			state = pool_read_kind(backend);
+			if (state < 0)
+				return POOL_END;
+
+			/* set transaction state */
+#ifdef PRINT_DEBUG
+			show_debug("%s: transaction state: %c", func, state);
+#endif			
+			MASTER(backend)->tstate = state;
+			if (REPLICATION)
+				SECONDARY(backend)->tstate = state;
+
+			pool_write(frontend, &state, 1);
+		}
+
+		if (pool_flush(frontend))
+			return POOL_END;
+	}
+
+	/* end load balance mode */
+	if (IN_LOAD_BALANCE)
+		end_load_balance(backend);
+
+	return ProcessFrontendResponse(frontend, backend);
+}
+
+static POOL_STATUS CompleteCommandResponse(POOL_CONNECTION *frontend, 
+										   POOL_CONNECTION_POOL *backend)
+{
+	char * func = "CompleteCommandResponse()";
+	char *string, *string1;
+	int len, len1;
+
+	/* read command tag */
+	string = pool_read_string(MASTER(backend), &len, 0);
+	if (string == NULL)
+		return POOL_END;
+
+	if (REPLICATION)
+	{
+		string1 = pool_read_string(SECONDARY(backend), &len1, 0);
+		if (string1 == NULL)
+			return POOL_END;
+
+		if (len != len1)
+		{
+			show_error("%s: message length does not match between master(%d \"%s\",) and secondary(%d \"%s\",)",
+					 func, len, string, len1, string1);
+		}
+	}
+
+	/* forward to the frontend */
+	pool_write(frontend, "C", 1);
+#ifdef PRINT_DEBUG
+	show_debug("%s: string: \"%s\"",func, string);
+#endif			
+	if (pool_write(frontend, string, len) < 0)
+	{
+		return POOL_END;
+	}
+	return POOL_CONTINUE;
+}
+
+static int RowDescription(POOL_CONNECTION *frontend, 
+						  POOL_CONNECTION_POOL *backend)
+{
+	char * func = "RowDescription()";
+	short num_fields, num_fields1;
+	int oid, mod;
+	int oid1, mod1;
+	short size, size1;
+	char *string, *string1;
+	int len, len1;
+	int i;
+
+	/* # of fields (could be 0) */
+	pool_read(MASTER(backend), &num_fields, sizeof(short));
+	if (REPLICATION)
+	{
+		pool_read(SECONDARY(backend), &num_fields1, sizeof(short));
+		if (num_fields != num_fields1)
+		{
+			show_error("%s: num_fields deos not match between backends master(%d) and secondary(%d)",
+					   func, num_fields, num_fields1);
+			return POOL_FATAL;
+		}
+	}
+
+	/* forward it to the frontend */
+	pool_write(frontend, "T", 1);
+	pool_write(frontend, &num_fields, sizeof(short));
+
+	num_fields = ntohs(num_fields);
+	for (i = 0;i<num_fields;i++)
+	{
+		/* field name */
+		string = pool_read_string(MASTER(backend), &len, 0);
+		if (string == NULL)
+			return POOL_END;
+
+		if (REPLICATION)
+		{
+			string1 = pool_read_string(SECONDARY(backend), &len1, 0);
+			if (string == NULL)
+				return POOL_END;
+			if (len != len1)
+			{
+				show_error("%s: field length deos not match between backends master(%d) and secondary(%d)",
+						   func, ntohl(len), ntohl(len1));
+				return POOL_FATAL;
+			}
+		}
+
+		pool_write(frontend, string, len);
+
+		/* oid */
+		pool_read(MASTER(backend), &oid, sizeof(int));
+		if (REPLICATION)
+		{
+			pool_read(SECONDARY(backend), &oid1, sizeof(int));
+
+			/* we do not regard oid mismatch as fatal */
+			if (oid != oid1)
+			{
+				show_error("%s: field oid deos not match between backends master(%d) and secondary(%d)",
+						 func, ntohl(oid), ntohl(oid1));
+			}
+		}
+		pool_write(frontend, &oid, sizeof(int));
+
+		/* size */
+		pool_read(MASTER(backend), &size, sizeof(short));
+		if (REPLICATION)
+		{
+			pool_read(SECONDARY(backend), &size1, sizeof(short));
+			if (size1 != size1)
+			{
+				show_error("%s: field size deos not match between backends master(%d) and secondary(%d)",
+						 func, ntohs(size), ntohs(size1));
+				return POOL_FATAL;
+			}
+		}
+#ifdef PRINT_DEBUG
+		show_debug("%s: field size:%d", func, ntohs(size));
+#endif			
+		pool_write(frontend, &size, sizeof(short));
+
+		/* modifier */
+		pool_read(MASTER(backend), &mod, sizeof(int));
+		if (REPLICATION)
+		{
+			pool_read(SECONDARY(backend), &mod1, sizeof(int));
+			if (mod != mod1)
+			{
+				show_error("%s: modifier deos not match between backends master(%d) and secondary(%d)",
+						 func, ntohl(mod), ntohl(mod1));
+			}
+		}
+		pool_write(frontend, &mod, sizeof(int));
+	}
+
+	return num_fields;
+}
+
+static POOL_STATUS AsciiRow(POOL_CONNECTION *frontend, 
+							POOL_CONNECTION_POOL *backend,
+							short num_fields)
+{
+	char * func = "AsciiRow()";
+	static char nullmap[8192], nullmap1[8192];
+	int nbytes;
+	int i;
+	unsigned char mask;
+	int size, size1;
+	char *buf;
+	char msgbuf[1024];
+
+	pool_write(frontend, "D", 1);
+
+	nbytes = (num_fields + 7)/8;
+
+	if (nbytes <= 0)
+		return POOL_CONTINUE;
+
+	/* NULL map */
+	pool_read(MASTER(backend), nullmap, nbytes);
+	if (pool_write(frontend, nullmap, nbytes) < 0)
+		return POOL_END;
+
+	if (REPLICATION)
+	{
+		if (pool_read(SECONDARY(backend), nullmap1, nbytes) < 0)
+			return POOL_END;
+
+		if (memcmp(nullmap, nullmap1, nbytes))
+		{
+			/* XXX: NULLMAP maybe different among
+			   backends. If we were a paranoid, we have to treat
+			   this as a fatal error. However in the real world
+			   we'd better to adapt this situation. Just throw a
+			   log... */
+			show_error("%s: NULLMAP differ between master and secondary",func);
+		}
+	}
+
+	mask = 0;
+
+	for (i = 0;i<num_fields;i++)
+	{
+		if (mask == 0)
+			mask = 0x80;
+
+		/* NOT NULL? */
+		if (mask & nullmap[i/8])
+		{
+			/* field size */
+			if (pool_read(MASTER(backend), &size, sizeof(int)) < 0)
+				return POOL_END;
+		}
+
+		if (REPLICATION && (mask & nullmap1[i/8]))
+		{
+			/* XXX: field size maybe different among
+			   backends. If we were a paranoid, we have to treat
+			   this as a fatal error. However in the real world
+			   we'd better to adapt this situation. Just throw a
+			   log... */
+
+			if (pool_read(SECONDARY(backend), &size1, sizeof(int)) < 0)
+				return POOL_END;
+
+			if (size != size1)
+				show_error("%s: %d th field size does not match between master(%d) and secondary(%d)",
+						 func, i, ntohl(size), ntohl(size1));
+			size1 = ntohl(size1) - 4;
+		}
+
+		buf = NULL;
+
+		if (mask & nullmap[i/8])
+		{
+			/* forward to frontend */
+			pool_write(frontend, &size, sizeof(int));
+			size = ntohl(size) - 4;
+
+			/* read and send actual data only when size > 0 */
+			if (size > 0)
+			{
+				buf = pool_read2(MASTER(backend), size);
+				if (buf == NULL)
+					return POOL_END;
+			}
+		}
+
+		if (REPLICATION && size1 > 0 && (mask & nullmap1[i/8]))
+		{
+			/* read and discard secondary data */
+			if (pool_read2(SECONDARY(backend), size1) == NULL)
+				return POOL_END;
+		}
+
+		if (buf)
+		{
+			pool_write(frontend, buf, size);
+			snprintf(msgbuf, Min(sizeof(msgbuf), size+1), "%s", buf);
+#ifdef PRINT_DEBUG
+			show_debug("%s: len: %d data: %s", func, size, msgbuf);
+#endif			
+		}
+
+		mask >>= 1;
+	}
+
+	return POOL_CONTINUE;
+}
+
+static POOL_STATUS BinaryRow(POOL_CONNECTION *frontend, 
+							 POOL_CONNECTION_POOL *backend,
+							 short num_fields)
+{
+	char * func = "BinaryRow()";
+	static char nullmap[8192], nullmap1[8192];
+	int nbytes;
+	int i;
+	unsigned char mask;
+	int size, size1;
+	char *buf;
+
+	pool_write(frontend, "B", 1);
+
+	nbytes = (num_fields + 7)/8;
+
+	if (nbytes <= 0)
+		return POOL_CONTINUE;
+
+	/* NULL map */
+	pool_read(MASTER(backend), nullmap, nbytes);
+	if (pool_write(frontend, nullmap, nbytes) < 0)
+		return POOL_END;
+
+	if (REPLICATION)
+	{
+		if (pool_read(SECONDARY(backend), nullmap1, nbytes) < 0)
+			return POOL_END;
+
+		if (memcmp(nullmap, nullmap1, nbytes))
+		{
+			/* XXX: NULLMAP maybe different among
+			   backends. If we were a paranoid, we have to treat
+			   this as a fatal error. However in the real world
+			   we'd better to adapt this situation. Just throw a
+			   log... */
+			show_error("%s: NULLMAP differ between master and secondary",func);
+		}
+	}
+
+	mask = 0;
+
+	for (i = 0;i<num_fields;i++)
+	{
+		if (mask == 0)
+			mask = 0x80;
+
+		/* NOT NULL? */
+		if (mask & nullmap[i/8])
+		{
+			/* field size */
+			if (pool_read(MASTER(backend), &size, sizeof(int)) < 0)
+				return POOL_END;
+		}
+
+		if (REPLICATION && (mask & nullmap1[i/8]))
+		{
+			/* XXX: field size maybe different among
+			   backends. If we were a paranoid, we have to treat
+			   this as a fatal error. However in the real world
+			   we'd better to adapt this situation. Just throw a
+			   log... */
+
+			if (pool_read(SECONDARY(backend), &size1, sizeof(int)) < 0)
+				return POOL_END;
+
+			if (size != size1)
+				show_error("%s: %d th field size does not match between master(%d) and secondary(%d)",
+						 func, i, ntohl(size), ntohl(size1));
+			size1 = ntohl(size1) - 4;
+		}
+
+		buf = NULL;
+
+		if (mask & nullmap[i/8])
+		{
+			/* forward to frontend */
+			pool_write(frontend, &size, sizeof(int));
+			size = ntohl(size) - 4;
+
+			/* read and send actual data only when size > 0 */
+			if (size > 0)
+			{
+				buf = pool_read2(MASTER(backend), size);
+				if (buf == NULL)
+					return POOL_END;
+			}
+		}
+
+		if (REPLICATION && size1 > 0 && (mask & nullmap1[i/8]))
+		{
+			/* read and discard secondary data */
+			if (pool_read2(SECONDARY(backend), size1) == NULL)
+				return POOL_END;
+		}
+
+		if (buf)
+			pool_write(frontend, buf, size);
+
+		mask >>= 1;
+	}
+	return POOL_CONTINUE;
+}
+
+static POOL_STATUS CursorResponse(POOL_CONNECTION *frontend, 
+								  POOL_CONNECTION_POOL *backend)
+{
+	char * func = "CursorResponse()";
+	char *string, *string1;
+	int len, len1;
+
+	/* read cursor name */
+	string = pool_read_string(MASTER(backend), &len, 0);
+	if (string == NULL)
+		return POOL_END;
+	if (REPLICATION)
+	{
+		string1 = pool_read_string(SECONDARY(backend), &len1, 0);
+		if (string1 == NULL)
+			return POOL_END;
+		if (len != len1)
+		{
+			show_error("%s: length does not match between master(%d) and secondary(%d)",
+					   func, len, len1);
+			show_error("%s: master(%s) secondary(%s)", func, string, string1);
+			return POOL_END;
+		}
+	}
+
+	/* forward to the frontend */
+	pool_write(frontend, "P", 1);
+	if (pool_write(frontend, string, len) < 0)
+	{
+		return POOL_END;
+	}
+	return POOL_CONTINUE;
+}
+
+POOL_STATUS ErrorResponse(POOL_CONNECTION *frontend, 
+						  POOL_CONNECTION_POOL *backend)
+{
+	char *string;
+	int len;
+
+	/* read error message */
+	string = pool_read_string(MASTER(backend), &len, 0);
+	if (string == NULL)
+		return POOL_END;
+	if (REPLICATION)
+	{
+		string = pool_read_string(SECONDARY(backend), &len, 0);
+		if (string == NULL)
+			return POOL_END;
+	}
+
+	/* forward to the frontend */
+	pool_write(frontend, "E", 1);
+	if (pool_write_and_flush(frontend, string, len) < 0)
+		return POOL_END;
+			
+	return POOL_CONTINUE;
+}
+
+static POOL_STATUS NoticeResponse(POOL_CONNECTION *frontend, 
+								  POOL_CONNECTION_POOL *backend)
+{
+	char *string, *string1;
+	int len, len1;
+
+	/* read notice message */
+	string = pool_read_string(MASTER(backend), &len, 0);
+	if (string == NULL)
+		return POOL_END;
+	if (REPLICATION)
+	{
+		string1 = pool_read_string(SECONDARY(backend), &len1, 0);
+		if (string1 == NULL)
+			return POOL_END;
+	}
+
+	/* forward to the frontend */
+	pool_write(frontend, "N", 1);
+	if (pool_write_and_flush(frontend, string, len) < 0)
+	{
+		return POOL_END;
+	}
+	return POOL_CONTINUE;
+}
+
+static POOL_STATUS CopyInResponse(POOL_CONNECTION *frontend, 
+								  POOL_CONNECTION_POOL *backend)
+{
+	POOL_STATUS status;
+
+	/* forward to the frontend */
+	if (MAJOR(backend) == PROTO_MAJOR_V3)
+	{
+		if (SimpleForwardToFrontend('G', frontend, backend) != POOL_CONTINUE)
+			return POOL_END;
+		if (pool_flush(frontend) != POOL_CONTINUE)
+			return POOL_END;
+	}
+	else
+		if (pool_write_and_flush(frontend, "G", 1) < 0)
+			return POOL_END;
+
+	status = CopyDataRows(frontend, backend, 1);
+	return status;
+}
+
+static POOL_STATUS CopyOutResponse(POOL_CONNECTION *frontend, 
+								   POOL_CONNECTION_POOL *backend)
+{
+	POOL_STATUS status;
+
+	/* forward to the frontend */
+	if (MAJOR(backend) == PROTO_MAJOR_V3)
+	{
+		if (SimpleForwardToFrontend('H', frontend, backend) != POOL_CONTINUE)
+			return POOL_END;
+		if (pool_flush(frontend) != POOL_CONTINUE)
+			return POOL_END;
+	}
+	else
+		if (pool_write_and_flush(frontend, "H", 1) < 0)
+			return POOL_END;
+
+	status = CopyDataRows(frontend, backend, 0);
+	return status;
+}
+
+static POOL_STATUS CopyDataRows(POOL_CONNECTION *frontend,
+								POOL_CONNECTION_POOL *backend, int copyin)
+{
+#ifdef PRINT_DEBUG
+	char * func = "CopyDataRows()";
+#endif
+	char *string;
+	int len;
+
+#ifdef PRINT_DEBUG
+	int i = 0;
+	char buf[1024];
+#endif
+
+	for (;;)
+	{
+		if (copyin)
+		{
+			if (MAJOR(backend) == PROTO_MAJOR_V3)
+			{
+				char kind;
+
+				if (pool_read(frontend, &kind, 1) < 0)
+					return POOL_END;
+				
+				SimpleForwardToBackend(kind, frontend, backend);
+
+				/* CopyData? */
+				if (kind == 'd')
+					continue;
+				else
+					break;
+			}
+			else
+				string = pool_read_string(frontend, &len, 1);
+		}
+		else
+		{
+			/* CopyOut */
+			if (MAJOR(backend) == PROTO_MAJOR_V3)
+			{
+				signed char kind;
+
+				if ((kind = pool_read_kind(backend)) < 0)
+					return POOL_END;
+				
+				SimpleForwardToFrontend(kind, frontend, backend);
+
+				/* CopyData? */
+				if (kind == 'd')
+					continue;
+				else
+					break;
+			}
+			else
+			{
+				string = pool_read_string(MASTER(backend), &len, 1);
+				if (REPLICATION)
+					string = pool_read_string(SECONDARY(backend), &len, 1);
+			}
+		}
+
+		if (string == NULL)
+			return POOL_END;
+
+#ifdef PRINT_DEBUG
+		strncpy(buf, string, len);
+		show_debug("%s: copy line %d %d bytes :%s:",func, i++, len, buf);
+#endif
+
+		if (copyin)
+		{
+			pool_write(MASTER(backend), string, len);
+			if (REPLICATION)
+				pool_write(SECONDARY(backend), string, len);
+		}
+		else
+			pool_write(frontend, string, len);			
+
+		if (len == PROTO_MAJOR_V3)
+		{
+			/* end of copy? */
+			if (string[0] == '\\' &&
+				string[1] == '.' &&
+				string[2] == '\n')
+			{
+				break;
+			}
+		}
+	}
+
+	if (copyin)
+	{
+		if (pool_flush(MASTER(backend)) <0)
+			return POOL_END;
+		if (REPLICATION)
+		{
+			if (pool_flush(SECONDARY(backend)) <0)
+				return POOL_END;
+		}
+	}
+	else
+		if (pool_flush(frontend) <0)
+			return POOL_END;
+
+	return POOL_CONTINUE;
+}
+
+static POOL_STATUS EmptyQueryResponse(POOL_CONNECTION *frontend,
+									  POOL_CONNECTION_POOL *backend)
+{
+	char c;
+
+	if (pool_read(MASTER(backend), &c, sizeof(c)) < 0)
+		return POOL_END;
+
+	if (REPLICATION)
+	{
+		if (pool_read(SECONDARY(backend), &c, sizeof(c)) < 0)
+			return POOL_END;
+	}
+
+	pool_write(frontend, "I", 1);
+	return pool_write_and_flush(frontend, "", 1);
+}
+
+static POOL_STATUS NotificationResponse(POOL_CONNECTION *frontend, 
+										POOL_CONNECTION_POOL *backend)
+{
+	int pid, pid1;
+	char *condition, *condition1;
+	int len, len1;
+
+	pool_write(frontend, "A", 1);
+
+	if (pool_read(MASTER(backend), &pid, sizeof(pid)) < 0)
+		return POOL_ERROR;
+
+	if (REPLICATION)
+	{
+		if (pool_read(SECONDARY(backend), &pid1, sizeof(pid1)) < 0)
+			return POOL_ERROR;
+	}
+
+	condition = pool_read_string(MASTER(backend), &len, 0);
+	if (condition == NULL)
+		return POOL_END;
+	if (REPLICATION)
+	{
+		condition1 = pool_read_string(SECONDARY(backend), &len1, 0);
+		if (condition1 == NULL)
+			return POOL_END;
+	}
+
+	pool_write(frontend, &pid, sizeof(pid));
+
+	return pool_write_and_flush(frontend, condition, len);
+}
+
+static POOL_STATUS FunctionCall(POOL_CONNECTION *frontend, 
+								POOL_CONNECTION_POOL *backend)
+{
+	char dummy[2];
+	int oid;
+	int argn;
+	int i;
+
+	pool_write(MASTER(backend), "F", 1);
+	if (REPLICATION)
+		pool_write(SECONDARY(backend), "F", 1);
+
+	/* dummy */
+	if (pool_read(frontend, dummy, sizeof(dummy)) < 0)
+		return POOL_ERROR;
+	pool_write(MASTER(backend), dummy, sizeof(dummy));
+	if (REPLICATION)
+		pool_write(SECONDARY(backend), dummy, sizeof(dummy));
+
+	/* function object id */
+	if (pool_read(frontend, &oid, sizeof(oid)) < 0)
+		return POOL_ERROR;
+
+	pool_write(MASTER(backend), &oid, sizeof(oid));
+	if (REPLICATION)
+		pool_write(SECONDARY(backend), &oid, sizeof(oid));
+
+	/* number of arguments */
+	if (pool_read(frontend, &argn, sizeof(argn)) < 0)
+		return POOL_ERROR;
+	pool_write(MASTER(backend), &argn, sizeof(argn));
+	if (REPLICATION)
+		pool_write(SECONDARY(backend), &argn, sizeof(argn));
+
+	argn = ntohl(argn);
+
+	for (i=0;i<argn;i++)
+	{
+		int len;
+		char *arg;
+
+		/* length of each argument in bytes */
+		if (pool_read(frontend, &len, sizeof(len)) < 0)
+			return POOL_ERROR;
+
+		pool_write(MASTER(backend), &len, sizeof(len));
+		if (REPLICATION)
+			pool_write(SECONDARY(backend), &len, sizeof(len));
+
+		len = ntohl(len);
+
+		/* argument value itself */
+		if ((arg = pool_read2(frontend, len)) == NULL)
+			return POOL_ERROR;
+		pool_write(MASTER(backend), arg, len);
+		if (REPLICATION)
+			pool_write(SECONDARY(backend), arg, len);
+	}
+
+	if (pool_flush(MASTER(backend)))
+		return POOL_ERROR;
+	if (REPLICATION)
+		if (pool_flush(SECONDARY(backend)))
+			return POOL_ERROR;
+	return POOL_CONTINUE;
+}
+
+static POOL_STATUS FunctionResultResponse(POOL_CONNECTION *frontend, 
+										  POOL_CONNECTION_POOL *backend)
+{
+	char dummy;
+	int len;
+	char *result;
+
+	pool_write(frontend, "V", 1);
+
+	if (pool_read(MASTER(backend), &dummy, 1) < 0)
+		return POOL_ERROR;
+	if (REPLICATION)
+		if (pool_read(SECONDARY(backend), &dummy, 1) < 0)
+			return POOL_ERROR;
+
+	pool_write(frontend, &dummy, 1);
+
+	/* non empty result? */
+	if (dummy == 'G')
+	{
+		/* length of result in bytes */
+		if (pool_read(MASTER(backend), &len, sizeof(len)) < 0)
+			return POOL_ERROR;
+		if (REPLICATION)
+			if (pool_read(SECONDARY(backend), &len, sizeof(len)) < 0)
+				return POOL_ERROR;
+
+		pool_write(frontend, &len, sizeof(len));
+
+		len = ntohl(len);
+
+		/* result value itself */
+		if ((result = pool_read2(MASTER(backend), len)) == NULL)
+			return POOL_ERROR;
+		if (REPLICATION)
+			if (pool_read(SECONDARY(backend), result, len) < 0)
+				return POOL_ERROR;
+
+		pool_write(frontend, result, len);
+	}
+
+	/* unused ('0') */
+	if (pool_read(MASTER(backend), &dummy, 1) < 0)
+		return POOL_ERROR;
+	if (REPLICATION)
+		if (pool_read(SECONDARY(backend), &dummy, 1) < 0)
+			return POOL_ERROR;
+
+	pool_write(frontend, "0", 1);
+
+	return pool_flush(frontend);
+}
+
+static POOL_STATUS ProcessFrontendResponse(POOL_CONNECTION *frontend, 
+										   POOL_CONNECTION_POOL *backend)
+{
+	char * func = "ProcessFrontendResponse()";
+	char fkind;
+	POOL_STATUS status;
+
+	if (frontend->len <= 0 && frontend->no_forward != 0)
+		return POOL_CONTINUE;
+
+	if (pool_read(frontend, &fkind, 1) < 0)
+	{
+		show_error("%s: failed to read kind",func);
+		return POOL_END;
+	}
+
+#ifdef PRINT_DEBUG
+	show_debug("%s:read kind from frontend %c(%02x)", func, fkind, fkind);
+#endif			
+
+	switch (fkind)
+	{
+		case 'X':
+			if (MAJOR(backend) == PROTO_MAJOR_V3)
+			{
+				int len;
+				pool_read(frontend, &len, sizeof(len));
+			}
+			status = POOL_END;
+			break;
+
+		case 'Q':
+			status = Query(frontend, backend, NULL);
+			break;
+
+		default:
+			if (MAJOR(backend) == PROTO_MAJOR_V3)
+			{
+				status = SimpleForwardToBackend(fkind, frontend, backend);
+				if (pool_flush(MASTER(backend)))
+					status = POOL_ERROR;
+				if (REPLICATION)
+					if (pool_flush(SECONDARY(backend)))
+						status = POOL_ERROR;
+			}
+			else if (MAJOR(backend) == PROTO_MAJOR_V2 && fkind == 'F')
+				status = FunctionCall(frontend, backend);
+			else
+			{
+				show_error("%s: unknown message type %c(%02x)", func, fkind, fkind);
+				status = POOL_ERROR;
+			}
+			break;
+	}
+
+	return status;
+}
+
+static int timeoutmsec;
+/*
+ * enable read timeout
+ */
+void pool_enable_timeout(void)
+{
+	timeoutmsec = pool_config_replication_timeout;
+}
+
+/*
+ * disable read timeout
+ */
+void pool_disable_timeout(void)
+{
+	timeoutmsec = 0;
+}
+
+/*
+ * wait until read data is ready
+ */
+static int synchronize(POOL_CONNECTION *cp)
+{
+	return pool_check_fd(cp, 1);
+}
+
+/*
+ * wait until read data is ready
+ * if notimeout is non 0, wait forever.
+ */
+int pool_check_fd(POOL_CONNECTION *cp, int notimeout)
+{
+	char * func = "pool_check_fd()";
+	fd_set readmask;
+	fd_set exceptmask;
+	int fd;
+	int fds;
+	struct timeval timeout;
+	struct timeval *tp;
+
+	fd = cp->fd;
+
+	for (;;)
+	{
+		FD_ZERO(&readmask);
+		FD_ZERO(&exceptmask);
+		FD_SET(fd, &readmask);
+		FD_SET(fd, &exceptmask);
+
+		if (notimeout || timeoutmsec == 0)
+			tp = NULL;
+		else
+		{
+			timeout.tv_sec = 0;
+			timeout.tv_usec = pool_config_replication_timeout*1000;
+			tp = &timeout;
+		}
+
+		fds = select(fd+1, &readmask, NULL, &exceptmask, tp);
+
+		if (fds == -1)
+		{
+			if (errno == EAGAIN || errno == EINTR)
+				continue;
+
+			show_error("%s: select() failed. reason %s",func, strerror(errno));
+			break;
+		}
+
+		if (FD_ISSET(fd, &exceptmask))
+		{
+			show_error("%s: exception occurred",func);
+			break;
+		}
+
+		if (fds == 0)
+		{
+			show_error("%s: data is not ready tp->tv_sec %d tp->tp_usec %d", func, tp->tv_sec, tp->tv_usec);
+			break;
+		}
+		return 0;
+	}
+	return -1;
+}
+
+static void process_reporting(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend)
+{
+	static char *cursorname = "blank";
+	static short num_fields = 3;
+	static char *field_names[] = {"item", "value", "description"};
+	static int oid = 0;
+	static short fsize = -1;
+	static int mod = 0;
+	short n;
+	int i;
+	short s;
+	int len;
+	short colnum;
+
+	static char nullmap[2] = {0xff, 0xff};
+	int nbytes = (num_fields + 7)/8;
+
+#define MAXVALLEN 512
+
+	typedef struct {
+		char *name;
+		char value[MAXVALLEN+1];
+		char *desc;
+	} POOL_REPORT_STATUS;
+
+#define MAXITEMS 128
+
+	POOL_REPORT_STATUS status[MAXITEMS];
+
+	short nrows;
+	int size;
+	int hsize;
+
+	i = 0;
+
+	status[i].name = "inetdomain";
+	snprintf(status[i].value, MAXVALLEN, "%d", pool_config_inetdomain);
+	status[i].desc = "1 if accepting TCP/IP connection";
+	i++;
+
+	status[i].name = "port";
+	snprintf(status[i].value, MAXVALLEN, "%d", pool_config_port);
+	status[i].desc = "pgpool accepting port number";
+	i++;
+
+	status[i].name = "socket_dir";
+	snprintf(status[i].value, MAXVALLEN, "%s", pool_config_socket_dir);
+	status[i].desc = "pgpool socket directory";
+	i++;
+
+	status[i].name = "backend_host_name";
+	snprintf(status[i].value, MAXVALLEN, "%s", pool_config_backend_host_name);
+	status[i].desc = "master backend host name";
+	i++;
+
+	status[i].name = "backend_port";
+	snprintf(status[i].value, MAXVALLEN, "%d", pool_config_backend_port);
+	status[i].desc = "master backend port number";
+	i++;
+
+	status[i].name = "secondary_backend_host_name";
+	snprintf(status[i].value, MAXVALLEN, "%s", pool_config_secondary_backend_host_name);
+	status[i].desc = "secondary backend host name";
+	i++;
+
+	status[i].name = "secondary_backend_port";
+	snprintf(status[i].value, MAXVALLEN, "%d", pool_config_secondary_backend_port);
+	status[i].desc = "secondary backend port number";
+	i++;
+
+	status[i].name = "num_init_children";
+	snprintf(status[i].value, MAXVALLEN, "%d", pool_config_num_init_children);
+	status[i].desc = "# of children initially pre-forked";
+	i++;
+
+	status[i].name = "child_life_time";
+	snprintf(status[i].value, MAXVALLEN, "%d", pool_config_child_life_time);
+	status[i].desc = "if idle for this seconds, child exits (not implemented yet)";
+	i++;
+
+	status[i].name = "connection_life_time";
+	snprintf(status[i].value, MAXVALLEN, "%d", pool_config_connection_life_time);
+	status[i].desc = "if idle for this seconds, connection closes";
+	i++;
+
+	status[i].name = "max_pool";
+	snprintf(status[i].value, MAXVALLEN, "%d", pool_config_max_pool);
+	status[i].desc = "max # of connection pool per child";
+	i++;
+
+	status[i].name = "logdir";
+	snprintf(status[i].value, MAXVALLEN, "%s", pool_config_logdir);
+	status[i].desc = "logging directory";
+	i++;
+
+	status[i].name = "backend_socket_dir";
+	snprintf(status[i].value, MAXVALLEN, "%s", pool_config_backend_socket_dir);
+	status[i].desc = "Unix domain socket directory for the PostgreSQL server";
+	i++;
+
+	status[i].name = "replication_mode";
+	snprintf(status[i].value, MAXVALLEN, "%d", pool_config_replication_mode);
+	status[i].desc = "non 0 if operating in replication mode";
+	i++;
+
+	status[i].name = "replication_strict";
+	snprintf(status[i].value, MAXVALLEN, "%d", pool_config_replication_strict);
+	status[i].desc = "non 0 if operating in strict mode";
+	i++;
+
+	status[i].name = "replication_timeout";
+	snprintf(status[i].value, MAXVALLEN, "%d", pool_config_replication_timeout);
+	status[i].desc = "if secondary does not respond in this milli seconds, abort the session";
+	i++;
+
+	status[i].name = "current_backend_host_name";
+	snprintf(status[i].value, MAXVALLEN, "%s", pool_config_current_backend_host_name);
+	status[i].desc = "current master host name";
+	i++;
+
+	status[i].name = "current_backend_port";
+	snprintf(status[i].value, MAXVALLEN, "%d", pool_config_current_backend_port);
+	status[i].desc = "current master port #";
+	i++;
+
+	status[i].name = "replication_enabled";
+	snprintf(status[i].value, MAXVALLEN, "%d", pool_config_replication_enabled);
+	status[i].desc = "non 0 if actually operating in replication mode";
+	i++;
+
+	status[i].name = "load_balance_mode";
+	snprintf(status[i].value, MAXVALLEN, "%d", pool_config_load_balance_mode);
+	status[i].desc = "non 0 if operating in load balancing mode";
+	i++;
+
+	status[i].name = "replication_stop_on_mismatch";
+	snprintf(status[i].value, MAXVALLEN, "%d", pool_config_replication_stop_on_mismatch);
+	status[i].desc = "stop replication mode on fatal error";
+	i++;
+
+	nrows = i;
+
+	if (MAJOR(backend) == PROTO_MAJOR_V2)
+	{
+		/* cursor response */
+		pool_write(frontend, "P", 1);
+		pool_write(frontend, cursorname, strlen(cursorname)+1);
+	}
+
+	/* row description */
+	pool_write(frontend, "T", 1);
+
+	if (MAJOR(backend) == PROTO_MAJOR_V3)
+	{
+		len = sizeof(num_fields) + sizeof(len);
+
+		for (i=0;i<num_fields;i++)
+		{
+			char *f = field_names[i];
+			len += strlen(f)+1;
+			len += sizeof(oid);
+			len += sizeof(colnum);
+			len += sizeof(oid);
+			len += sizeof(s);
+			len += sizeof(mod);
+			len += sizeof(s);
+		}
+
+		len = htonl(len);
+		pool_write(frontend, &len, sizeof(len));
+	}
+
+	n = htons(num_fields);
+	pool_write(frontend, &n, sizeof(short));
+
+	for (i=0;i<num_fields;i++)
+	{
+		char *f = field_names[i];
+
+		pool_write(frontend, f, strlen(f)+1);		/* field name */
+
+		if (MAJOR(backend) == PROTO_MAJOR_V3)
+		{
+			pool_write(frontend, &oid, sizeof(oid));	/* table oid */
+			colnum = htons(i);
+			pool_write(frontend, &colnum, sizeof(colnum));	/* column number */
+		}
+
+		pool_write(frontend, &oid, sizeof(oid));		/* data type oid */
+		s = htons(fsize);
+		pool_write(frontend, &s, sizeof(fsize));		/* field size */
+		pool_write(frontend, &mod, sizeof(mod));		/* modifier */
+
+		if (MAJOR(backend) == PROTO_MAJOR_V3)
+		{
+			s = htons(0);
+			pool_write(frontend, &s, sizeof(fsize));	/* field format (text) */
+		}
+	}
+	pool_flush(frontend);
+
+	if (MAJOR(backend) == PROTO_MAJOR_V2)
+	{
+		/* ascii row */
+		for (i=0;i<nrows;i++)
+		{
+			pool_write(frontend, "D", 1);
+			pool_write_and_flush(frontend, nullmap, nbytes);
+
+			size = strlen(status[i].name);
+			hsize = htonl(size+4);
+			pool_write(frontend, &hsize, sizeof(hsize));
+			pool_write(frontend, status[i].name, size);
+
+			size = strlen(status[i].value);
+			hsize = htonl(size+4);
+			pool_write(frontend, &hsize, sizeof(hsize));
+			pool_write(frontend, status[i].value, size);
+
+			size = strlen(status[i].desc);
+			hsize = htonl(size+4);
+			pool_write(frontend, &hsize, sizeof(hsize));
+			pool_write(frontend, status[i].desc, size);
+		}
+	}
+	else
+	{
+		/* data row */
+		for (i=0;i<nrows;i++)
+		{
+			pool_write(frontend, "D", 1);
+			len = sizeof(len) + sizeof(nrows);
+			len += sizeof(int) + strlen(status[i].name);
+			len += sizeof(int) + strlen(status[i].value);
+			len += sizeof(int) + strlen(status[i].desc);
+			len = htonl(len);
+			pool_write(frontend, &len, sizeof(len));
+			s = htons(3);
+			pool_write(frontend, &s, sizeof(s));
+
+			len = htonl(strlen(status[i].name));
+			pool_write(frontend, &len, sizeof(len));
+			pool_write(frontend, status[i].name, strlen(status[i].name));
+
+			len = htonl(strlen(status[i].value));
+			pool_write(frontend, &len, sizeof(len));
+			pool_write(frontend, status[i].value, strlen(status[i].value));
+			
+			len = htonl(strlen(status[i].desc));
+			pool_write(frontend, &len, sizeof(len));
+			pool_write(frontend, status[i].desc, strlen(status[i].desc));
+		}
+	}
+
+	/* complete command response */
+	pool_write(frontend, "C", 1);
+	if (MAJOR(backend) == PROTO_MAJOR_V3)
+	{
+		len = htonl(sizeof(len) + strlen("SELECT")+1);
+		pool_write(frontend, &len, sizeof(len));
+	}
+	pool_write(frontend, "SELECT", strlen("SELECT")+1);
+
+	/* ready for query */
+	pool_write(frontend, "Z", 1);
+	if (MAJOR(backend) == PROTO_MAJOR_V3)
+	{
+		len = htonl(sizeof(len) + 1);
+		pool_write(frontend, &len, sizeof(len));
+		pool_write(frontend, "I", 1);
+	}
+
+	pool_flush(frontend);
+}
+
+void pool_send_frontend_exits(POOL_CONNECTION_POOL *backend)
+{
+	int len;
+
+	pool_write(MASTER(backend), "X", 1);
+
+	if (MAJOR(backend) == PROTO_MAJOR_V3)
+	{
+		len = htonl(4);
+		pool_write(MASTER(backend), &len, sizeof(len));
+	}
+
+	/*
+	 * XXX we cannot call pool_flush() here since backend may already
+	 * close the socket and pool_flush() automatically invokes fail
+	 * over handler. This could happen in copy command (remember the
+	 * famouse "lostsynchronization with server, resettin g
+	 * connection" message)
+	 */
+	fflush(MASTER(backend)->write_fd);
+
+	if (REPLICATION)
+	{
+		pool_write(SECONDARY(backend), "X", 1);
+		if (MAJOR(backend) == PROTO_MAJOR_V3)
+		{
+			len = htonl(4);
+			pool_write(MASTER(backend), &len, sizeof(len));
+		}
+		fflush(SECONDARY(backend)->write_fd);
+	}
+}
+
+/*
+ * -------------------------------------------------------
+ * V3 functions
+ * -------------------------------------------------------
+ */
+POOL_STATUS SimpleForwardToFrontend(char kind, POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend)
+{
+	char * func = "SimpleForwardToFrontend()";
+	int len, len1;
+	char *p;
+	int status;
+
+	pool_write(frontend, &kind, 1);
+
+	status = pool_read(MASTER(backend), &len, sizeof(len));
+	if (status < 0)
+	{
+		show_error("%s: error while reading message length",func);
+		return POOL_END;
+	}
+
+	if (REPLICATION)
+	{
+		status = pool_read(SECONDARY(backend), &len1, sizeof(len1));
+		if (status < 0)
+		{
+			show_error("%s: error while reading message length from secondary backend",func);
+			return POOL_END;
+		}
+
+		if (len != len1)
+		{
+			show_error("%s: length does not match between backends master(%d) secondary(%d) kind:(%c)",
+					 func, ntohl(len), ntohl(len1), kind);
+		}
+	}
+
+	pool_write(frontend, &len, sizeof(len));
+
+	len = ntohl(len);
+	len -= 4;
+
+	p = pool_read2(MASTER(backend), len);
+	if (p == NULL)
+		return POOL_END;
+
+	if (REPLICATION)
+	{
+		len1 = ntohl(len1);
+		len1 -= 4;
+		if (pool_read2(SECONDARY(backend), len1) == NULL)
+			return POOL_END;
+	}
+
+	return pool_write(frontend, p, len);
+}
+
+POOL_STATUS SimpleForwardToBackend(char kind, POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend)
+{
+	int len;
+	int sendlen;
+	char *p;
+
+	if (pool_write(MASTER(backend), &kind, 1))
+		return POOL_END;
+	if (REPLICATION)
+		if (pool_write(SECONDARY(backend), &kind, 1))
+			return POOL_END;
+
+	if (pool_read(frontend, &sendlen, sizeof(sendlen)))
+	{
+		return POOL_END;
+	}
+
+	len = ntohl(sendlen) - 4;
+
+	p = pool_read2(frontend, len);
+	if (p == NULL)
+		return POOL_END;
+
+	if (pool_write(MASTER(backend), &sendlen, sizeof(sendlen)))
+		return POOL_END;
+	if (pool_write(MASTER(backend), p, len))
+		return POOL_END;
+
+	if (REPLICATION)
+	{
+		if (pool_write(SECONDARY(backend), &sendlen, sizeof(sendlen)))
+			return POOL_END;
+		if (pool_write(SECONDARY(backend), p, len))
+			return POOL_END;
+	}
+
+	return POOL_CONTINUE;
+}
+
+POOL_STATUS ParameterStatus(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend)
+{
+#ifdef PRINT_DEBUG
+	char * func = "ParameterStatus()";
+#endif			
+	int len;
+	int sendlen;
+	char *p;
+	char *name;
+	char *value;
+
+	pool_write(frontend, "S", 1);
+
+	len = pool_read_message_length(backend);
+	if (len < 0)
+	{
+		return POOL_END;
+	}
+
+	sendlen = htonl(len);
+	pool_write(frontend, &sendlen, sizeof(sendlen));
+
+	len -= 4;
+
+	p = pool_read2(MASTER(backend), len);
+	if (p == NULL)
+		return POOL_END;
+
+	name = p;
+	value = p + strlen(name) + 1;
+
+#ifdef PRINT_DEBUG
+	show_debug("%s:name: %s value: %s",func, name, value);
+#endif			
+
+	pool_add_param(&MASTER(backend)->params, name, value);
+
+#ifdef PRINT_DEBUG
+	pool_param_debug_print(&MASTER(backend)->params);
+#endif
+
+	if (REPLICATION)
+		if (pool_read2(SECONDARY(backend), len) == NULL)
+			return POOL_END;
+
+	return pool_write(frontend, p, len);
+
+}
+
+/*
+ * reset backend status. return values are:
+ * 0: no query was issued 1: a query was issued 2: no more queries remain -1: error
+ */
+static int reset_backend(POOL_CONNECTION_POOL *backend, int qcnt)
+{
+#ifdef NO_RESET_ALL
+	static char *queries[] = {"ABORT"};
+#else
+	static char *queries[] = {"ABORT", "RESET ALL"};
+#endif
+
+	char *query;
+	int qn = sizeof(queries)/sizeof(char *);
+
+	/* for PGCluster */
+	if ((! Use_Connection_Pool) ||
+		(qcnt >= qn))
+		return 2;
+
+	query = queries[qcnt];
+
+	/* if transaction state is idle, we don't need to issue ABORT */
+	if (TSTATE(backend) == 'I' && !strcmp("ABORT", query))
+		return 0;
+
+	if (Query(NULL, backend, query) != POOL_CONTINUE)
+		return -1;
+
+	return 1;
+}
+
+/*
+ * return non 0 if load balance is possible
+ */
+static int load_balance_enabled(POOL_CONNECTION_POOL *backend, char *sql)
+{
+	if (pool_config_load_balance_mode &&
+		REPLICATION &&
+		MAJOR(backend) == PROTO_MAJOR_V3 &&
+		TSTATE(backend) == 'I' &&
+		!strncasecmp(sql, "SELECT", 6))
+		return 1;
+	return 0;
+}
+
+/*
+ * start load balance mode
+ */
+static void start_load_balance(POOL_CONNECTION_POOL *backend)
+{
+#ifdef PRINT_DEBUG
+	char * func = "start_load_balance()";
+#endif			
+	int i;
+	int master;
+
+	/* save backend connection slots */
+	for (i=0;i<backend->num;i++)
+	{
+		slots[i] = backend->slots[i];
+	}
+
+	/* temporary turn off replication mode */
+	/*REPLICATION = 0; */
+
+	/* choose a master in random manner */
+	master = random() % backend->num;
+	backend->slots[0] = slots[master];
+#ifdef PRINT_DEBUG
+	show_debug("%s: selected master is %d", func,master);
+#endif			
+
+	/* start load balancing */
+	/*in_load_balance = 1;*/
+}
+
+/*
+ * finish load balance mode
+ */
+static void end_load_balance(POOL_CONNECTION_POOL *backend)
+{
+	int i;
+
+	/* restore backend connection slots */
+	for (i=0;i<backend->num;i++)
+	{
+		backend->slots[i] = slots[i];
+	}
+
+	/* turn on replication mode */
+	/* REPLICATION = 1; */
+
+	/*in_load_balance = 0;*/
+#ifdef PRINT_DEBUG
+	show_debug("end_load_balance: end load balance mode");
+#endif			
+}
+
+/*
+ * send error message to frontend
+ */
+void pool_send_error_message(POOL_CONNECTION *frontend, int protoMajor,
+							 char *code,
+							 char *message,
+							 char *detail,
+							 char *hint,
+							 char *file,
+							 int line)
+{
+#define MAXDATA	1024
+#define MAXMSGBUF 128
+	char * func = "pool_send_error_message()";
+
+	if (protoMajor == PROTO_MAJOR_V2)
+	{
+		pool_write(frontend, "E", 1);
+		pool_write_and_flush(frontend, message, strlen(message)+1);
+	}
+	else if (protoMajor == PROTO_MAJOR_V3)
+	{
+		char data[MAXDATA];
+		char msgbuf[MAXMSGBUF];
+		int len;
+		int thislen;
+		int sendlen;
+
+		len = 0;
+
+		pool_write(frontend, "E", 1);
+
+		/* error level */
+		thislen = snprintf(msgbuf, MAXMSGBUF, "SERROR");
+		memcpy(data +len, msgbuf, thislen+1);
+		len += thislen + 1;
+
+		/* code */
+		thislen = snprintf(msgbuf, MAXMSGBUF, "C%s", code);
+		memcpy(data +len, msgbuf, thislen+1);
+		len += thislen + 1;
+
+		/* message */
+		thislen = snprintf(msgbuf, MAXMSGBUF, "M%s", message);
+		memcpy(data +len, msgbuf, thislen+1);
+		len += thislen + 1;
+
+		/* detail */
+		if (*detail != '\0')
+		{
+			thislen = snprintf(msgbuf, MAXMSGBUF, "D%s", detail);
+			memcpy(data +len, msgbuf, thislen+1);
+			len += thislen + 1;
+		}
+
+		/* hint */
+		if (*hint != '\0')
+		{
+			thislen = snprintf(msgbuf, MAXMSGBUF, "H%s", hint);
+			memcpy(data +len, msgbuf, thislen+1);
+			len += thislen + 1;
+		}
+
+		/* file */
+		thislen = snprintf(msgbuf, MAXMSGBUF, "F%s", file);
+		memcpy(data +len, msgbuf, thislen+1);
+		len += thislen + 1;
+
+		/* line */
+		thislen = snprintf(msgbuf, MAXMSGBUF, "L%d", line);
+		memcpy(data +len, msgbuf, thislen+1);
+		len += thislen + 1;
+
+		/* stop null */
+		len++;
+		*(data + len) = '\0';
+
+		sendlen = len;
+		len = htonl(len + 4);
+		pool_write(frontend, &len, sizeof(len));
+		pool_write_and_flush(frontend, data, sendlen);
+	}
+	else
+		show_error("%s: unknown protocol major %d",func, protoMajor);
+}
+
+#endif /* USE_REPLICATION */
diff -ruN postgresql-7.4.13-old/src/pgcluster/pglb/pool_stream.c postgresql-7.4.13/src/pgcluster/pglb/pool_stream.c
--- postgresql-7.4.13-old/src/pgcluster/pglb/pool_stream.c	1970-01-01 01:00:00.000000000 +0100
+++ postgresql-7.4.13/src/pgcluster/pglb/pool_stream.c	2006-08-05 16:53:43.000000000 +0200
@@ -0,0 +1,581 @@
+/*--------------------------------------------------------------------
+ * FILE:
+ *     pool_stream.c
+ *
+ * NOTE:
+ *     stream I/O modules
+ *
+ * Portions Copyright (c) 2003, 2004  Atsushi Mitani
+ * Portions Copyright (c) 2003, 2004  Tatsuo Ishii
+ *--------------------------------------------------------------------
+ */
+/*
+* 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.
+*/
+#ifdef USE_REPLICATION
+
+#include "postgres.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include "replicate_com.h"
+#include "pglb.h"
+
+#define READBUFSZ 1024
+
+POOL_CONNECTION *pool_open(int fd);
+void pool_close(POOL_CONNECTION *cp);
+int pool_read(POOL_CONNECTION *cp, void *buf, int len);
+char *pool_read2(POOL_CONNECTION *cp, int len);
+int pool_write(POOL_CONNECTION *cp, void *buf, int len);
+int pool_flush(POOL_CONNECTION *cp);
+int pool_write_and_flush(POOL_CONNECTION *cp, void *buf, int len);
+char *pool_read_string(POOL_CONNECTION *cp, int *len, int line);
+
+static int mystrlen(char *str, int upper, int *flag);
+static int mystrlinelen(char *str, int upper, int *flag);
+static int save_pending_data(POOL_CONNECTION *cp, void *data, int len);
+static int consume_pending_data(POOL_CONNECTION *cp, void *data, int len);
+
+
+/*
+* open read/write file descriptors.
+* returns POOL_CONNECTION on success otherwise NULL.
+*/
+POOL_CONNECTION *pool_open(int fd)
+{
+	POOL_CONNECTION *cp;
+
+	cp = (POOL_CONNECTION *)malloc(sizeof(POOL_CONNECTION));
+	if (cp == NULL)
+	{
+		show_error("pool_open: malloc failed: %s", strerror(errno));
+		return NULL;
+	}
+
+	memset(cp, 0, sizeof(*cp));
+
+	cp->write_fd = fdopen(fd, "w");
+	if (cp->write_fd == NULL)
+	{
+		show_error("pool_open: fdopen failed: %s",strerror(errno));
+		free(cp);
+		return NULL;
+	}
+
+	/* initialize pending data buffer */
+	cp->hp = malloc(READBUFSZ);
+	if (cp->hp == NULL)
+	{
+		show_error("pool_open: malloc failed");
+		return NULL;
+	}
+	cp->bufsz = READBUFSZ;
+	cp->po = 0;
+	cp->len = 0;
+	cp->sbuf = NULL;
+	cp->sbufsz = 0;
+	cp->buf2 = NULL;
+	cp->sbufsz = 0;
+
+	cp->fd = fd;
+	return cp;
+}
+
+/*
+* close read/write file descriptors.
+*/
+void pool_close(POOL_CONNECTION *cp)
+{
+	fclose(cp->write_fd);
+	free(cp->hp);
+	if (cp->sbuf)
+		free(cp->sbuf);
+	if (cp->buf2)
+		free(cp->buf2);
+	pool_discard_params(&cp->params);
+	free(cp);
+}
+
+/*
+* read len bytes from cp
+* returns 0 on success otherwise -1.
+*/
+int pool_read(POOL_CONNECTION *cp, void *buf, int len)
+{
+	static char readbuf[READBUFSZ];
+
+	int consume_size;
+	int readlen;
+
+	consume_size = consume_pending_data(cp, buf, len);
+	len -= consume_size;
+	buf += consume_size;
+
+	while (len > 0)
+	{
+		if (cp->issecondary_backend)
+		{
+			if (pool_check_fd(cp, 0))
+			{
+				show_error("pool_read: secondary data is not ready. abort this session");
+				exit(1);
+			}
+		}
+
+		readlen = read(cp->fd, readbuf, READBUFSZ);
+		if (readlen == -1)
+		{
+			show_error("pool_read: read failed (%s)", strerror(errno));
+
+			if (cp->isbackend)
+			{
+			    /* fatal error, notice to parent and exit */
+			    notice_backend_error();
+			    exit(1);
+			}
+			else
+			{
+			    return -1;
+			}
+		}
+		else if (readlen == 0)
+		{
+			show_error("pool_read: EOF encountered");
+
+			if (cp->isbackend)
+			{
+			    /* fatal error, notice to parent and exit */
+			    notice_backend_error();
+				exit(1);
+			}
+			else
+			{
+				/*
+				 * if backend offers authentication method, frontend could close connection
+				 */
+				return -1;
+			}
+		}
+
+		if (len < readlen)
+		{
+			/* overrun. we need to save remaining data to pending buffer */
+			if (save_pending_data(cp, readbuf+len, readlen-len))
+				return -1;
+			memmove(buf, readbuf, len);
+			break;
+		}
+
+		memmove(buf, readbuf, readlen);
+		buf += readlen;
+		len -= readlen;
+	}
+
+	return 0;
+}
+
+/*
+* read exactly len bytes from cp
+* returns buffer address on success otherwise NULL.
+*/
+char *pool_read2(POOL_CONNECTION *cp, int len)
+{
+	char *buf;
+	int req_size;
+	int alloc_size;
+	int consume_size;
+	int readlen;
+
+	req_size = cp->len + len;
+
+	if (req_size > cp->bufsz2)
+	{
+		alloc_size = ((req_size+1)/READBUFSZ+1)*READBUFSZ;
+		cp->buf2 = realloc(cp->buf2, alloc_size);
+		if (cp->buf2 == NULL)
+		{
+			show_error("pool_read2: failed to realloc");
+			exit(1);
+		}
+		cp->bufsz2 = alloc_size;
+	}
+
+	buf = cp->buf2;
+
+	consume_size = consume_pending_data(cp, buf, len);
+	len -= consume_size;
+	buf += consume_size;
+
+	while (len > 0)
+	{
+		if (cp->issecondary_backend)
+		{
+			if (pool_check_fd(cp, 0))
+			{
+				show_error("pool_read2: secondary data is not ready. abort this session");
+				exit(1);
+			}
+		}
+
+		readlen = read(cp->fd, buf, len);
+		if (readlen == -1)
+		{
+			show_error("pool_read2: read failed (%s)", strerror(errno));
+
+			if (cp->isbackend)
+			{
+			    /* fatal error, notice to parent and exit */
+			    notice_backend_error();
+			    exit(1);
+			}
+			else
+			{
+			    return NULL;
+			}
+		}
+		else if (readlen == 0)
+		{
+			show_error("pool_read2: EOF encountered");
+
+			if (cp->isbackend)
+			{
+			    /* fatal error, notice to parent and exit */
+			    notice_backend_error();
+				exit(1);
+			}
+			else
+			{
+				/*
+				 * if backend offers authentication method, frontend could close connection
+				 */
+				return NULL;
+			}
+		}
+
+		buf += readlen;
+		len -= readlen;
+	}
+
+	return cp->buf2;
+}
+
+/*
+* write len bytes from cp
+* returns 0 on success otherwise -1.
+*/
+int pool_write(POOL_CONNECTION *cp, void *buf, int len)
+{
+	if (!cp->no_forward)
+		fwrite(buf, len, 1, cp->write_fd);
+
+	return 0;
+}
+
+/*
+* flush write buffer
+*/
+int pool_flush(POOL_CONNECTION *cp)
+{
+	if (fflush(cp->write_fd) != 0)
+	{
+		show_error("pool_flush: fflush failed (%s)", strerror(errno));
+
+		if (cp->isbackend)
+		{
+		    notice_backend_error();
+		    exit(1);
+		}
+		else
+		{
+		    return -1;
+		}
+	}
+	return 0;
+}
+
+/*
+* combo of pool_write and pool_flush
+*/
+int pool_write_and_flush(POOL_CONNECTION *cp, void *buf, int len)
+{
+	if (pool_write(cp, buf, len))
+		return -1;
+	return pool_flush(cp);
+}
+
+/* 
+ * read a string until EOF or NULL is encountered.
+ * if line is not 0, read until new line is encountered.
+*/
+char *pool_read_string(POOL_CONNECTION *cp, int *len, int line)
+{
+	int readp;
+	int readsize;
+	int readlen;
+	int strlength;
+	int flag;
+	int consume_size;
+
+#ifdef DEBUG
+	static char pbuf[READBUFSZ];
+#endif
+
+	*len = 0;
+	readp = 0;
+
+	/* initialize read buffer */
+	if (cp->sbufsz == 0)
+	{
+		cp->sbuf = malloc(READBUFSZ);
+		if (cp->sbuf == NULL)
+		{
+			show_error("pool_read_string: malloc failed");
+			return NULL;
+		}
+		cp->sbufsz = READBUFSZ;
+		*cp->sbuf = '\0';
+	}
+
+	/* any pending data? */
+	if (cp->len)
+	{
+		if (line)
+			strlength = mystrlinelen(cp->hp+cp->po, cp->len, &flag);
+		else
+			strlength = mystrlen(cp->hp+cp->po, cp->len, &flag);
+
+		/* buffer is too small? */
+		if ((strlength + 1) > cp->sbufsz)
+		{
+			cp->sbufsz = ((strlength+1)/READBUFSZ+1)*READBUFSZ;
+			cp->sbuf = realloc(cp->sbuf, cp->sbufsz);
+			if (cp->sbuf == NULL)
+			{
+				show_error("pool_read_string: realloc failed");
+				return NULL;
+			}
+		}
+
+		/* consume pending and save to read string buffer */
+		consume_size = consume_pending_data(cp, cp->sbuf, strlength);
+
+		*len = strlength;
+
+		/* is the string null terminated? */
+		if (consume_size == strlength && !flag)
+		{
+			/* not null or line terminated.
+			 * we need to read more since we have not encountered NULL or new line yet
+			 */
+			readsize = cp->sbufsz - strlength;
+			readp = strlength;
+		}
+		else
+		{
+#ifdef PRINT_DEBUG
+			show_debug("pool_read_string: read all from pending data. po:%d len:%d",
+					   cp->po, cp->len);
+#endif			
+			return cp->sbuf;
+		}
+	} else
+	{
+		readsize = cp->sbufsz;
+	}
+
+
+	for (;;)
+	{
+		readlen = read(cp->fd, cp->sbuf+readp, readsize);
+		if (readlen == -1)
+		{
+			show_error("pool_read_string: read() failed. reason:%s", strerror(errno));
+
+			if (cp->isbackend)
+			{
+			    notice_backend_error();
+			    exit(1);
+			}
+			else
+			{
+			    return NULL;
+			}
+		}
+
+		/* check overrun */
+		if (line)
+			strlength = mystrlinelen(cp->sbuf+readp, readlen, &flag);
+		else
+			strlength = mystrlen(cp->sbuf+readp, readlen, &flag);
+
+		if (strlength < readlen)
+		{
+			save_pending_data(cp, cp->sbuf+readp+strlength, readlen-strlength);
+			*len += strlength;
+#ifdef PRINT_DEBUG
+			show_debug("pool_read_string: total result %d with pending data po:%d len:%d", *len, cp->po, cp->len);
+#endif			
+			return cp->sbuf;
+		}
+
+		*len += readlen;
+
+		/* encountered null or newline? */
+		if (flag)
+		{
+			/* ok we have read all data */
+#ifdef PRINT_DEBUG
+			show_debug("pool_read_string: total result %d ", *len);
+#endif			
+			break;
+		}
+
+		readp += readlen;
+		readsize = READBUFSZ;
+
+		if ((*len+readsize) > cp->sbufsz)
+		{
+			cp->sbufsz += READBUFSZ;
+
+			cp->sbuf = realloc(cp->sbuf, cp->sbufsz);
+			if (cp->sbuf == NULL)
+			{
+				show_error("pool_read_string: realloc failed");
+				return NULL;
+			}
+		}
+	}
+	return cp->sbuf;
+}
+
+/*
+ * returns the byte length of str, including \0, no more than upper.
+ * if encountered \0, flag is set to non 0.
+ * example:
+ *	mystrlen("abc", 2) returns 2
+ *	mystrlen("abc", 3) returns 3
+ *	mystrlen("abc", 4) returns 4
+ *	mystrlen("abc", 5) returns 4
+ */
+static int mystrlen(char *str, int upper, int *flag)
+{
+	int len;
+
+	*flag = 0;
+
+	for (len = 0;len < upper; len++, str++)
+	{
+	    if (!*str)
+	    {
+			len++;
+			*flag = 1;
+			break;
+	    }
+	}
+	return len;
+}
+
+/*
+ * returns the byte length of str terminated by \n or \0 (including \n or \0), no more than upper.
+ * if encountered \0 or \n, flag is set to non 0.
+ * example:
+ *	mystrlinelen("abc", 2) returns 2
+ *	mystrlinelen("abc", 3) returns 3
+ *	mystrlinelen("abc", 4) returns 4
+ *	mystrlinelen("abc", 5) returns 4
+ *	mystrlinelen("abcd\nefg", 4) returns 4
+ *	mystrlinelen("abcd\nefg", 5) returns 5
+ *	mystrlinelen("abcd\nefg", 6) returns 5
+ */
+static int mystrlinelen(char *str, int upper, int *flag)
+{
+	int len;
+
+	*flag = 0;
+
+	for (len = 0;len < upper; len++, str++)
+	{
+	    if (!*str || *str == '\n')
+	    {
+			len++;
+			*flag = 1;
+			break;
+	    }
+	}
+	return len;
+}
+
+/*
+ * save pending data
+ */
+static int save_pending_data(POOL_CONNECTION *cp, void *data, int len)
+{
+	int reqlen;
+	size_t realloc_size;
+	char *p;
+
+	/* to be safe */
+	if (cp->len == 0)
+		cp->po = 0;
+
+	reqlen = cp->po + cp->len + len;
+
+	/* pending buffer is enough? */
+	if (reqlen > cp->bufsz)
+	{
+		/* too small, enlarge it */
+		realloc_size = (reqlen/READBUFSZ+1)*READBUFSZ;
+		p = realloc(cp->hp, realloc_size);
+		if (p == NULL)
+		{
+			show_error("save_pending_data: realloc failed");
+			return -1;
+		}
+
+		cp->bufsz = realloc_size;
+		cp->hp = p;
+	}
+
+	memmove(cp->hp + cp->po + cp->len, data, len);
+	cp->len += len;
+
+	return 0;
+}
+
+/*
+ * consume pending data. returns actually consumed data length.
+ */
+static int consume_pending_data(POOL_CONNECTION *cp, void *data, int len)
+{
+	int consume_size;
+
+	if (cp->len <= 0)
+		return 0;
+
+	consume_size = Min(len, cp->len);
+	memmove(data, cp->hp + cp->po, consume_size);
+	cp->len -= consume_size;
+
+	if (cp->len <= 0)
+		cp->po = 0;
+	else
+		cp->po += consume_size;
+
+	return consume_size;
+}
+
+#endif /* USE_REPLICATION */
diff -ruN postgresql-7.4.13-old/src/pgcluster/pglb/recovery.c postgresql-7.4.13/src/pgcluster/pglb/recovery.c
--- postgresql-7.4.13-old/src/pgcluster/pglb/recovery.c	1970-01-01 01:00:00.000000000 +0100
+++ postgresql-7.4.13/src/pgcluster/pglb/recovery.c	2006-08-05 16:53:43.000000000 +0200
@@ -0,0 +1,241 @@
+/*--------------------------------------------------------------------
+ * FILE:
+ *     recovery.c
+ *
+ * NOTE:
+ *     This file is composed of the functions to call with the source
+ *     at pglb for the recovery.
+ *
+ * Portions Copyright (c) 2003, Atsushi Mitani
+ *--------------------------------------------------------------------
+ */
+/*
+ * 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.
+ *
+*/
+#ifdef USE_REPLICATION
+
+#include "postgres.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sys/wait.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/ipc.h>
+#include <sys/msg.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/time.h>
+#include <time.h>
+#include <sys/param.h>
+#include <arpa/inet.h>
+#include <sys/file.h>
+
+#ifdef HAVE_NETINET_TCP_H
+#include <netinet/tcp.h>
+#endif
+
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+#include "replicate_com.h"
+#include "pglb.h"
+
+
+/*--------------------------------------
+ * PROTOTYPE DECLARATION
+ *--------------------------------------
+ */
+void PGRrecovery_main(void);
+
+static int set_recovery(RecoveryPacket *packet);
+static int receive_recovery(int fd);
+
+
+/*--------------------------------------------------------------------
+ * SYMBOL
+ *    PGRrecovery_main()
+ * NOTES
+ *    main module of recovery function
+ * ARGS
+ *    void
+ * RETURN
+ *    none
+ *--------------------------------------------------------------------
+ */
+void
+PGRrecovery_main(void)
+{
+	char * func = "PGRrecovery_main()";
+	int fd = -1;
+	int rtn;
+
+	fd = PGRcreate_recv_socket("", Com_Info.ConfData_Info.Recovery_Port_Number);
+	if (fd < 0)
+	{
+		show_error("%s:PGRcreate_recv_socket failed",func);
+		exit(1);
+	}
+	
+	for (;;)
+	{
+		fd_set	  rmask;
+		struct timeval timeout;
+
+		timeout.tv_sec = 60;
+		timeout.tv_usec = 0;
+
+		/*
+		 * Wait for something to happen.
+		 */
+		FD_ZERO(&rmask);
+		FD_SET(fd,&rmask);
+		rtn = select(fd+1, &rmask, (fd_set *)NULL, (fd_set *)NULL, &timeout);
+		if (rtn && FD_ISSET(fd, &rmask))
+		{
+			receive_recovery(fd);
+		}
+	}
+}
+
+/*--------------------------------------------------------------------
+ * SYMBOL
+ *    set_recovery()
+ * NOTES
+ *    check a recovery request from replication server
+ * ARGS
+ *    void
+ * RETURN
+ *    none
+ *--------------------------------------------------------------------
+ */
+static int
+set_recovery(RecoveryPacket *packet)
+{
+#ifdef PRINT_DEBUG
+	char * func = "set_recovery()";
+#endif			
+	int status = STATUS_OK;
+	ClusterTbl key;
+	ClusterTbl * ptr;
+
+	PGRset_key_of_cluster(&key,packet);
+#ifdef PRINT_DEBUG
+	show_debug("%s:received no:%d",func, ntohs(packet->packet_no));
+#endif			
+	switch (ntohs(packet->packet_no))
+	{
+	case RECOVERY_PREPARE_REQ:
+		/* add cluster db */
+#ifdef PRINT_DEBUG
+		show_debug("%s:add_db host:%s port:%d max:%d",
+			func, packet->hostName,ntohs(packet->port),ntohs(packet->max_connect));
+#endif			
+		ptr = PGRsearch_cluster_tbl(&key);
+		if (ptr == NULL)
+		{
+			ptr = PGRadd_cluster_tbl(&key);
+		}
+		if (ptr != NULL)
+		{
+			PGRset_status_on_cluster_tbl(TBL_STOP,ptr);
+			if (Use_Connection_Pool)
+			{
+				signal(SIGCHLD,PGRrecreate_child);
+				status = PGRpre_fork_child(ptr);
+			}
+		}
+		break;
+	case RECOVERY_FINISH:
+		/* start cluster db */
+		ptr = PGRsearch_cluster_tbl(&key);
+		if (ptr != NULL)
+		{
+#ifdef PRINT_DEBUG
+			show_debug("%s:start_db host:%s port:%d max:%d",
+				func,packet->hostName,ntohs(packet->port),ntohs(packet->max_connect));
+#endif			
+			PGRset_status_on_cluster_tbl(TBL_USE,ptr);
+		}
+		break;
+	case RECOVERY_PGDATA_ANS:
+		/* stop cluster db */
+		ptr = PGRsearch_cluster_tbl(&key);
+		if (ptr != NULL)
+		{
+#ifdef PRINT_DEBUG
+			show_debug("%s:stop_db host:%s port:%d max:%d",
+				func, packet->hostName,ntohs(packet->port),ntohs(packet->max_connect));
+#endif			
+			PGRset_status_on_cluster_tbl(TBL_STOP,ptr);
+		}
+		break;
+	case RECOVERY_ERROR:
+		/* delete cluster db */
+		ptr = PGRsearch_cluster_tbl(&key);
+		if (ptr != NULL)
+		{
+			PGRset_status_on_cluster_tbl(TBL_FREE,ptr);
+			if (Use_Connection_Pool)
+			{
+				PGRquit_children_on_cluster(ptr->rec_no);
+			}
+		}
+		break;
+	/* cluster db has error */
+	case RECOVERY_ERROR_CONNECTION:
+		/* set error cluster db */
+		ptr = PGRsearch_cluster_tbl(&key);
+		if (ptr != NULL)
+		{
+			PGRset_status_on_cluster_tbl(TBL_ERROR,ptr);
+			if (Use_Connection_Pool)
+			{
+				PGRquit_children_on_cluster(ptr->rec_no);
+			}
+		}
+		break;
+	}
+	return STATUS_OK;
+}
+
+static int
+receive_recovery(int fd)
+{
+	int status = STATUS_ERROR;
+	int r_size = -1;
+	int recv_sock = -1;
+	RecoveryPacket packet;
+
+	recv_sock = PGRcreate_acception(fd,"",Com_Info.ConfData_Info.Recovery_Port_Number);
+	if (recv_sock >= 0 )
+	{
+		memset(&packet,0, sizeof(RecoveryPacket));
+		r_size = PGRread_byte(recv_sock,(char *)&packet,sizeof(RecoveryPacket),MSG_WAITALL);
+		if ( r_size == sizeof(RecoveryPacket) )
+		{
+			status = set_recovery(&packet);
+		}
+	}
+	PGRclose_sock(&recv_sock);
+	return status;
+}
+
+#endif /* USE_REPLICATION */
diff -ruN postgresql-7.4.13-old/src/pgcluster/pglb/socket.c postgresql-7.4.13/src/pgcluster/pglb/socket.c
--- postgresql-7.4.13-old/src/pgcluster/pglb/socket.c	1970-01-01 01:00:00.000000000 +0100
+++ postgresql-7.4.13/src/pgcluster/pglb/socket.c	2006-08-05 16:53:43.000000000 +0200
@@ -0,0 +1,401 @@
+/*--------------------------------------------------------------------
+ * FILE:
+ *     socket.c
+ *
+ * NOTE:
+ *     This file is composed of the communication modules
+ *
+ * Portions Copyright (c) 2003, Atsushi Mitani
+ *--------------------------------------------------------------------
+ */
+/*
+ * 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.
+ *
+*/
+#ifdef USE_REPLICATION
+
+#include "postgres.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/ipc.h>
+#include <netdb.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/time.h>
+#include <time.h>
+#include <sys/param.h>
+#include <sys/file.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+
+#ifdef HAVE_NETINET_TCP_H
+#include <netinet/tcp.h>
+#endif
+
+#include "replicate_com.h"
+#include "pglb.h"
+
+
+/*--------------------------------------
+ * PROTOTYPE DECLARATION
+ *--------------------------------------
+ */
+int PGRcreate_unix_domain_socket(char * sock_dir, unsigned short port);
+int PGRcreate_recv_socket(char * hostName , unsigned short portNumber);
+int PGRcreate_acception(int fd, char * hostName , unsigned short portNumber);
+void PGRclose_sock(int * sock);
+int PGRread_byte(int sock,char * buf,int len, int flag);
+int PGRcreate_cluster_socket( int * sock, ClusterTbl * ptr );
+
+static int create_send_socket(int * fdP, char * hostName , unsigned short portNumber);
+
+
+/*
+* create UNIX domain socket
+*/
+int 
+PGRcreate_unix_domain_socket(char * sock_dir, unsigned short port)
+{
+	char * func = "PGRcreate_unix_domain_socket()";
+	struct sockaddr_un addr;
+	int fd;
+	int status;
+	int len;
+
+	/* set unix domain socket path */
+	fd = socket(AF_UNIX, SOCK_STREAM, 0);
+	if (fd == -1)
+	{
+		show_error("%s:Failed to create UNIX domain socket. reason: %s",func,  strerror(errno));
+		return -1;
+	}
+	memset((char *) &addr, 0, sizeof(addr));
+	((struct sockaddr *)&addr)->sa_family = AF_UNIX;
+	snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/.s.PGSQL.%d",sock_dir,port);
+	len = sizeof(struct sockaddr_un);
+	status = bind(fd, (struct sockaddr *)&addr, len);
+	if (status == -1)
+	{
+		show_error("%s: bind() failed. reason: %s", func, strerror(errno));
+		return -1;
+	}
+
+	if (chmod(addr.sun_path, 0777) == -1)
+	{
+		show_error("%s: chmod() failed. reason: %s", func, strerror(errno));
+		return -1;
+	}
+
+	status = listen(fd, PGLB_MAX_SOCKET_QUEUE);
+	if (status < 0)
+	{
+		show_error("%s: listen() failed. reason: %s", func, strerror(errno));
+		return -1;
+	}
+	return fd;
+}
+
+int
+PGRcreate_recv_socket(char * hostName , unsigned short portNumber)
+{
+	char * func = "PGRcreate_recv_socket()";
+	int fd,err;
+	size_t	len = 0;
+	struct sockaddr_in addr;
+	int one = 1;
+
+	if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
+	{
+		show_error("%s: socket() failed. (%s)", func, strerror(errno));
+		return -1;
+	}
+	if ((setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one))) == -1)
+	{
+		PGRclose_sock(&fd);
+		show_error("%s: setsockopt() failed. (%s)",func, strerror(errno));
+		return -1;
+	}
+	addr.sin_family = AF_INET;
+	if (hostName[0] == '\0')
+		addr.sin_addr.s_addr = htonl(INADDR_ANY);
+	else
+	{
+		struct hostent *hp;
+
+		hp = gethostbyname(hostName);
+		if ((hp == NULL) || (hp->h_addrtype != AF_INET))
+		{
+			PGRclose_sock(&fd);
+			return -1;
+		}
+		memmove((char *) &(addr.sin_addr), (char *) hp->h_addr, hp->h_length);
+	}
+
+	addr.sin_port = htons(portNumber);
+	len = sizeof(struct sockaddr_in);
+	
+	err = bind(fd, (struct sockaddr *) & addr, len);
+	if (err < 0)
+	{
+		PGRclose_sock(&fd);
+		show_error("%s: bind() failed. (%s)",func, strerror(errno));
+		return -1;
+	}
+	err = listen(fd, PGLB_MAX_SOCKET_QUEUE);
+	if (err < 0)
+	{
+		PGRclose_sock(&fd);
+		show_error("%s: listen() failed. (%s)", func, strerror(errno));
+		return -1;
+	}
+	return	fd;
+}
+
+int
+PGRcreate_acception(int fd, char * hostName , unsigned short portNumber)
+{
+	char * func = "PGRcreate_acception()";
+	int sock;
+	struct sockaddr  addr;
+	size_t	len = 0;
+	int one = 1;
+	int count;
+
+	len = sizeof(struct sockaddr);
+	count = 0;
+	while ((sock = accept(fd,&addr,&len)) < 0)
+	{
+		show_error("%s:accept error",func);
+		PGRclose_sock(&fd);
+		if ( count > PGLB_CONNECT_RETRY_TIME)
+		{
+			return -1;
+		}
+		fd = PGRcreate_recv_socket(hostName , portNumber);
+		count ++;
+	}
+	
+	count = 0;
+	while (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) < 0)
+	{
+		show_error("%s: setsockopt TCP_NODELAY error (%s)",func, strerror(errno));
+		if ( count > PGLB_CONNECT_RETRY_TIME)
+		{
+			return -1;
+		}
+		count ++;
+	}
+	count = 0;
+	while (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one)) < 0)
+	{
+		show_error("%s:setsockopt SO_KEEPALIVE error (%s)",func,strerror(errno));
+		if ( count > PGLB_CONNECT_RETRY_TIME)
+		{
+			return -1;
+		}
+		count ++;
+	}
+
+	return	sock;
+}
+
+void
+PGRclose_sock(int * sock)
+{
+	close(*sock);
+	*sock = -1;
+}
+
+int
+PGRread_byte(int sock,char * buf,int len, int flag)
+{
+	char * func = "PGRread_byte()";
+	int r;
+	char * read_ptr;
+	int read_size = 0;
+	int max_buf_size ;
+	int pid;
+
+	pid = getpid();
+	max_buf_size = len;
+	read_ptr = (char*)buf;
+	for (;;)
+	{
+		r = recv(sock,read_ptr + read_size ,max_buf_size - read_size, flag);
+		if (r < 0)
+		{
+			if (errno == EINTR)
+			{
+				continue;
+			}
+#ifdef EAGAIN
+			if (errno == EAGAIN)
+			{
+				return read_size;
+			}
+#endif
+#if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN))
+			if (errno == EWOULDBLOCK)
+			{
+				show_error("%s:no data (%s)",func,strerror(errno));
+				return read_size;
+			}
+#endif
+#ifdef ECONNRESET
+			if (errno == ECONNRESET)
+			{
+				PGRclose_sock(&sock);
+				show_error("%s:connection reset (%s)",func, strerror(errno));
+				return -1;
+			}
+#endif
+			show_error("%s:recv() failed. (%s)",func,strerror(errno));
+			read_size = -1;
+			break;
+		}
+		if (r > 0)
+		{
+			read_size += r;
+			if (max_buf_size == read_size)
+			{
+				break;
+			}
+			break;
+		}
+		if (read_size)
+		{
+			return read_size;
+		}
+		else
+		{
+			return -1;
+		}
+	}
+
+	return read_size;
+}
+
+int
+PGRcreate_cluster_socket( int * sock, ClusterTbl * ptr )
+{
+	char * func = "PGRcreate_cluster_socket()";
+	int status = STATUS_ERROR;
+
+	/*
+	if (PGRis_connection_full(ptr) == 1)
+	{
+		return STATUS_ERROR;
+	}
+	*/
+	if (ptr != (ClusterTbl *) NULL)
+	{
+		status = create_send_socket(sock, ptr->hostName, ptr->port)	;
+	}
+	else
+	{
+		show_error("%s:ClusterTbl is not initialize",func);
+	}
+	return status;
+}
+
+static int
+create_send_socket(int * fdP, char * hostName , unsigned short portNumber)
+{
+	char * func = "create_send_socket()";
+	int sock;
+	size_t	len = 0;
+	struct sockaddr_in addr;
+	int fd;
+	int one = 1;
+
+#ifdef PRINT_DEBUG
+	show_debug("%s: host:%s port:%d",func, hostName,portNumber);
+#endif			
+
+	memset((char *)&addr,0,sizeof(addr));
+
+	if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
+	{
+		* fdP = -1;
+		
+		show_error("%s:socket() failed. (%s)",func, strerror(errno));
+		return STATUS_ERROR;
+	}
+	if ((setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one))) == -1)
+	{
+		PGRclose_sock(&fd);
+		* fdP = -1;
+		show_error("%s:setsockopt() failed. (%s)", func, strerror(errno));
+		return STATUS_ERROR;
+		return STATUS_ERROR;
+	}
+	if ((setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one))) == -1)
+	{
+		PGRclose_sock(&fd);
+		* fdP = -1;
+		show_error("%s:setsockopt() failed. (%s)", func, strerror(errno));
+		return STATUS_ERROR;
+	}
+	if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) < 0)
+	{
+		PGRclose_sock(&fd);
+		* fdP = -1;
+		show_error("%s:setsockopt() failed. (%s)",func, strerror(errno));
+		return STATUS_ERROR;
+	}
+	
+	addr.sin_family = AF_INET;
+	if (hostName[0] == '\0')
+   		addr.sin_addr.s_addr = htonl(INADDR_ANY);
+	else
+	{
+		struct hostent *hp;
+
+		hp = gethostbyname(hostName);
+		if ((hp == NULL) || (hp->h_addrtype != AF_INET))
+		{
+			PGRclose_sock(&fd);
+			* fdP = -1;
+			return STATUS_ERROR;
+		}
+		memmove((char *) &(addr.sin_addr), (char *) hp->h_addr, hp->h_length);
+	}
+
+	addr.sin_port = htons(portNumber);
+	len = sizeof(struct sockaddr_in);
+	
+	if ((sock = connect(fd,(struct sockaddr*)&addr,len)) < 0)
+	{
+		PGRclose_sock(&fd);
+		* fdP = -1;
+		return STATUS_ERROR;
+	}
+	
+	* fdP = fd;
+	return	STATUS_OK;
+}
+
+
+#endif /* USE_REPLICATION */
diff -ruN postgresql-7.4.13-old/src/pgcluster/pgrp/AUTHORS postgresql-7.4.13/src/pgcluster/pgrp/AUTHORS
--- postgresql-7.4.13-old/src/pgcluster/pgrp/AUTHORS	1970-01-01 01:00:00.000000000 +0100
+++ postgresql-7.4.13/src/pgcluster/pgrp/AUTHORS	2006-08-05 16:53:43.000000000 +0200
@@ -0,0 +1,3 @@
+Authors of pglb
+
+pglb was written by Atsushi Mitani
diff -ruN postgresql-7.4.13-old/src/pgcluster/pgrp/COPYING postgresql-7.4.13/src/pgcluster/pgrp/COPYING
--- postgresql-7.4.13-old/src/pgcluster/pgrp/COPYING	1970-01-01 01:00:00.000000000 +0100
+++ postgresql-7.4.13/src/pgcluster/pgrp/COPYING	2006-08-05 16:53:43.000000000 +0200
@@ -0,0 +1,12 @@
+Copyright (c) 2003	Atsushi Mitani
+
+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.
diff -ruN postgresql-7.4.13-old/src/pgcluster/pgrp/Makefile postgresql-7.4.13/src/pgcluster/pgrp/Makefile
--- postgresql-7.4.13-old/src/pgcluster/pgrp/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ postgresql-7.4.13/src/pgcluster/pgrp/Makefile	2006-08-05 16:53:43.000000000 +0200
@@ -0,0 +1,40 @@
+#-------------------------------------------------------------------------
+#
+# Makefile for src/pgcluster/pgrp
+#
+#-------------------------------------------------------------------------
+
+subdir = src/pgcluster/pgrp
+top_builddir = ../../..
+include $(top_builddir)/src/Makefile.global
+
+confdir := ${exec_prefix}/etc
+
+OBJS= cascade.o conf.o main.o recovery.o replicate.o rlog.o
+
+EXTRA_OBJS = $(top_builddir)/src/backend/libpq/pgcluster.o 
+
+override CPPFLAGS := -I$(libpq_srcdir) $(CPPFLAGS) -DBINDIR=\"$(bindir)\" -DPRINT_DEBUG
+
+all: pgreplicate
+
+pgreplicate: $(OBJS) $(libpq_builddir)/libpq.a 
+	$(CC) $(CFLAGS) $(OBJS) $(EXTRA_OBJS) $(libpq) $(LDFLAGS) $(LIBS) -o $@
+
+install: all installdirs
+	$(INSTALL_PROGRAM) pgreplicate$(X) $(DESTDIR)$(bindir)/pgreplicate$(X)
+	$(INSTALL_DATA) pgreplicate.conf.sample  $(DESTDIR)$(confdir)/pgreplicate.conf.sample
+
+installdirs:
+	$(mkinstalldirs) $(DESTDIR)$(bindir)
+	$(mkinstalldirs) $(DESTDIR)$(confdir)
+
+uninstall:
+	rm -f $(addprefix $(DESTDIR)$(bindir)/, pgreplicate$(X))
+	rm -f $(DESTDIR)$(confdir)/pgreplicate.conf.sample
+
+clean distclean maintainer-clean:
+	rm -f pgreplicate$(X) $(OBJS) 
+
+clean_obj:
+	rm -f $(OBJS)
diff -ruN postgresql-7.4.13-old/src/pgcluster/pgrp/README postgresql-7.4.13/src/pgcluster/pgrp/README
--- postgresql-7.4.13-old/src/pgcluster/pgrp/README	1970-01-01 01:00:00.000000000 +0100
+++ postgresql-7.4.13/src/pgcluster/pgrp/README	2006-08-05 16:53:43.000000000 +0200
@@ -0,0 +1,274 @@
+=============================================================
+1. Installation
+=============================================================
+
+1-1. Install Cluster DB Server, Replication Server & Load Balancer
+----------------------------------------------------------------
+$ cd $source_dir 
+$ ./configure
+$ gmake
+$ su
+# gmake install
+# chown -R postgres /usr/local/pgsql
+----------------------------------------------------------------
+
+=============================================================
+2. Initialize DB
+=============================================================
+$ su
+# adduser postgres
+# mkdir /usr/local/pgsql/data
+# chown postgres /usr/local/pgsql/data
+# su - postgres
+$ /usr/local/pgsql/bin/initdb -D /usr/local/pgsql/data
+
+
+=============================================================
+3. Configuration
+=============================================================
+(EX.System Composition)
+
+                        |
+             ((Load Balance Server))
+             ( hostname: lb.hoo.com)
+             ( receive port:5432   )
+             ( recovery port:6001  )
+                        |
+----------+-------------+------------+----------
+          |                          |
+ ((  Cluster DB 1    ))    ((  Cluster DB 2    ))
+ ( hostname:c1.hoo.com)    ( hostname:c2.hoo.com)
+ ( receive port: 5432 )    ( receive port:5432  )
+ ( recovery port:7001 )    ( recovery port 7002 )
+          |                          |
+----------+-------------+------------+----------
+                        |
+             ((Replication Server))
+             ( hostname:pgr.hoo.com)
+             ( receive port:8001   )
+             ( recovery port:8101  )
+
+
+3-1. Load Balance Server
+
+The setup file of load balance server is copied from the sample file and edited.
+(the sample file is installed '/usr/local/pgsql/etc' in default)
+----------------------------------------------------------------
+$cd /usr/local/pgsql/etc
+$cp pglb.conf.sample pglb.conf
+----------------------------------------------------------------
+
+In the case of the above system composition example,
+the setup example of pglb.conf file is as the following 
+
+#============================================================
+#          Load Balance Server configuration file
+#-------------------------------------------------------------
+# file: pglb.conf
+#-------------------------------------------------------------
+# This file controls:
+#       o which hosts are db cluster server
+#       o which port  use connect to db cluster server
+#       o how many connections are allowed on each DB server
+#============================================================
+#-------------------------------------------------------------
+# set cluster DB server information
+#		o Host_Name : hostname
+#		o Port : connection for postmaster
+#		o Max_Connection : maximun number of connection to postmaster
+#-------------------------------------------------------------
+<Cluster_Server_Info>
+    <Host_Name>   c1.hoo.com  </Host_Name>
+    <Port>        5432                </Port>
+    <Max_Connect> 32                   </Max_Connect>
+</Cluster_Server_Info>
+<Cluster_Server_Info>
+    <Host_Name>   c2.hoo.com  </Host_Name>
+    <Port>        5432                </Port>
+    <Max_Connect> 32                   </Max_Connect>
+</Cluster_Server_Info>
+#-------------------------------------------------------------
+# set Load Balance server information
+#		o Receive_Port : connection from client
+#		o Recovery_Port : connection for recovery process
+#		o Max_Cluster_Num : maximun number of cluster DB servers
+#		o Use_Connection_Pooling : use connection pool [yes/no] 
+#		o Max_Pool_Each_Server : number of pool connections/DB server
+#-------------------------------------------------------------
+<Receive_Port>    5432                </Receive_Port>
+<Recovery_Port>   6001                </Recovery_Port>
+<Max_Cluster_Num> 128                 </Max_Cluster_Num>
+<Use_Connection_Pooling> yes          </Use_Connection_Pooling>
+<Max_Pool_Each_Server> 1              </Max_Pool_Each_Server>
+
+3-2. Cluster DB Server
+
+The Cluster DB server need edit two configuration files
+('pg_hba.conf' and 'cluster.conf').
+These files are create under the $PG_DATA directory after 'initdb'.
+
+A. pg_hba.conf
+Permission to connect DB via IP connectoins is need for this system.
+
+B. cluster.conf
+In the case of the above system composition example,
+the setup example of cluster.conf file is as the following 
+
+#============================================================
+#          Cluster DB Server configuration file
+#-------------------------------------------------------------
+# file: cluster.conf
+#-------------------------------------------------------------
+# This file controls:
+#       o which hosts & port are replication server
+#       o which port use for replication request to replication server
+#       o which command use for recovery function
+#
+#============================================================
+#-------------------------------------------------------------
+# set cluster DB server information
+#		o Host_Name : hostname
+#		o Port : connection for postmaster
+#		o Recovery_Port : connection for recovery process
+#-------------------------------------------------------------
+<Replicate_Server_Info>
+	<Host_Name> pgr.hoo.com </Host_Name>
+	<Port> 8001 </Port>
+	<Recovery_Port> 8101 </Recovery_Port>
+</Replicate_Server_Info>
+#-------------------------------------------------------------
+# set Cluster DB Server information
+#		o Recovery_Port : connection for recovery
+#		o Rsync_Path : path of rsync command 
+#		o Rsync_Option : file transfer option for rsync
+#       o When_Stand_Alone : When all replication servers fell,
+#                            you can set up two kinds of permittion,
+#                            "real_only" or "read_write".
+#-------------------------------------------------------------
+<Recovery_Port>    7001           </Recovery_Port>
+<Rsync_Path>       /usr/bin/rsync </Rsync_Path>
+<Rsync_Option>     ssh -1         </Rsync_Option>
+<When_Stand_Alone> read_only      </When_Stand_Alone>
+#-------------------------------------------------------------
+# set partitional replicate control information
+#     set DB name and Table name to stop reprication
+#       o DB_Name : DB name
+#       o Table_Name : table name
+#-------------------------------------------------------------
+#<Not_Replicate_Info>
+#    <DB_Name>     test_db      </DB_Name>
+#    <Table_Name>  log_table    </Table_Name>
+#</Not_Replicate_Info>
+
+3-3. Replication Server
+
+The setup file of replication server is copied from the sample file and edited.
+(the sample file is installed '/usr/local/pgsql/etc' in default)
+----------------------------------------------------------------
+$cd /usr/local/pgsql/etc
+$cp pgreplicate.conf.sample pgreplicate.conf
+----------------------------------------------------------------
+In the case of the above system composition example,
+the setup example of pgreplicate.conf file is as the following 
+
+#============================================================
+#                 PGReplicate configuration file
+#-------------------------------------------------------------
+# file: pgreplicate.conf
+#-------------------------------------------------------------
+# This file controls:
+#       o which hosts & port are cluster server
+#       o which port use for replication request from cluster server
+#============================================================
+#-------------------------------------------------------------
+# set cluster DB server information
+#		o Host_Name : hostname
+#		o Port : connection for postmaster
+#		o Recovery_Port : connection for recovery
+#-------------------------------------------------------------
+<Cluster_Server_Info>
+    <Host_Name>      c1.hoo.com    </Host_Name>
+    <Port>           5432          </Port>
+    <Recovery_Port>  7001          </Recovery_Port>
+</Cluster_Server_Info>
+<Cluster_Server_Info>
+    <Host_Name>      c2.hoo.com    </Host_Name>
+    <Port>           5432          </Port>
+    <Recovery_Port>  7001          </Recovery_Port>
+</Cluster_Server_Info>
+#-------------------------------------------------------------
+# set Load Balance server information
+#		o Host_Name : hostname
+#		o Recovery_Port : connection for recovery
+#-------------------------------------------------------------
+<LoadBalance_Server_Info>
+    <Host_Name>       lb.hoo.com   </Host_Name>
+    <Recovery_Port>   6001         </Recovery_Port>
+</LoadBalance_Server_Info>
+#-------------------------------------------------------------
+# set PGReplicate server information
+#		o Replicate_Port : connection for reprication
+#		o Recovery_Port : connection for recovery
+#-------------------------------------------------------------
+<Replication_Port>    8001         </Replication_Port>
+<Recovery_Port>       8101         </Recovery_Port>
+
+
+=============================================================
+4. Start Up / Stop
+=============================================================
+
+4-1. replication server
+
+A. Start replication server
+----------------------------------------------------------------
+$ /usr/local/pgsql/bin/pgreplicate -D /usr/local/pgsql/etc
+----------------------------------------------------------------
+
+B. Stop replication server
+----------------------------------------------------------------
+$ /usr/local/pgsql/bin/pgreplicate -D /usr/local/pgsql/etc stop
+----------------------------------------------------------------
+
+usage: pgreplicate [-D path_of_config_file] [-W path_of_work_files] [-U login us
+er][-l][-n][-v][-h][stop]
+    -l: print error logs in the log file.
+    -n: don't run in daemon mode.
+    -v: debug mode. need '-n' flag
+    -h: print this help
+    stop: stop pgreplicate
+(config file default path: ./pgreplicate.conf)
+
+4-2. cluster DB server
+$PG_HOME = /usr/local/pgsql
+$PG_DATA = /usr/local/pgsql/data
+
+A. Start cluster DB server
+----------------------------------------------------------------
+$ /usr/local/pgsql/bin/pg_ctl -D /usr/local/pgsql/data -o "-i" start
+----------------------------------------------------------------
+
+B. Stop cluster DB server
+----------------------------------------------------------------
+$ /usr/local/pgsql/bin/pg_ctl -D /usr/local/pgsql/data stop
+----------------------------------------------------------------
+
+4-3. load balance server
+
+A. Start load balance server
+----------------------------------------------------------------
+$ /usr/local/pgsql/bin/pglb -D /usr/local/pgsql/etc
+----------------------------------------------------------------
+
+B. Stop load balance server
+----------------------------------------------------------------
+$ /usr/local/pgsql/bin/pglb -D /usr/local/pgsql/etc stop
+----------------------------------------------------------------
+
+usage: pglb [-D path_of_config_file] [-W path_of_work_files] [-n][-v][-h][stop]
+    -l: print error logs in the log file.
+    -n: don't run in daemon mode.
+    -v: debug mode. need '-n' flag
+    -h: print this help
+    stop: stop pglb
+    (config file default path: ./pglb.conf)
diff -ruN postgresql-7.4.13-old/src/pgcluster/pgrp/cascade.c postgresql-7.4.13/src/pgcluster/pgrp/cascade.c
--- postgresql-7.4.13-old/src/pgcluster/pgrp/cascade.c	1970-01-01 01:00:00.000000000 +0100
+++ postgresql-7.4.13/src/pgcluster/pgrp/cascade.c	2006-08-05 16:53:43.000000000 +0200
@@ -0,0 +1,884 @@
+/*--------------------------------------------------------------------
+ * FILE:
+ *     cascade.c
+ *
+ * NOTE:
+ *     This file is composed of the functions to call with the source
+ *     at pgreplicate for backup and cascade .
+ *
+ * Portions Copyright (c) 2003, Atsushi Mitani
+ *--------------------------------------------------------------------
+ */
+#ifdef USE_REPLICATION
+
+#include "postgres.h"
+#include "postgres_fe.h"
+
+#include <stdio.h>
+#include <unistd.h>
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#include <errno.h>
+#include <ctype.h>
+#include <time.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <sys/sem.h>
+#include <signal.h>
+#include <sys/socket.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <netdb.h>
+#ifdef HAVE_NETINET_TCP_H
+#include <netinet/tcp.h>
+#endif
+#include <dirent.h>
+#include <arpa/inet.h>
+
+#ifdef HAVE_CRYPT_H
+#include <crypt.h>
+#endif
+
+#ifdef MULTIBYTE
+#include "mb/pg_wchar.h"
+#endif
+
+#include "libpq-fe.h"
+#include "libpq-int.h"
+#include "fe-auth.h"
+#include "access/xact.h"
+#include "replicate_com.h"
+#include "pgreplicate.h"
+
+int PGRstartup_cascade(void);
+int PGRsend_lower_cascade(ReplicateHeader * header, char * query);
+int PGRsend_upper_cascade(ReplicateHeader * header, char * query);
+int PGRwait_answer_cascade(int  sock);
+ReplicateServerInfo * PGRget_lower_cascade(void);
+ReplicateServerInfo * PGRget_upper_cascade(void);
+void PGRset_cascade_server_status(ReplicateServerInfo * cascade, int status);
+ReplicateServerInfo * PGRrecv_cascade_answer(ReplicateServerInfo * cascade,ReplicateHeader * header);
+int PGRsend_cascade(int sock , ReplicateHeader * header, char * query);
+int PGRcascade_main(int sock, ReplicateHeader * header, char * query);
+int PGRwait_notice_rlog_done(void);
+int PGRsend_notice_rlog_done(int sock);
+
+#if 0
+static int count_cascade(int flag);
+#endif
+static ReplicateServerInfo * get_cascade_data(int * cnt, int flag);
+static int add_cascade_data(ReplicateHeader * header, ReplicateServerInfo * add_data);
+static int update_cascade_data(ReplicateHeader * header, ReplicateServerInfo * update_data);
+static void write_cascade_status_file(ReplicateServerInfo * cascade);
+static int notice_cascade_data(int sock);
+static int notice_cascade_data_to_cluster_db(void);
+
+/*--------------------------------------
+ * PROTOTYPE DECLARATION
+ *--------------------------------------
+ */
+
+#if 0
+static int
+count_cascade(int flag)
+{
+	int cnt = 0;
+	int cascade_cnt = 0;
+	ReplicateServerInfo * cascade = NULL;
+
+	if ((Cascade_Tbl == NULL) || (Cascade_Inf == NULL))
+	{
+		return 0;
+	}
+
+	/* count cascadeing replication server */
+	switch (flag)
+	{
+		case UPPER_CASCADE:
+		case ALL_CASCADE:
+			cascade = Cascade_Tbl;
+			break;
+		case LOWER_CASCADE:
+			cascade = Cascade_Inf->myself;
+			break;
+	}
+
+	if (cascade == NULL)
+	{
+		return 0;
+	}
+	while (cascade->useFlag != DATA_END)
+	{
+		if (cascade->useFlag == DATA_USE)
+		{
+			cascade_cnt ++;
+		}
+		if ((flag == UPPER_CASCADE) &&
+			(cascade == Cascade_Inf->myself))
+		{
+			break;
+		}
+		cnt ++;
+		if (cnt >= MAX_DB_SERVER -1 )
+		{
+			break;
+		}
+		cascade ++;
+	}
+	return cascade_cnt;
+}
+#endif /* if 0 */
+
+static ReplicateServerInfo * 
+get_cascade_data(int * cnt, int flag)
+{
+	char * func = "get_cascade_data()";
+	int i = 0;
+	int loop_cnt = 0;
+	int size = 0;
+	ReplicateServerInfo * buf = NULL;
+	ReplicateServerInfo * cascade = NULL;
+
+	size = sizeof(ReplicateServerInfo) * MAX_DB_SERVER;
+	buf = (ReplicateServerInfo *)malloc(size);
+	if (buf == (ReplicateServerInfo *)NULL)
+	{
+		show_error("%s:malloc failed: (%s)",func,strerror(errno));
+		*cnt = 0;
+		return NULL;
+	}
+	memset(buf,0,size);
+
+	switch (flag)
+	{
+		case UPPER_CASCADE:
+		case ALL_CASCADE:
+			cascade = Cascade_Tbl;
+			break;
+		case LOWER_CASCADE:
+			cascade = Cascade_Inf->myself;
+			break;
+	}
+
+	if (cascade == NULL)
+	{
+		free(buf);
+		*cnt = 0;
+		return NULL;
+	}
+	i = 0;
+	loop_cnt = 0;
+	while (cascade->useFlag != DATA_END)
+	{
+		if (cascade->useFlag == DATA_USE) 
+		{
+			(buf + i)->useFlag = htonl(cascade->useFlag);
+			strncpy((buf + i)->hostName,cascade->hostName,sizeof(cascade->hostName));
+			(buf + i)->portNumber = htons(cascade->portNumber);
+			(buf + i)->recoveryPortNumber = htons(cascade->recoveryPortNumber);
+			(buf + i)->lifecheckPortNumber = htons(cascade->lifecheckPortNumber);
+			i++;
+		}
+		if ((flag == UPPER_CASCADE) &&
+			(cascade == Cascade_Inf->myself))
+		{
+			break;
+		}
+		loop_cnt ++;
+		if (loop_cnt >= MAX_DB_SERVER -1 )
+		{
+			break;
+		}
+		if (Cascade_Inf->end == cascade)
+		{
+			break;
+		}
+		cascade ++;
+	}
+	*cnt = i;
+	return buf;
+}
+
+static int
+update_cascade_data(ReplicateHeader * header, ReplicateServerInfo * update_data)
+{
+	char * func = "update_cascade_data()";
+	int size = 0;
+	int cnt = 0;
+	ReplicateServerInfo * ptr = NULL;
+	ReplicateServerInfo * cascade = NULL;
+	char hostName[HOSTNAME_MAX_LENGTH];
+
+	if ((header == NULL ) || ( update_data == NULL))
+	{
+		show_error("%s:receive data is wrong",func);
+		return STATUS_ERROR;
+	}
+	if ((Cascade_Tbl == NULL) || (Cascade_Inf == NULL))
+	{
+		show_error("%s:config data read error",func);
+		return STATUS_ERROR;
+	}
+	size = ntohl(header->query_size);
+	cnt = size / sizeof(ReplicateServerInfo);
+	if (cnt >= MAX_DB_SERVER)
+	{
+		show_error("%s:update cascade data is too large. it's more than %d", func,MAX_DB_SERVER);
+		return STATUS_ERROR;
+	}
+
+	Cascade_Inf->useFlag = DATA_INIT;
+	if ((Cascade_Inf->upper != NULL) && (Cascade_Inf->upper->sock > 0))
+	{
+		close(Cascade_Inf->upper->sock);
+	}
+	if ((Cascade_Inf->lower != NULL) && (Cascade_Inf->lower->sock > 0))
+	{
+		close(Cascade_Inf->lower->sock);
+	}
+	Cascade_Inf->myself = NULL;
+	Cascade_Inf->upper = NULL;
+	Cascade_Inf->lower = NULL;
+
+	gethostname(hostName,sizeof(hostName));
+	ptr = update_data;
+	cascade = Cascade_Tbl;
+	memset(cascade,0,(sizeof(ReplicateServerInfo)*MAX_DB_SERVER));
+	Cascade_Inf->top = cascade;
+	while (cnt > 0)
+	{
+		cascade->useFlag = ntohl(ptr->useFlag);
+		strncpy(cascade->hostName,ptr->hostName,sizeof(cascade->hostName));
+		cascade->portNumber = ntohs(ptr->portNumber);
+		cascade->recoveryPortNumber = ntohs(ptr->recoveryPortNumber);
+		cascade->lifecheckPortNumber = ntohs(ptr->lifecheckPortNumber);
+
+		if ((!strncmp(cascade->hostName,hostName,sizeof(cascade->hostName)))  &&
+			(cascade->portNumber == Port_Number) &&
+			(cascade->recoveryPortNumber == Recovery_Port_Number))
+		{
+			Cascade_Inf->myself = cascade;
+		}
+		Cascade_Inf->end = cascade;
+		cascade ++;
+		ptr ++;
+		cnt --;
+		cascade->useFlag = DATA_END;
+	}
+	Cascade_Inf->useFlag = DATA_USE;
+
+	return STATUS_OK;
+}
+
+static int
+add_cascade_data(ReplicateHeader * header, ReplicateServerInfo * add_data)
+{
+	char *func = "add_cascade_data()";
+	int size = 0;
+	int cnt = 0;
+	ReplicateServerInfo * ptr = NULL;
+	ReplicateServerInfo * cascade = NULL;
+	char hostName[HOSTNAME_MAX_LENGTH];
+
+	if ((header == NULL ) || ( add_data == NULL))
+	{
+		show_error("%s:receive data is wrong",func);
+		return STATUS_ERROR;
+	}
+	if ((Cascade_Tbl == NULL) || (Cascade_Inf == NULL))
+	{
+		show_error("%s:config data read error",func);
+		return STATUS_ERROR;
+	}
+	size = ntohl(header->query_size);
+	cnt = size / sizeof(ReplicateServerInfo);
+	if (cnt >= MAX_DB_SERVER)
+	{
+		show_error("%s:addtional cascade data is too large. it's more than %d", func,MAX_DB_SERVER);
+		return STATUS_ERROR;
+	}
+
+	Cascade_Inf->useFlag = DATA_INIT;
+	if ((Cascade_Inf->lower != NULL) && (Cascade_Inf->lower->sock > 0))
+	{
+		close(Cascade_Inf->lower->sock);
+	}
+	Cascade_Inf->lower = NULL;
+
+	gethostname(hostName,sizeof(hostName));
+	ptr = add_data;
+	cascade = Cascade_Inf->myself;
+	cascade ++;
+	while (cnt > 0)
+	{
+		cascade->useFlag = ntohl(ptr->useFlag);
+		strncpy(cascade->hostName,ptr->hostName,sizeof(cascade->hostName));
+		cascade->portNumber = ntohs(ptr->portNumber);
+		cascade->recoveryPortNumber = ntohs(ptr->recoveryPortNumber);
+		cascade->lifecheckPortNumber = ntohs(ptr->lifecheckPortNumber);
+
+		if ((!strncmp(cascade->hostName,hostName,sizeof(cascade->hostName)))  &&
+			(cascade->portNumber == Port_Number) &&
+			(cascade->recoveryPortNumber == Recovery_Port_Number))
+		{
+			ptr ++;
+			cnt --;
+			continue;
+		}
+		cascade ++;
+		cascade->useFlag = DATA_END;
+		ptr ++;
+		cnt --;
+	}
+	Cascade_Inf->useFlag = DATA_USE;
+
+	return STATUS_OK;
+}
+
+int
+PGRstartup_cascade(void)
+{
+	char * func = "PGRstartup_cascade()";
+	int cnt = 0;
+	int status = STATUS_OK;
+	ReplicateHeader header;
+	ReplicateServerInfo * cascade = NULL;
+	ReplicateServerInfo * buf = NULL;
+
+	if ((Cascade_Tbl == NULL) || (Cascade_Inf == NULL))
+	{
+		show_error("%s:config data read error",func);
+		return STATUS_ERROR;
+	}
+
+	/* count lower server */
+	cascade = Cascade_Inf->myself;
+	if (cascade == NULL)
+	{
+		show_error("%s:cascade data initialize error",func);
+		return STATUS_ERROR;
+	}
+	buf = get_cascade_data(&cnt,LOWER_CASCADE);
+	if (cnt <= 0)
+	{
+		show_error("%s:cascade data get error",func);
+		return STATUS_ERROR;
+	}
+	
+	memset(&header,0,sizeof(ReplicateHeader));
+	header.cmdSys = CMD_SYS_CASCADE;
+	header.cmdSts = CMD_STS_TO_UPPER;
+	header.cmdType = CMD_TYPE_ADD;
+	header.query_size = htonl(sizeof(ReplicateServerInfo) * cnt);
+
+	status = PGRsend_upper_cascade(&header, (char *)buf);
+	if (buf != NULL)
+	{
+		free(buf);
+	}
+	if (status == STATUS_OK)
+	{
+		memset(&header,0,sizeof(ReplicateHeader));
+		buf = PGRrecv_cascade_answer( Cascade_Inf->upper, &header);
+		if ((buf != NULL) &&
+			(header.cmdSys == CMD_SYS_CASCADE) &&
+			(header.cmdSts == CMD_STS_TO_LOWER) &&
+			(header.cmdType == CMD_TYPE_UPDATE_ALL))
+		{
+			status = update_cascade_data(&header,buf);
+			free(buf);
+		}
+	}
+	
+	return status;
+}
+
+int
+PGRsend_lower_cascade(ReplicateHeader * header, char * query)
+{
+	char * func = "PGRsend_lower_cascade()";
+	int status = STATUS_OK;
+
+	for(;;)
+	{
+		if (Cascade_Inf->lower != NULL)
+		{
+			if (Cascade_Inf->lower->sock <= 0)
+			{
+#ifdef PRINT_DEBUG
+				show_debug("%s:sock is not ready, Cascade_Inf->lower set NULL",func);
+#endif			
+				status = PGR_Create_Socket_Connect(&(Cascade_Inf->lower->sock),Cascade_Inf->lower->hostName,Cascade_Inf->lower->portNumber);
+		
+				if (status != STATUS_OK)
+				{
+					PGRset_cascade_server_status(Cascade_Inf->lower,DATA_ERR);
+					Cascade_Inf->lower = NULL;
+				}
+			}
+		}
+		while (Cascade_Inf->lower == NULL)
+		{
+			Cascade_Inf->lower = PGRget_lower_cascade();	
+			if (Cascade_Inf->lower == NULL)
+			{
+#ifdef PRINT_DEBUG
+				show_debug("%s:there is no lower cascaded server",func);
+#endif			
+				return STATUS_ERROR;
+			}
+			status = PGR_Create_Socket_Connect(&(Cascade_Inf->lower->sock),Cascade_Inf->lower->hostName,Cascade_Inf->lower->portNumber);
+	
+			if (status != STATUS_OK)
+			{
+#ifdef PRINT_DEBUG
+				show_debug("%s:PGRset_cascade_server_status call status ERROR",func);
+#endif			
+				PGRset_cascade_server_status(Cascade_Inf->lower,DATA_ERR);
+				Cascade_Inf->lower = NULL;
+			}
+			else
+			{
+				break;
+			}
+		}
+		if (PGRsend_cascade(Cascade_Inf->lower->sock,header,query) != STATUS_OK)
+		{
+			show_error("%s:PGRsend_cascade failed",func);
+			if (Cascade_Inf->lower->sock > 0)
+			{
+				close(Cascade_Inf->lower->sock);
+				Cascade_Inf->lower->sock = -1;
+			}
+			PGRset_cascade_server_status(Cascade_Inf->lower,DATA_ERR);
+			Cascade_Inf->lower = NULL;
+		}
+		if (Cascade_Inf->lower != NULL)
+		{
+			break;
+		}
+	}
+	return STATUS_OK;
+}
+
+int
+PGRsend_upper_cascade(ReplicateHeader * header, char * query)
+{
+	char * func = "PGRsend_upper_cascade()";
+	int status = STATUS_OK;
+	int sock;
+
+	for(;;)
+	{
+		if (Cascade_Inf->upper != NULL)
+		{
+			if (Cascade_Inf->upper->sock <= 0)
+			{
+				Cascade_Inf->upper = NULL;
+			}
+		}
+		while (Cascade_Inf->upper == NULL)
+		{
+			Cascade_Inf->upper = PGRget_upper_cascade();	
+			if (Cascade_Inf->upper == NULL)
+			{
+				show_debug("Cascade_Inf->upper is NULL");
+				return STATUS_ERROR;
+			}
+#ifdef PRINT_DEBUG
+			show_debug("%s:sock[%d] host[%s] port[%d]", func,sock,Cascade_Inf->upper->hostName,Cascade_Inf->upper->portNumber);
+#endif			
+			status = PGR_Create_Socket_Connect(&sock,Cascade_Inf->upper->hostName,Cascade_Inf->upper->portNumber);
+	
+			if (status != STATUS_OK)
+			{
+#ifdef PRINT_DEBUG
+				show_debug("%s:PGR_Create_Socket_Connect failed",func);
+#endif			
+				PGRset_cascade_server_status(Cascade_Inf->upper,DATA_ERR);
+				Cascade_Inf->upper = NULL;
+			}
+			else
+			{
+#ifdef PRINT_DEBUG
+				show_debug("%s:PGR_Create_Socket_Connect OK[%d]",func,sock);
+#endif			
+				Cascade_Inf->upper->sock = sock;
+				break;
+			}
+		}
+		if (PGRsend_cascade(Cascade_Inf->upper->sock,header,query) != STATUS_OK)
+		{
+#ifdef PRINT_DEBUG
+			show_debug("%s:PGRsend_cascade failed",func);
+#endif			
+			PGRset_cascade_server_status(Cascade_Inf->upper,DATA_ERR);
+			Cascade_Inf->upper = NULL;
+		}
+		if (Cascade_Inf->upper != NULL)
+		{
+			break;
+		}
+	}
+	return STATUS_OK;
+}
+
+ReplicateServerInfo *
+PGRget_lower_cascade(void)
+{
+	char * func = "PGRget_lower_cascade()";
+	ReplicateServerInfo * cascade = NULL;
+
+	if ((Cascade_Tbl == NULL) || (Cascade_Inf == NULL))
+	{
+		show_error("%s:config data read error",func);
+		return NULL;
+	}
+
+	/* count lower server */
+	cascade = Cascade_Inf->myself;
+	if (cascade == NULL)
+	{
+		show_error("%s:cascade data initialize error",func);
+		return NULL;
+	}
+	if (cascade->useFlag != DATA_END)
+	{
+		cascade ++;
+	}
+	while (cascade->useFlag != DATA_END)
+	{
+#ifdef PRINT_DEBUG
+		show_debug("%s:lower cascade search[%d]@[%s] use[%d]",
+			func,
+			cascade->portNumber,
+			cascade->hostName,
+			cascade->useFlag);
+#endif			
+		if (cascade->useFlag == DATA_USE)
+		{
+#ifdef PRINT_DEBUG
+			show_debug("%s:find lower cascade",func);
+#endif			
+			return cascade;
+		}
+		cascade ++;
+	}
+	return NULL;
+}
+
+ReplicateServerInfo *
+PGRget_upper_cascade(void)
+{
+	char * func = "PGRget_upper_cascade()";
+	ReplicateServerInfo * cascade = NULL;
+
+	if ((Cascade_Tbl == NULL) || (Cascade_Inf == NULL))
+	{
+		show_error("%s:config data read error",func);
+		return NULL;
+	}
+
+	/* count lower server */
+	cascade = Cascade_Inf->myself;
+	if ((cascade == NULL) || (Cascade_Inf->top == cascade))
+	{
+		return NULL;
+	}
+	cascade --;
+	while (cascade != NULL)
+	{
+		if (cascade->useFlag == DATA_USE)
+		{
+			return cascade;
+		}
+		if (Cascade_Inf->top == cascade)
+		{
+			break;
+		}
+		cascade --;
+	}
+	return NULL;
+}
+
+static void
+write_cascade_status_file(ReplicateServerInfo * cascade)
+{
+	switch( cascade->useFlag)
+	{
+		case DATA_FREE:
+			PGRwrite_log_file(Com_Info.Log_Info.StatusFp,"cascade(%s) port(%d) free",
+					cascade->hostName,
+					cascade->portNumber);
+			break;
+		case DATA_INIT:
+			PGRwrite_log_file(Com_Info.Log_Info.StatusFp,"cascade(%s) port(%d) initialize",
+					cascade->hostName,
+					cascade->portNumber);
+			break;
+		case DATA_USE:
+			PGRwrite_log_file(Com_Info.Log_Info.StatusFp,"cascade(%s) port(%d) start use",
+					cascade->hostName,
+					cascade->portNumber);
+			break;
+		case DATA_ERR:
+			PGRwrite_log_file(Com_Info.Log_Info.StatusFp,"cascade(%s) port(%d) error",
+					cascade->hostName,
+					cascade->portNumber);
+			break;
+		case DATA_TOP:
+			PGRwrite_log_file(Com_Info.Log_Info.StatusFp,"cascade(%s) port(%d) become top",
+					cascade->hostName,
+					cascade->portNumber);
+			break;
+	}
+}
+
+void
+PGRset_cascade_server_status(ReplicateServerInfo * cascade, int status)
+{
+	if (cascade == NULL)
+	{
+		return;
+	}
+	if (cascade->useFlag != status)
+	{
+		cascade->useFlag = status;
+		write_cascade_status_file(cascade);
+	}
+}
+
+ReplicateServerInfo *
+PGRrecv_cascade_answer(ReplicateServerInfo * cascade,ReplicateHeader * header)
+{
+	ReplicateServerInfo * answer = NULL;
+
+	if ((cascade == NULL) || (header == NULL))
+	{
+		return NULL;
+	}
+	answer = (ReplicateServerInfo*)PGRread_packet(cascade->sock,header);
+	return answer;
+}
+
+int
+PGRsend_cascade(int sock , ReplicateHeader * header, char * query)
+{
+	char * func ="PGRsend_cascade()";
+	int s;
+	char * send_ptr;
+	char * buf;
+	int send_size = 0;
+	int buf_size;
+	int header_size;
+	int rtn;
+	fd_set      wmask;
+	struct timeval timeout;
+	int query_size = 0;
+
+	/* check parameter */
+	if ((header == NULL) || (sock <= 0))
+	{
+		show_error("%s:header or sock is null",func);
+		return STATUS_ERROR;
+	}
+
+#ifdef PRINT_DEBUG
+	show_debug("%s:PGRsend_cascade sock[%d]",func,sock);
+#endif			
+	query_size = ntohl(header->query_size);
+	header_size = sizeof(ReplicateHeader);
+	buf_size = header_size + query_size + 4;
+	buf = malloc(buf_size);
+	memset(buf,0,buf_size);
+	buf_size -= 4;
+	memcpy(buf,header,header_size);
+	if (query_size > 0)
+	{
+		memcpy((char *)(buf+header_size),query,query_size+1);
+	}
+	send_ptr = buf;
+
+	timeout.tv_sec = 10;
+	timeout.tv_usec = 0;
+
+	/*
+	 * Wait for something to happen.
+	 */
+	FD_ZERO(&wmask);
+	FD_SET(sock,&wmask);
+	rtn = select(sock+1, (fd_set *)NULL, &wmask, (fd_set *)NULL, &timeout);
+	if (rtn && FD_ISSET(sock, &wmask))
+	{
+		for (;;)
+		{
+			s = send(sock,send_ptr + send_size,buf_size - send_size ,0);
+			if (s < 0){
+				if (errno == EINTR)
+				{
+					continue;
+				}
+				show_error("%s:send failed",func);
+				free(buf);
+				return STATUS_ERROR;
+			}
+			if (s == 0)
+			{
+				free(buf);
+				return STATUS_ERROR;
+			}
+			send_size += s;
+			if (send_size == buf_size)
+			{
+#ifdef PRINT_DEBUG
+				show_debug("%s:send[%s] size[%d]",func,query,send_size);
+#endif			
+				free(buf);
+				return STATUS_OK;
+			}
+		}
+	}
+	return STATUS_OK;
+}
+
+int
+PGRwait_answer_cascade(int  sock)
+{
+	ReplicateHeader header;
+	char * answer = NULL;
+
+	answer = PGRread_packet(sock,&header);
+	if (answer != NULL)
+	{
+		free(answer);
+		return STATUS_OK;
+	}
+	return STATUS_ERROR;
+}
+
+static int
+notice_cascade_data(int sock)
+{
+	char * func = "notice_cascade_data";
+	ReplicateServerInfo *cascade_data = NULL;
+	ReplicateHeader header;
+	int cnt = 0;
+	int size = 0;
+
+	if (sock <= 0)
+	{
+		return STATUS_ERROR;
+	}
+
+	cascade_data = get_cascade_data(&cnt, ALL_CASCADE );
+	if (cnt <= 0)
+	{
+		show_error("%s:cascade data is wrong",func);
+		return STATUS_ERROR;
+	}
+	size = sizeof (ReplicateServerInfo) * cnt ;
+
+	memset(&header,0,sizeof(ReplicateHeader));
+	header.cmdSys = CMD_SYS_CASCADE ;
+	header.cmdSts = CMD_STS_TO_LOWER ;
+	header.cmdType = CMD_TYPE_UPDATE_ALL;
+	header.query_size = htonl(size);
+	PGRsend_cascade(sock, &header, (char *)cascade_data );
+	if (cascade_data != NULL)
+	{
+		free(cascade_data);
+	}
+	return STATUS_OK;
+}
+
+int
+PGRcascade_main(int sock, ReplicateHeader * header, char * query)
+{
+	switch (header->cmdSts)
+	{
+		case CMD_STS_TO_UPPER:
+			if (header->cmdType == CMD_TYPE_ADD)
+			{
+				/* add lower cascade data to myself */
+				add_cascade_data(header,(ReplicateServerInfo*)query);
+				/* send cascade data to upper */
+				/* and receive new cascade data from upper */
+				PGRstartup_cascade();
+				/* return to lower with new cascade data */
+				notice_cascade_data(sock);
+				/* notifies a cascade server's information to Cluster DBs */
+				notice_cascade_data_to_cluster_db();
+			}
+			break;
+		case CMD_STS_TO_LOWER:
+			/*
+			 * use for cascading replication 
+			 */
+			break;
+	}
+	return STATUS_OK;
+}
+
+static int
+notice_cascade_data_to_cluster_db(void)
+{
+	char userName[USERNAME_MAX_LENGTH];
+
+	if (Cascade_Inf->lower == NULL)
+	{
+		Cascade_Inf->lower = PGRget_lower_cascade();	
+	}
+	if (Cascade_Inf->lower == NULL)
+	{
+		return STATUS_ERROR;
+	}
+	memset(userName,0,sizeof(userName));
+	strncpy(userName ,getenv("LOGNAME"),sizeof(userName)-1);
+
+	PGRnotice_replication_server(Cascade_Inf->lower->hostName, Cascade_Inf->lower->portNumber, Cascade_Inf->lower->recoveryPortNumber,Cascade_Inf->lower->lifecheckPortNumber,userName);
+
+	return STATUS_OK;
+}
+
+int
+PGRwait_notice_rlog_done(void)
+{
+
+	if (Cascade_Inf->lower != NULL)
+	{
+		if (Cascade_Inf->lower->sock > 0)
+		{
+			PGRreturn_result(Cascade_Inf->lower->sock,PGR_WAIT_ANSWER);
+			return STATUS_OK;
+		}
+	}
+	return STATUS_ERROR;
+}
+
+int
+PGRsend_notice_rlog_done(int sock)
+{
+	ReplicateHeader header;
+	int size = 0;
+
+	if (sock <= 0)
+	{
+		return STATUS_ERROR;
+	}
+
+	size = strlen(PGR_QUERY_DONE_NOTICE_CMD);
+	memset(&header,0,sizeof(ReplicateHeader));
+	header.cmdSys = CMD_SYS_CASCADE ;
+	header.cmdSts = CMD_STS_RESPONSE ;
+	header.cmdType = 0;
+	header.query_size = htonl(size);
+	PGRsend_cascade(sock, &header, PGR_QUERY_DONE_NOTICE_CMD);
+	return STATUS_OK;
+
+}
+#endif /* USE_REPLICATION */
diff -ruN postgresql-7.4.13-old/src/pgcluster/pgrp/conf.c postgresql-7.4.13/src/pgcluster/pgrp/conf.c
--- postgresql-7.4.13-old/src/pgcluster/pgrp/conf.c	1970-01-01 01:00:00.000000000 +0100
+++ postgresql-7.4.13/src/pgcluster/pgrp/conf.c	2006-08-05 16:53:43.000000000 +0200
@@ -0,0 +1,635 @@
+/*--------------------------------------------------------------------
+ * FILE:
+ *    conf.c
+ *    Replication server for PostgreSQL
+ *
+ * NOTE:
+ *    Read and set configuration data in this modul.
+ *
+ * Portions Copyright (c) 2003, Atsushi Mitani
+ *--------------------------------------------------------------------
+ */
+#ifdef USE_REPLICATION
+
+#include "postgres.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <sys/stat.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <sys/sem.h>
+#include <netdb.h>
+#include <errno.h>
+#include <sys/file.h>
+
+#include "libpq-fe.h"
+#include "replicate_com.h"
+#include "pgreplicate.h"
+
+int PGRset_Conf_Data(char * path);
+
+/*--------------------------------------------------------------------
+ * SYMBOL
+ *    PGRset_Conf_Data()
+ * NOTES
+ *    Initialize mamory and tables
+ * ARGS
+ *    char * path: path of the setup file (I)
+ * RETURN
+ *    OK: STATUS_OK
+ *    NG: STATUS_ERROR
+ *--------------------------------------------------------------------
+ */
+int
+PGRset_Conf_Data(char * path)
+{
+	char * func = "init_server_tbl()";
+	HostTbl host_tbl[MAX_DB_SERVER];
+	ConfDataType * conf = NULL;
+	int cnt = 0;
+	int lb_cnt = 0;
+	int cascade_cnt = 0;
+	int rec_no = 0;
+	int lb_rec_no = 0;
+	int cascade_rec_no = -1;
+	int i = 0;
+	int size = 0;
+	char fname[256];
+	union semun sem_arg;
+
+	/*
+	 * open log file
+	 */
+	if (path == NULL)
+	{
+		path = ".";
+	}
+
+	if (Com_Info.Log_Info.Log_Print)
+	{
+		snprintf(fname,sizeof(fname),"%s/%s",path,PGREPLICATE_LOG_FILE);
+		Com_Info.Log_Info.LogFp = fopen(fname,"a");
+		if (Com_Info.Log_Info.LogFp == NULL)
+		{
+			show_error("%s:fopen failed: (%s)",func,strerror(errno));
+			return STATUS_ERROR;
+		}
+	}
+
+	snprintf(fname,sizeof(fname),"%s/%s",path,PGREPLICATE_STATUS_FILE);
+	Com_Info.Log_Info.StatusFp = fopen(fname,"a");
+	if (Com_Info.Log_Info.StatusFp == NULL)
+	{
+		show_error("%s:fopen failed: (%s)",func,strerror(errno));
+		return STATUS_ERROR;
+	}
+
+	/*
+	 * Recovery Queue structure initialize
+	 */
+	RecoveryQueue.queue_fp = (FILE *)NULL;
+	RecoveryQueue.current_queue_no = 0;
+
+	/*
+	 * read configuration file
+	 */
+	if (PGR_Get_Conf_Data(path,PGREPLICATE_CONF_FILE) != STATUS_OK)
+	{
+		show_error("%s:PGR_Get_Conf_Data failed",func);
+		return STATUS_ERROR;
+	}
+
+	/* allocate response information table */
+	PGR_Response_Inf = (ResponseInf *)malloc(sizeof(ResponseInf));
+	if (PGR_Response_Inf == NULL)
+	{
+		show_error("%s:malloc() failed. reason: %s", func,strerror(errno));
+		return STATUS_ERROR;
+	}
+	PGR_Response_Inf->response_mode = PGR_NORMAL_MODE;
+	PGR_Response_Inf->current_cluster = 0;
+
+	/*
+	 * memory allocate load balance table buffer
+	 */
+	size = sizeof(RecoveryTbl) * MAX_DB_SERVER;
+	LoadBalanceTblShmid = shmget(IPC_PRIVATE,size,IPC_CREAT | IPC_EXCL | 0600);
+	if (LoadBalanceTblShmid < 0)
+	{
+		show_error("shmget() failed. reason: %s", strerror(errno));
+		return STATUS_ERROR;
+	}
+	LoadBalanceTbl = (RecoveryTbl *)shmat(LoadBalanceTblShmid,0,0);
+	if (LoadBalanceTbl == (RecoveryTbl *)-1)
+	{
+		show_error("%s:shmat() failed. reason: %s", func,strerror(errno));
+		return STATUS_ERROR;
+	}
+	if (LoadBalanceTbl == (RecoveryTbl *)NULL)
+	{
+		show_error("%s:malloc failed: (%s)",func,strerror(errno));
+		return STATUS_ERROR;
+	}
+	memset(LoadBalanceTbl , 0 , size );
+
+	/*
+	 * memory allocate cascade server table buffer
+	 */
+	size = sizeof(ReplicateServerInfo) * MAX_DB_SERVER;
+	CascadeTblShmid = shmget(IPC_PRIVATE,size,IPC_CREAT | IPC_EXCL | 0600);
+	if (CascadeTblShmid < 0)
+	{
+		show_error("%s:shmget() failed. reason: %s", func,strerror(errno));
+		return STATUS_ERROR;
+	}
+	Cascade_Tbl = (ReplicateServerInfo *)shmat(CascadeTblShmid,0,0);
+	if (Cascade_Tbl == (ReplicateServerInfo *)-1)
+	{
+		show_error("%s:shmat() failed. reason: %s",func, strerror(errno));
+		return STATUS_ERROR;
+	}
+	memset(Cascade_Tbl , 0 , size );
+
+	/*
+	 * memory allocate cascade index 
+	 */
+	size = sizeof(CascadeInf);
+	CascadeInfShmid = shmget(IPC_PRIVATE,size,IPC_CREAT | IPC_EXCL | 0600);
+	if (CascadeInfShmid < 0)
+	{
+		show_error("%s:shmget() failed. reason: %s", func,strerror(errno));
+		return STATUS_ERROR;
+	}
+	Cascade_Inf = (CascadeInf *)shmat(CascadeInfShmid,0,0);
+	if (Cascade_Inf == (CascadeInf *)-1)
+	{
+		show_error("%s:shmat() failed. reason: %s", func,strerror(errno));
+		return STATUS_ERROR;
+	}
+	memset(Cascade_Inf , 0 , size );
+
+	/*
+	 * memory allocate replication commit log buffer
+	 */
+	size = sizeof(CommitLogInf) * MAX_DB_SERVER * MAX_CONNECTIONS;
+	CommitLogShmid = shmget(IPC_PRIVATE,size,IPC_CREAT | IPC_EXCL | 0600);
+	if (CommitLogShmid < 0)
+	{
+		show_error("%s:shmget() failed. reason: %s", func,strerror(errno));
+		return STATUS_ERROR;
+	}
+	Commit_Log_Tbl = (CommitLogInf *)shmat(CommitLogShmid,0,0);
+	if (Commit_Log_Tbl == (CommitLogInf *)-1)
+	{
+		show_error("%s:shmat() failed. reason: %s",func, strerror(errno));
+		return STATUS_ERROR;
+	}
+	memset(Commit_Log_Tbl , 0 , size );
+	(Commit_Log_Tbl + (MAX_DB_SERVER * MAX_CONNECTIONS) -1)->inf.useFlag = DATA_END;
+
+	/* create semapho */
+	if ((SemID = semget(IPC_PRIVATE,4,IPC_CREAT | IPC_EXCL | 0600)) < 0)
+	{
+		show_error("%s:semget() failed. (%s)",func,strerror(errno));
+		return STATUS_ERROR;
+	}
+	for ( i = 0 ; i < 4 ; i ++)
+	{
+		semctl(SemID, i, GETVAL, sem_arg);
+		sem_arg.val = 1;
+		semctl(SemID, i, SETVAL, sem_arg);
+	}
+
+	size = sizeof(ReplicationLogInf);
+	Replicateion_Log = malloc(size);
+	if (Replicateion_Log == NULL)
+	{
+		show_error("%s:malloc failed: (%s)",func,strerror(errno));
+		return STATUS_ERROR;
+	}
+	memset(Replicateion_Log , 0 , size );
+	Replicateion_Log->RLog_Sock_Path = NULL;
+
+	/*
+	 * set each datas into the tables
+	 */
+	conf = Com_Info.ConfData_Info.ConfData_Top;
+	while (conf != (ConfDataType *)NULL) 
+	{
+		/* get cluster db data */
+		if (!strcmp(conf->table,CLUSTER_SERVER_TAG))
+		{
+			rec_no = conf->rec_no;
+			if (cnt < rec_no)
+			{
+				cnt = rec_no;
+				if (cnt >= MAX_DB_SERVER)
+				{
+					continue;
+				}
+			}
+			if (!strcmp(conf->key,HOST_NAME_TAG))
+			{
+				strncpy(host_tbl[rec_no].hostName,conf->value,sizeof(host_tbl[rec_no].hostName));
+				conf = (ConfDataType*)conf->next;
+				continue;
+			}
+			if (!strcmp(conf->key,PORT_TAG))
+			{
+				host_tbl[rec_no].port = atoi(conf->value);
+				conf = (ConfDataType*)conf->next;
+				continue;
+			}
+			if (!strcmp(conf->key,RECOVERY_PORT_TAG))
+			{
+				host_tbl[rec_no].recoveryPort = atoi(conf->value);
+				conf = (ConfDataType*)conf->next;
+				continue;
+			}
+			if (!STRCMP(conf->key,LIFECHECK_PORT_TAG))
+			{
+				if (atoi(conf->value) > 0)
+				{
+					host_tbl[rec_no].lifecheckPort = atoi(conf->value);
+				}
+				else
+				{
+					host_tbl[rec_no].lifecheckPort = DEFAULT_CLUSTER_LIFECHECK_PORT;
+				}
+				conf = (ConfDataType*)conf->next;
+				continue;
+			}
+		}
+		/* get cascade server data */
+		else if (!strcmp(conf->table, REPLICATION_SERVER_INFO_TAG))
+		{
+			cascade_rec_no = conf->rec_no ;
+			if (cascade_cnt < cascade_rec_no)
+			{
+				cascade_cnt = cascade_rec_no;
+				if (cascade_cnt >= MAX_DB_SERVER)
+				{
+					continue;
+				}
+			}
+			if (!strcmp(conf->key,HOST_NAME_TAG))
+			{
+				strncpy((Cascade_Tbl+cascade_rec_no)->hostName,conf->value,sizeof(Cascade_Tbl->hostName));
+				conf = (ConfDataType*)conf->next;
+				continue;
+			}
+			if (!strcmp(conf->key,PORT_TAG))
+			{
+				if (atoi(conf->value) > 0)
+				{
+					(Cascade_Tbl+cascade_rec_no)->portNumber = atoi(conf->value);
+				}
+				else
+				{
+					(Cascade_Tbl+cascade_rec_no)->portNumber = DEFAULT_PGRP_PORT;
+				}
+				conf = (ConfDataType*)conf->next;
+				PGRset_cascade_server_status(Cascade_Tbl+cascade_rec_no,DATA_USE);
+				if (cascade_rec_no == 0)
+				{
+					Cascade_Inf->top = Cascade_Tbl;
+				}
+				continue;
+			}
+			if (!strcmp(conf->key,RECOVERY_PORT_TAG))
+			{
+				if (atoi(conf->value) > 0)
+				{
+					(Cascade_Tbl+cascade_rec_no)->recoveryPortNumber = atoi(conf->value);
+				}
+				else
+				{
+					(Cascade_Tbl+cascade_rec_no)->recoveryPortNumber = DEFAULT_PGRP_RECOVERY_PORT;
+				}
+				conf = (ConfDataType*)conf->next;
+				continue;
+			}
+			if (!STRCMP(conf->key,LIFECHECK_PORT_TAG))
+			{
+				if (atoi(conf->value) > 0)
+				{
+					(Cascade_Tbl+cascade_rec_no)->lifecheckPortNumber = atoi(conf->value);
+				}
+				else
+				{
+					(Cascade_Tbl+cascade_rec_no)->lifecheckPortNumber = DEFAULT_PGRP_LIFECHECK_PORT;
+				}
+				conf = (ConfDataType*)conf->next;
+				continue;
+			}
+		}
+		/* get loadbalancer table data */
+		else if (!strcmp(conf->table,LOAD_BALANCE_SERVER_TAG))
+		{
+			lb_rec_no = conf->rec_no;
+			if (lb_cnt < lb_rec_no)
+			{
+				lb_cnt = lb_rec_no;
+				if (lb_cnt >= MAX_DB_SERVER)
+				{
+					continue;
+				}
+			}
+			if (!strcmp(conf->key,HOST_NAME_TAG))
+			{
+				strncpy((LoadBalanceTbl + lb_rec_no)->hostName, conf->value,sizeof(LoadBalanceTbl->hostName));
+				conf = (ConfDataType*)conf->next;
+				continue;
+			}
+			if (!strcmp(conf->key,RECOVERY_PORT_TAG))
+			{
+				(LoadBalanceTbl + lb_rec_no)->useFlag = DATA_USE; 
+				(LoadBalanceTbl + lb_rec_no+1)->useFlag = DATA_END; 
+				if (atoi(conf->value) > 0)
+				{
+					(LoadBalanceTbl + lb_rec_no)->recoveryPort = atoi(conf->value);
+				}
+				else
+				{
+					(LoadBalanceTbl + lb_rec_no)->recoveryPort = DEFAULT_PGLB_RECOVERY_PORT;
+				}
+				(LoadBalanceTbl + lb_rec_no)->sock = -1;
+				(LoadBalanceTbl + lb_rec_no)->recovery_sock = -1;
+				conf = (ConfDataType*)conf->next;
+				continue;
+			}
+			if (!STRCMP(conf->key,LIFECHECK_PORT_TAG))
+			{
+				if (atoi(conf->value) > 0)
+				{
+					(LoadBalanceTbl + lb_rec_no)->lifecheckPort = atoi(conf->value);
+				}
+				else
+				{
+					(LoadBalanceTbl + lb_rec_no)->lifecheckPort = DEFAULT_PGLB_LIFECHECK_PORT;
+				}
+				conf = (ConfDataType*)conf->next;
+				continue;
+			}
+		}
+		else
+		{
+			if (!strcmp(conf->key,REPLICATE_PORT_TAG))
+			{
+				if (atoi(conf->value) > 0)
+				{
+					Port_Number = atoi(conf->value);
+				}
+				else
+				{
+					Port_Number =DEFAULT_PGRP_PORT;
+				}
+				conf = (ConfDataType*)conf->next;
+				continue;
+			}
+			if (!strcmp(conf->key,RECOVERY_PORT_TAG))
+			{
+				if (atoi(conf->value) > 0)
+				{
+					Recovery_Port_Number = atoi(conf->value);
+				}
+				else
+				{
+					Recovery_Port_Number =DEFAULT_PGRP_RECOVERY_PORT;
+				}
+				conf = (ConfDataType*)conf->next;
+				continue;
+			}
+			if (!STRCMP(conf->key,LIFECHECK_PORT_TAG))
+			{
+				if (atoi(conf->value) > 0)
+				{
+					LifeCheck_Port_Number = atoi(conf->value);
+				}
+				else
+				{
+					LifeCheck_Port_Number = DEFAULT_PGRP_LIFECHECK_PORT;
+				}
+				conf = (ConfDataType*)conf->next;
+				continue;
+			}
+			if (!STRCMP(conf->key,RLOG_PORT_TAG))
+			{
+				if (atoi(conf->value) > 0)
+				{
+					Replicateion_Log->RLog_Port_Number = atoi(conf->value);
+				}
+				else
+				{
+					Replicateion_Log->RLog_Port_Number = DEFAULT_PGRP_RLOG_PORT;
+				}
+				conf = (ConfDataType*)conf->next;
+				continue;
+			}
+			if (!STRCMP(conf->key,STATUS_LOG_FILE_TAG))
+			{
+				Com_Info.Log_Info.PGRStatusFileName = strdup(conf->value);
+				conf = (ConfDataType*)conf->next;
+				continue;
+			}
+			if (!STRCMP(conf->key,ERROR_LOG_FILE_TAG))
+			{
+				Com_Info.Log_Info.PGRLogFileName = strdup(conf->value);
+				conf = (ConfDataType*)conf->next;
+				continue;
+			}
+			/* get response mode */
+			if (!strcmp(conf->key,RESPONSE_MODE_TAG))
+			{
+				if (!strcmp(conf->value,RESPONSE_MODE_RELIABLE))
+				{
+					PGR_Response_Inf->response_mode = PGR_RELIABLE_MODE;
+				}
+				else if (!strcmp(conf->value,RESPONSE_MODE_FAST))
+				{
+					PGR_Response_Inf->response_mode = PGR_FAST_MODE;
+				}
+				else
+				{
+					PGR_Response_Inf->response_mode = PGR_NORMAL_MODE;
+				}
+				conf = (ConfDataType*)conf->next;
+				continue;
+			}
+			/* get replication log use or not */
+			if (!strcmp(conf->key,USE_REPLICATION_LOG_TAG))
+			{
+				if (!strcmp(conf->value,"yes"))
+				{
+					PGR_Use_Replication_Log = true;
+				}
+				conf = (ConfDataType*)conf->next;
+				continue;
+			}
+			/* get reserved connection number */
+			if (!strcmp(conf->key,RESERVED_CONNECTIONS_TAG))
+			{
+				if (atoi(conf->value) > 1)
+				{
+					Reserved_Connections = atoi(conf->value);
+				}
+				else
+				{
+					Reserved_Connections = 1;
+				}
+				conf = (ConfDataType*)conf->next;
+				continue;
+			}
+			conf = (ConfDataType*)conf->next;
+		}
+		conf = (ConfDataType*)conf->next;
+	}
+
+	/*
+	 * open log file
+	 */
+	if (Com_Info.Log_Info.Log_Print)
+	{
+		if (Com_Info.Log_Info.PGRLogFileName == NULL)
+		{
+			snprintf(fname,sizeof(fname),"%s/%s",path,PGREPLICATE_LOG_FILE);
+		}
+		else
+		{
+			strncpy(fname,Com_Info.Log_Info.PGRLogFileName,sizeof(fname));
+		}
+		Com_Info.Log_Info.LogFp = fopen(fname,"a");
+		if (Com_Info.Log_Info.LogFp == NULL)
+		{
+			show_error("%s:fopen failed: (%s)",func,strerror(errno));
+			return STATUS_ERROR;
+		}
+	}
+
+	if (Com_Info.Log_Info.PGRStatusFileName == NULL)
+	{
+		snprintf(fname,sizeof(fname),"%s/%s",path,PGREPLICATE_STATUS_FILE);
+	}
+	else
+	{
+		strncpy(fname,Com_Info.Log_Info.PGRStatusFileName,sizeof(fname));
+	}
+	Com_Info.Log_Info.StatusFp = fopen(fname,"a");
+	if (Com_Info.Log_Info.StatusFp == NULL)
+	{
+		show_error("%s:fopen failed: (%s)",func,strerror(errno));
+		return STATUS_ERROR;
+	}
+
+	/* create cluster db server table */
+	Host_Tbl_Begin = (HostTbl *)NULL;
+
+	size = sizeof(HostTbl) * MAX_DB_SERVER;
+	HostTblShmid = shmget(IPC_PRIVATE,size,IPC_CREAT | IPC_EXCL | 0600);
+	if (HostTblShmid < 0)
+	{
+		show_error("%s:shmget() failed. reason: %s",func, strerror(errno));
+		return STATUS_ERROR;
+	}
+	Host_Tbl_Begin = (HostTbl *)shmat(HostTblShmid,0,0);
+	if (Host_Tbl_Begin == (HostTbl *)-1)
+	{
+		show_error("%s:shmat() failed. reason: %s",func, strerror(errno));
+		return STATUS_ERROR;
+	}
+	memset(Host_Tbl_Begin , 0 , size );
+	Host_Tbl_Begin -> useFlag = DATA_END;
+
+	for ( i = 0 ; i <= cnt ; i ++)
+	{
+		PGRadd_HostTbl(&host_tbl[i],DATA_USE);
+	}
+	/* set load balance table */
+	for ( i = 0 ; i <= lb_cnt ; i ++)
+	{
+		(LoadBalanceTbl + i)->port = -1;
+		(LoadBalanceTbl + i)->sock = -1;
+	}
+	memset((LoadBalanceTbl + i),0,sizeof(RecoveryTbl));
+	PGR_Free_Conf_Data();
+
+	/* allocate result buffer of query */
+	PGR_Result = malloc(PGR_MESSAGE_BUFSIZE);
+	if (PGR_Result == NULL)
+	{
+		show_error("%s:malloc() failed. reason: %s",func,strerror(errno));
+		return STATUS_ERROR;
+	}
+	memset(PGR_Result,0,PGR_MESSAGE_BUFSIZE);
+
+	/* allocate log_data */
+	PGR_Log_Header = malloc(sizeof(ReplicateHeader));
+	if (PGR_Log_Header == NULL)
+	{
+		show_error("%s:malloc() failed. reason: %s",func, strerror(errno));
+		return STATUS_ERROR;
+	}
+	memset(PGR_Log_Header,0,sizeof(ReplicateHeader));
+
+	/* allocate send query id */
+	size = sizeof(unsigned int) * (MAX_DB_SERVER +1);
+	PGR_Send_Query_ID = malloc (sizeof(unsigned int) * MAX_DB_SERVER);
+	if (PGR_Send_Query_ID == NULL)
+	{
+		show_error("%s:malloc() failed. reason: %s",func, strerror(errno));
+		return STATUS_ERROR;
+	}
+	memset(PGR_Send_Query_ID, 0, size);
+
+	/* create lock wait table */
+	size = sizeof(LockWaitInf);
+	LockWaitTblShmid = shmget(IPC_PRIVATE,size,IPC_CREAT | IPC_EXCL | 0600);
+	if (LockWaitTblShmid < 0)
+	{
+		show_error("%s:shmget() failed. reason: %s", func,strerror(errno));
+		return STATUS_ERROR;
+	}
+	Lock_Wait_Tbl = (LockWaitInf *)shmat(LockWaitTblShmid,0,0);
+	if (Lock_Wait_Tbl == (LockWaitInf *)-1)
+	{
+		show_error("%s:shmat() failed. reason: %s",func, strerror(errno));
+		return STATUS_ERROR;
+	}
+	memset(Lock_Wait_Tbl , 0 , size );
+	
+	for ( i = 0 ; i < MAX_DB_SERVER ; i ++)
+	{
+		StartReplication[i] = true;
+	}
+
+	/* set self data into cascade table */
+
+	cascade_rec_no ++;
+	gethostname((Cascade_Tbl+cascade_rec_no)->hostName,sizeof(Cascade_Tbl->hostName));
+	(Cascade_Tbl+cascade_rec_no)->portNumber = Port_Number;
+	(Cascade_Tbl+cascade_rec_no)->recoveryPortNumber = Com_Info.ConfData_Info.Recovery_Port_Number;
+
+	PGRset_cascade_server_status(Cascade_Tbl+cascade_rec_no,DATA_USE);
+	/* terminate */
+	(Cascade_Tbl+(cascade_rec_no+1))->useFlag = DATA_END;
+
+	Cascade_Inf->top = Cascade_Tbl;
+	Cascade_Inf->end = Cascade_Tbl+cascade_rec_no;
+	Cascade_Inf->lower = NULL;
+	if (cascade_rec_no >= 1)
+	{
+		Cascade_Inf->upper = (Cascade_Tbl+cascade_rec_no - 1);
+	}
+
+	Cascade_Inf->myself = (Cascade_Tbl+cascade_rec_no);
+	Cascade_Inf->useFlag = DATA_USE;
+
+	return STATUS_OK;
+}
+
+#endif /* USE_REPLICATION */
diff -ruN postgresql-7.4.13-old/src/pgcluster/pgrp/main.c postgresql-7.4.13/src/pgcluster/pgrp/main.c
--- postgresql-7.4.13-old/src/pgcluster/pgrp/main.c	1970-01-01 01:00:00.000000000 +0100
+++ postgresql-7.4.13/src/pgcluster/pgrp/main.c	2006-08-05 16:53:43.000000000 +0200
@@ -0,0 +1,860 @@
+/*--------------------------------------------------------------------
+ * FILE:
+ *    main.c
+ *    Replication server for PostgreSQL
+ *
+ * NOTE:
+ *    This is the main module of the replication server.
+ *
+ * Portions Copyright (c) 2003, Atsushi Mitani
+ *--------------------------------------------------------------------
+ */
+#ifdef USE_REPLICATION
+
+#include "postgres.h"
+
+#include <pthread.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <signal.h>
+#include <sys/wait.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <time.h>
+#include <sys/param.h>
+#include <arpa/inet.h>
+#include <sys/file.h>
+
+#ifdef HAVE_NETINET_TCP_H
+#include <netinet/tcp.h>
+#endif
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#endif
+
+#include "miscadmin.h"
+#include "nodes/nodes.h"
+#include "libpq-fe.h"
+#include "libpq/libpq-fs.h"
+#include "libpq-int.h"
+#include "fe-auth.h"
+#include "access/xact.h"
+#include "replicate_com.h"
+#include "pgreplicate.h"
+
+#ifdef WIN32
+#include "win32.h"
+#endif
+#include <arpa/inet.h>
+#ifdef HAVE_CRYPT_H
+#include <crypt.h>
+#endif
+
+#ifdef MULTIBYTE
+#include "mb/pg_wchar.h"
+#endif
+
+/*--------------------------------------
+ * GLOBAL VARIABLE DECLARATION
+ *--------------------------------------
+ */
+/* for replicate_com.h */
+PGR_Com_Info Com_Info;
+
+/* replication server data */
+uint16_t Port_Number = 0;
+uint16_t LifeCheck_Port_Number = 0;
+uint16_t Recovery_Port_Number = 0;
+
+/* global table data */
+HostTbl *Host_Tbl_Begin = NULL;
+TransactionTbl * Transaction_Tbl_Begin = NULL;
+TransactionTbl * Transaction_Tbl_End = NULL;
+TransactionTbl * PGconn_Tbl_Begin = NULL;
+TransactionTbl * PGconn_Tbl_End = NULL;
+RecoveryTbl * LoadBalanceTbl = NULL;
+RecoveryStatusInf * Recovery_Status_Inf = NULL;
+LockWaitInf * Lock_Wait_Tbl = NULL;
+ReplicateHeader * PGR_Log_Header = NULL;
+ReplicateServerInfo * Cascade_Tbl = NULL;;
+CommitLogInf * Commit_Log_Tbl = NULL;
+QueryLogType * Query_Log_Top = NULL;
+QueryLogType * Query_Log_End = NULL;
+CascadeInf * Cascade_Inf = NULL;
+ReplicationLogInf * Replicateion_Log = NULL;
+/* IPC's id data */
+int RecoveryShmid = 0;
+int HostTblShmid = 0;
+int LockWaitTblShmid = 0;
+int LoadBalanceTblShmid = 0;
+int CascadeTblShmid = 0;
+int CascadeInfShmid = 0;
+int CommitLogShmid = 0;
+int QueryLogMsgid = 0;
+int QueryLogAnsMsgid = 0;
+int PGconnMsgid = 0;
+int MaxBackends = 0;
+char * PGR_Result = NULL;
+int SemID = 0;
+int RecoverySemID = 0;
+int VacuumSemID = 0;
+char * PGR_Data_Path = NULL;
+char * PGR_Write_Path = NULL;
+int IS_SESSION_AUTHORIZATION = 0;
+ResponseInf * PGR_Response_Inf = NULL; 
+bool StartReplication[MAX_DB_SERVER]; 
+bool PGR_Cascade = false;
+bool PGR_Use_Replication_Log = false;
+bool	PGR_AutoCommit = true;
+unsigned int * PGR_Send_Query_ID = NULL;
+unsigned int PGR_Query_ID = 0;
+RecoveryQueueInf RecoveryQueue;
+char * Backend_Socket_Dir = NULL;
+char * PGRuserName = NULL;
+int Reserved_Connections = 1;
+int Idle_Flag = IDLE_MODE;
+bool Exit_Request = false;
+
+extern char *optarg;
+
+/*--------------------------------------
+ * PROTOTYPE DECLARATION
+ *--------------------------------------
+ */
+static void startup_replication_server(void);
+static int replicate_loop(int fd);
+static void replicate_main(void);
+static void quick_exit(SIGNAL_ARGS);
+static void daemonize(void);
+static void write_pid_file(void);
+static bool is_exist_pid_file(void);
+static void child_wait(SIGNAL_ARGS);
+static void usage(void);
+
+void PGRstop_pgreplicate(int sig);
+
+/*--------------------------------------------------------------------
+ * SYMBOL
+ *    replicate_loop()
+ * NOTES
+ *   replication module
+ * ARGS
+ *    int fd :
+ * RETURN
+ *    OK: STATUS_OK
+ *    NG: STATUS_ERROR
+ *--------------------------------------------------------------------
+ */
+static int
+replicate_loop(int fd)
+{
+	char *func = "replicate_loop()";
+	pid_t pgid = 0;
+	pid_t pid = 0;
+	int sock = -1;
+	int rtn = 0;
+	bool exist_sys_log = false;
+
+	PGR_Create_Acception(fd,&sock,"",Port_Number);
+	pgid = getpgid(0);
+	pid = fork();
+	if (pid <0)
+	{
+		show_error("%s:fork failed (%s)",func,strerror(errno));
+		PGRreplicate_exit(0);
+	}
+	if (pid == 0)
+	{
+		int status = LOOP_CONTINUE;
+		bool PGR_Cascade = false;
+		ReplicateHeader  header;
+		char * query = NULL;
+
+		signal(SIGHUP, SIG_IGN);	
+		signal(SIGINT, quick_exit);	
+		signal(SIGQUIT, quick_exit);	
+		signal(SIGTERM, quick_exit);	
+		signal(SIGALRM, quick_exit); 
+		setpgid(0,pgid);
+
+		/* child loop */
+		for (;;)
+		{
+			fd_set	  rmask;
+			struct timeval timeout;
+
+			Idle_Flag = IDLE_MODE;
+			if (Exit_Request)
+			{
+				quick_exit(SIGINT);
+			}
+			timeout.tv_sec = 1;
+			timeout.tv_usec = 0;
+			
+			if (query != NULL)
+			{
+				free(query);
+				query = NULL;
+			}
+			/*
+			 * Wait for something to happen.
+			 */
+			FD_ZERO(&rmask);
+			FD_SET(sock,&rmask);
+			rtn = select(sock+1, &rmask, (fd_set *)NULL, (fd_set *)NULL, &timeout);
+			if (rtn && FD_ISSET(sock, &rmask))
+			{
+				Idle_Flag = BUSY_MODE;
+#ifdef PRINT_DEBUG
+				show_debug("%s:replicate_loop selected",func);
+#endif			
+				query = PGRread_packet(sock,&header);
+				if ((query == NULL) && (header.cmdSys == 0))
+				{
+#ifdef PRINT_DEBUG
+				show_debug("%s: PGRread_packet failed query[%s] cmdSys[%c]",func,query,header.cmdSys);
+#endif			
+					if (exist_sys_log)
+					{
+						show_error("%s:upper cascade closed",func);
+						memset(&header, 0, sizeof(ReplicateHeader));
+						header.cmdSys = CMD_SYS_CALL;
+						header.cmdSts = CMD_STS_QUERY_SUSPEND;
+						header.query_size = htonl(0);
+						PGRsend_rlog_to_local(&header, NULL);
+						exist_sys_log = false;
+					}
+					else
+					{
+#ifdef PRINT_DEBUG
+						show_debug("%s:session closed",func);
+#endif			
+					}
+					break;
+				}
+				switch (header.cmdSys)
+				{
+					case CMD_SYS_REPLICATE:
+						status = PGRdo_replicate(sock,&header,query);
+						PGRset_start_life_check();
+						break;
+					case CMD_SYS_LOG:
+						exist_sys_log = true;
+						PGRsend_rlog_to_local(&header, query);
+						/* set own replicate id by rlog */
+						PGRset_replication_id(header.replicate_id);
+						PGRsend_notice_rlog_done(sock);
+						break;
+					case  CMD_SYS_CASCADE:
+						PGR_Cascade = true;
+						PGRcascade_main(sock,&header,query);
+						break;
+					case  CMD_SYS_CALL:
+						if (header.cmdSts == CMD_STS_TRANSACTION_ABORT)
+						{
+							PGRreconfirm_commit(sock,&header);
+						}
+						else if (header.cmdSts == CMD_STS_NOTICE)
+						{
+							if (header.cmdType == CMD_TYPE_DEADLOCK_DETECT)
+							{
+								status = LOOP_END;
+							}
+						}
+						else if (header.cmdSts == CMD_STS_RESPONSE)
+						{
+							if (header.cmdType == CMD_TYPE_FRONTEND_CLOSED)
+							{
+								status = LOOP_END;
+							}
+						}
+						break;
+				}
+			}
+			if (query != NULL)
+			{
+				free(query);
+				query = NULL;
+			}
+			if (status == LOOP_END)
+			{
+				break;
+			}
+		}
+		PGR_Close_Sock(&sock);
+		PGRclear_transactions();
+		PGRclear_connections( DATA_TEMP_USE );
+#ifdef PRINT_DEBUG
+		show_debug("%s:replicate loop exit",func);
+#endif			
+		pthread_exit((void*)0);
+	}
+	else
+	{
+		PGR_Close_Sock(&sock);
+		return 0;
+	}
+}
+
+static void
+startup_replication_server(void)
+{
+	char hostName[HOSTNAME_MAX_LENGTH];
+
+	memset(hostName,0,sizeof(hostName));
+	gethostname(hostName,sizeof(hostName)-1);
+	if (PGRuserName == NULL)
+	{
+		PGRuserName = getenv("LOGNAME");
+		if (PGRuserName == NULL)
+		{
+			PGRuserName = getenv("USER");
+			if (PGRuserName == NULL)
+				PGRuserName = "postgres";
+		}
+	}
+	PGRnotice_replication_server(hostName,Port_Number,Recovery_Port_Number,LifeCheck_Port_Number,PGRuserName);
+}
+
+/*--------------------------------------------------------------------
+ * SYMBOL
+ *    replicate_main()
+ * NOTES
+ *    Replication main module
+ * ARGS
+ *    void
+ * RETURN
+ *    none
+ *--------------------------------------------------------------------
+ */
+static void
+replicate_main(void)
+{
+	char * func = "replicate_main()";
+	int status;
+	int fd = -1;
+	int rtn;
+
+	status = PGR_Create_Socket_Bind(&fd, "", Port_Number);
+	if (status != STATUS_OK)
+	{
+		PGRreplicate_exit(0);
+	}
+#ifdef PRINT_DEBUG
+	show_debug("%s:replicate main %d port bind OK",func,Port_Number);
+#endif			
+	
+	/* cascade start up notice */
+	if (Cascade_Inf->upper != NULL)
+	{
+		PGRstartup_cascade();
+	}
+
+	/* replication start up notice */
+	startup_replication_server();
+
+	for (;;)
+	{
+		fd_set	  rmask;
+		struct timeval timeout;
+
+		Idle_Flag = IDLE_MODE;
+		if (Exit_Request)
+		{
+			PGRreplicate_exit(SIGINT);
+		}
+		timeout.tv_sec = PGR_RECV_TIMEOUT;
+		timeout.tv_usec = 0;
+
+
+		/*
+		 * Wait for something to happen.
+		 */
+		FD_ZERO(&rmask);
+		FD_SET(fd,&rmask);
+		rtn = select(fd+1, &rmask, (fd_set *)NULL, (fd_set *)NULL, &timeout);
+		if (rtn && FD_ISSET(fd, &rmask))
+		{
+			Idle_Flag = BUSY_MODE;
+			/*
+			 * get recovery status.
+			 */
+			PGRcheck_recovered_host();
+			/* 
+			 * get new db login info
+			 */
+			PGRget_pgconn_queue();
+			/*
+			 * call replication module
+			 */
+			replicate_loop(fd);
+		}
+	}
+}
+
+/*--------------------------------------------------------------------
+ * SYMBOL
+ *    quick_exit()
+ * NOTES
+ *    Exit child process
+ * ARGS
+ *    SIGNAL_ARGS: receive signal number(I)
+ * RETURN
+ *    none
+ *--------------------------------------------------------------------
+ */
+static void
+quick_exit(int sig)
+{
+	Exit_Request = true;
+	if (sig == SIGTERM)
+	{
+		if (Idle_Flag == BUSY_MODE)
+		{
+			return;
+		}
+	}
+	exit(0);
+}
+
+/*--------------------------------------------------------------------
+ * SYMBOL
+ *    daemonize()
+ * NOTES
+ *    Daemonize this process
+ * ARGS
+ *    void
+ * RETURN
+ *    none
+ *--------------------------------------------------------------------
+ */
+static void 
+daemonize(void)
+{
+	char * func = "daemonize()";
+	int		i;
+	pid_t		pid;
+
+	pid = fork();
+	if (pid == (pid_t) -1)
+	{
+		show_error("%s:fork() failed. reason: %s",func, strerror(errno));
+		exit(1);
+		return;					/* not reached */
+	}
+	else if (pid > 0)
+	{			/* parent */
+		exit(0);
+	}
+
+#ifdef HAVE_SETSID
+	if (setsid() < 0)
+	{
+		show_error("%s:setsid() failed. reason:%s",func,strerror(errno));
+		exit(1);
+	}
+#endif
+
+	i = open("/dev/null", O_RDWR);
+	dup2(i, 0);
+	dup2(i, 1);
+	dup2(i, 2);
+	close(i);
+}
+
+/*--------------------------------------------------------------------
+ * SYMBOL
+ *    write_pid_file()
+ * NOTES
+ *    The process ID is written in the file.
+ *    This process ID is used when finish pglb.
+ * ARGS
+ *    void
+ * RETURN
+ *    none
+ *--------------------------------------------------------------------
+ */
+static void 
+write_pid_file(void)
+{
+	char * func = "write_pid_file()";
+	FILE *fd;
+	char fname[256];
+	char pidbuf[128];
+
+	snprintf(fname, sizeof(fname), "%s/%s", PGR_Write_Path, PGREPLICATE_PID_FILE);
+	fd = fopen(fname, "w");
+	if (!fd)
+	{
+		show_error("%s:could not open pid file as %s. reason: %s",
+				   func,fname, strerror(errno));
+		exit(1);
+	}
+	snprintf(pidbuf, sizeof(pidbuf), "%d", getpid());
+	fwrite(pidbuf, strlen(pidbuf), 1, fd);
+	if (fclose(fd))
+	{
+		show_error("%s:could not write pid file as %s. reason: %s",
+				   func,fname, strerror(errno));
+		exit(1);
+	}
+}
+
+/*--------------------------------------------------------------------
+ * SYMBOL
+ *    PGRstop_pgreplicate()
+ * NOTES
+ *    Stop the pgreplicate process
+ * ARGS
+ *    void
+ * RETURN
+ *    none
+ *--------------------------------------------------------------------
+ */
+void 
+PGRstop_pgreplicate(int sig)
+{
+	char * func = "PGRstop_pgreplicate()";
+	FILE *fd;
+	char fname[256];
+	char pidbuf[128];
+	pid_t pid;
+
+	if (sig == 0)
+	{
+		sig = SIGTERM;
+	}
+	signal(sig,SIG_IGN);
+
+	snprintf(fname, sizeof(fname), "%s/%s", PGR_Write_Path, PGREPLICATE_PID_FILE);
+	fd = fopen(fname, "r");
+	if (!fd)
+	{
+		show_error("%s:could not open pid file as %s. reason: %s",
+				   func,fname, strerror(errno));
+		exit(1);
+	}
+	memset(pidbuf,0,sizeof(pidbuf));
+	fread(pidbuf, sizeof(pidbuf), 1, fd);
+	fclose(fd);
+	pid = atoi(pidbuf);
+
+	if (kill (pid,sig) == -1)
+	{
+		show_error("%s:could not stop pid: %d, reason: %s",func,pid,strerror(errno));
+		exit(1);
+	}
+	if (sig != SIGTERM)
+		exit(0);
+}
+
+/*--------------------------------------------------------------------
+ * SYMBOL
+ *    is_exist_pid_file()
+ * NOTES
+ *    Check existence of pid file.
+ * ARGS
+ *    void
+ * RETURN
+ *    1: the pid file is exist
+ *    0: the pid file is not exist
+ *--------------------------------------------------------------------
+ */
+static bool
+is_exist_pid_file(void)
+{
+	char fname[256];
+	struct stat buf;
+
+	snprintf(fname, sizeof(fname), "%s/%s", PGR_Write_Path, PGREPLICATE_PID_FILE);
+	if (stat(fname,&buf) == 0)
+	{
+		/* pid file is exist */
+		return true;
+	}
+	else
+	{
+		/* pid file is not exist */
+		return false;
+	}
+}
+
+/*--------------------------------------------------------------------
+ * SYMBOL
+ *    child_wait()
+ * NOTES
+ *    Waiting for hung up a child
+ * ARGS
+ *    int signal_args: signal number (expecting the SIGCHLD)
+ * RETURN
+ *    none
+ *--------------------------------------------------------------------
+ */
+static void
+child_wait(SIGNAL_ARGS)
+{
+	pid_t pid = 0;
+
+	do {
+		int ret;
+		pid = waitpid(-1,&ret,WNOHANG);
+	} while(pid > 0);
+}
+
+/*--------------------------------------------------------------------
+ * SYMBOL
+ *    usage()
+ * NOTES
+ *    show usage of pglb
+ * ARGS
+ *    void
+ * RETURN
+ *    none
+ *--------------------------------------------------------------------
+ */
+static void
+usage(void)
+{
+	char * path;
+
+	path = getenv("PGDATA");
+	if (path == NULL)
+		path = ".";
+	fprintf(stderr,"PGReplicate version [%s]\n",PGREPLICATE_VERSION);
+	fprintf(stderr,"A replication server for cluster DB servers (based on PostgreSQL)\n\n");
+	fprintf(stderr,"usage: pgreplicate [-D path_of_config_file] [-W path_of_work_files] [-U login user][-l][-n][-v][-h][stop][restart]\n");
+	fprintf(stderr,"    config file default path: %s/%s\n",path, PGREPLICATE_CONF_FILE);
+	fprintf(stderr,"    -l: print error logs in the log file.\n");
+	fprintf(stderr,"    -n: don't run in daemon mode.\n");
+	fprintf(stderr,"    -v: debug mode. need '-n' flag\n");
+	fprintf(stderr,"    -h: print this help\n");
+	fprintf(stderr,"    stop: stop pgreplicate\n");
+	fprintf(stderr,"    restart: restart pgreplicate\n");
+}
+
+/*--------------------------------------------------------------------
+ * SYMBOL
+ *    main()
+ * NOTES
+ *    main module of pgreplicate
+ * ARGS
+ *    int argc: number of parameter
+ *    char ** argv: value of parameter
+ * RETURN
+ *    none
+ *--------------------------------------------------------------------
+ */
+int
+main(int argc, char * argv[])
+{
+	char * func = "main()";
+	int opt = 0;
+	pid_t pgid = 0;
+	pid_t pid = 0;
+	char * r_path = NULL;
+	char * w_path = NULL;
+	bool detach = true;
+	pid_t syn_pid = 0;
+	pid_t ack_pid = 0;
+	pid_t rlog_pid = 0;
+	int sig_opt = SIGTERM;
+
+	/* init global variables */
+	PGR_Init_Com_Info(&Com_Info);
+
+	r_path = getenv("PGDATA");
+	if (r_path == NULL)
+		r_path = ".";
+	while ((opt = getopt(argc, argv, "U:D:W:m:lvnh")) != -1)
+	{
+		switch (opt)
+		{
+			case 'U':
+				if (!optarg)
+				{
+					usage();
+					exit(1);
+				}
+				PGRuserName = strdup(optarg);
+				break;
+			case 'D':
+				if (!optarg)
+				{
+					usage();
+					exit(1);
+				}
+				r_path = optarg;
+				break;
+			case 'W':
+				if (!optarg)
+				{
+					usage();
+					exit(1);
+				}
+				w_path = optarg;
+				break;
+			case 'm':
+				if (!optarg)
+				{
+					usage();
+					exit(1);
+				}
+				if (!strcmp(optarg,"i"))
+				{
+					sig_opt = SIGINT;
+				}
+				break;
+			case 'l':
+				Com_Info.Log_Info.Log_Print = 1;
+				break;
+			case 'v':
+				Com_Info.Log_Info.Debug_Print = 1;
+				break;
+			case 'n':
+				detach = false;
+				break;
+			case 'h':
+				usage();
+				exit(0);
+				break;
+			default:
+				usage();
+				exit(1);
+		}
+	}
+	PGR_Data_Path = r_path;
+	if (w_path == NULL)
+	{
+		PGR_Write_Path = PGR_Data_Path;
+	}
+	else
+	{
+		PGR_Write_Path = w_path;
+	}
+
+	if (optind == (argc-1) && !strcmp(argv[optind],"stop"))
+	{
+		PGRstop_pgreplicate(sig_opt);
+		exit(0);
+	}
+	if (optind == (argc-1) && !strcmp(argv[optind],"restart"))
+	{
+		PGRstop_pgreplicate(SIGTERM);
+	}
+	else if (optind == argc)
+	{
+		if (is_exist_pid_file())
+		{
+			fprintf(stderr,"pid file %s/%s found. is another pgreplicate running?", PGR_Write_Path, PGREPLICATE_PID_FILE);
+			exit(1);
+		}
+	}
+	else if (optind < argc)
+	{
+		usage();
+		exit(1);
+	}
+
+	if (detach)
+	{
+		daemonize();
+	}
+	write_pid_file();
+
+	if (PGRset_Conf_Data(PGR_Data_Path) != STATUS_OK)
+	{
+		show_error("%s:PGRset_Conf_Data error",func);
+		PGRreplicate_exit(0);
+	}
+	if (PGRinit_recovery() != STATUS_OK)
+	{
+		show_error("%s:PGRinit_recovery error",func);
+		PGRreplicate_exit(0);
+	}
+	if (PGRsyn_init() != STATUS_OK)
+	{
+		show_error("%s:syn_init is failed",func);
+		PGRreplicate_exit(0);
+	}
+
+	/* life check process start */
+	syn_pid = PGR_SYN_Main(SYN_TO_CLUSTER_DB, (void *)Host_Tbl_Begin);
+	if (syn_pid < 0)
+	{
+		show_error("%s:PGR_SYN_Main failed",func);
+		PGRreplicate_exit(0);
+	}
+	ack_pid = PGR_ACK_Main(LifeCheck_Port_Number);
+	if (ack_pid < 0)
+	{
+		show_error("%s:PGR_ACK_Main failed",func);
+		PGRreplicate_exit(0);
+	}
+	if ( PGR_Use_Replication_Log == true )
+	{
+#ifdef PRINT_DEBUG
+		show_debug("Use Replication Log. Start PGR_RLog_Main()");
+#endif
+		rlog_pid = PGR_RLog_Main();
+		if (rlog_pid < 0)
+		{
+			show_error("%s:PGR_RLog_Main failed",func);
+			PGRreplicate_exit(0);
+		}
+	}
+	pgid = getpgid(0);
+	pid = fork();
+	if (pid == (pid_t) -1)
+	{
+		show_error("%s:fork() failed. reason: %s", func,strerror(errno));
+		exit(1);
+	}
+	if (pid == 0)
+	{
+		signal(SIGHUP, SIG_IGN);	
+		signal(SIGINT, quick_exit);	
+		signal(SIGQUIT, quick_exit);	
+		signal(SIGTERM, quick_exit);	
+		signal(SIGPIPE, SIG_IGN);
+		/*
+		 * in child process,
+		 * call recovery module
+		 */
+		setpgid(0,pgid);
+		PGRrecovery_main();
+	}
+	else
+	{
+		signal(SIGSEGV, PGRreplicate_exit);
+		signal(SIGINT, PGRreplicate_exit);
+		signal(SIGQUIT, PGRreplicate_exit);
+		signal(SIGTERM, PGRreplicate_exit);
+		signal(SIGCHLD, child_wait);
+		signal(SIGPIPE, SIG_IGN);
+		/*
+		 * call replicate module
+		 */
+		Replicateion_Log->r_log_sock = -1;
+		replicate_main();
+	}
+
+	PGRreplicate_exit(0);
+	return STATUS_OK;
+}
+#else
+void main() { }
+#endif /* USE_REPLICATION */
diff -ruN postgresql-7.4.13-old/src/pgcluster/pgrp/pgreplicate.conf.sample postgresql-7.4.13/src/pgcluster/pgrp/pgreplicate.conf.sample
--- postgresql-7.4.13-old/src/pgcluster/pgrp/pgreplicate.conf.sample	1970-01-01 01:00:00.000000000 +0100
+++ postgresql-7.4.13/src/pgcluster/pgrp/pgreplicate.conf.sample	2006-08-05 16:53:43.000000000 +0200
@@ -0,0 +1,107 @@
+#=============================================================
+#  PGReplicate configuration file
+#                                     for  PGCluster-1.1.0a
+#-------------------------------------------------------------
+# file: pgreplicate.conf
+#-------------------------------------------------------------
+# This file controls:
+#       o which hosts & port are cluster server
+#       o which port use for replication request from cluster server
+#=============================================================
+#
+#-------------------------------------------------------------
+# A setup of Cluster DB(s)
+#
+#		o Host_Name : The host name of Cluster DB.
+#		              -- please write a host name by FQDN.
+#		              -- do not write IP address.
+#		o Port : The connection port with postmaster.
+#		o Recovery_Port : The connection port at the time of 
+#		                  a recovery sequence .
+#		o LifeCheck_Port : connection for life check process
+#-------------------------------------------------------------
+#<Cluster_Server_Info>
+#    <Host_Name>   master.postgres.jp  </Host_Name>
+#    <Port>                5432        </Port>
+#    <Recovery_Port>       7101        </Recovery_Port>
+#    <LifeCheck_Port>      7201        </LifeCheck_Port>
+#</Cluster_Server_Info>
+#<Cluster_Server_Info>
+#    <Host_Name>   clusterdb2.postgres.jp </Host_Name>
+#    <Port>                5432        </Port>
+#    <Recovery_Port>       7101        </Recovery_Port>
+#    <LifeCheck_Port>      7201        </LifeCheck_Port>
+#</Cluster_Server_Info>
+#<Cluster_Server_Info>
+#    <Host_Name>   cluster3.postgres.jp   </Host_Name>
+#    <Port>                5432        </Port>
+#    <Recovery_Port>       7101        </Recovery_Port>
+#    <LifeCheck_Port>      7201        </LifeCheck_Port>
+#</Cluster_Server_Info>
+#
+#-------------------------------------------------------------
+# A setup of Load Balance Server
+#
+#		o Host_Name : The host name of a load balance server.
+#		              -- please write a host name by FQDN.
+#		              -- do not write IP address.
+#		o Recovery_Port : The connection port at the time of 
+#		                  a recovery sequence .
+#		o LifeCheck_Port : connection for life check process
+#-------------------------------------------------------------
+#<LoadBalance_Server_Info>
+#    <Host_Name>   loadbalancer.postgres.jp  </Host_Name>
+#    <Recovery_Port>       6101        </Recovery_Port>
+#    <LifeCheck_Port>      6201        </LifeCheck_Port>
+#</LoadBalance_Server_Info>
+#
+#------------------------------------------------------------
+# A setup of the upper replication server for cascade connection.
+#
+#		o Host_Name : The host name of Cluster DB.
+#		              -- please write a host name by FQDN.
+#		              -- do not write IP address.
+#		o Port : The connection port with postmaster.
+#		o Recovery_Port : The connection port at the time of 
+#		                  a recovery sequence .
+#		o LifeCheck_Port : connection for life check process
+#------------------------------------------------------------
+#<Replicate_Server_Info>
+#    <Host_Name> upper_replicate.postgres.jp </Host_Name>
+#    <Port>                   8001           </Port>
+#    <Recovery_Port>          8101           </Recovery_Port>
+#    <LifeCheck_Port>         8201           </LifeCheck_Port>
+#</Replicate_Server_Info>
+#
+#-------------------------------------------------------------
+# A setup of a replication server
+#
+#		o Status_Log_File : logging file of cluster db's status
+#		o Error_Log_File : logging file of error and warning
+#		o Replicate_Port : connection for reprication
+#		o Recovery_Port : connection for recovery
+#		o LifeCheck_Port : connection for life check process
+#		o Response_mode : timing which returns a response
+#		  normal   -- return result of DB which received the query
+#		  reliable -- return result after waiting for response of 
+#                      all Cluster DBs.
+#		o Use_Replication_Log : When this server hangs up without
+#                               being replicated to the end,
+#                               a remote server continues the
+#                               replication using this log. 
+#		  yes  --  use replication log
+#		  no   --  not use replication log
+#		o Reserved_Connections : The number of reserved connections
+#                                from this replication server
+#                                to each cluster dbs.
+#                                (default is 1).
+#-------------------------------------------------------------
+<Status_Log_File>  /tmp/pgreplicate.sts  </Status_Log_File>
+<Error_Log_File>   /tmp/pgreplicate.log  </Error_Log_File>
+<Replication_Port>       8001            </Replication_Port>
+<Recovery_Port>          8101            </Recovery_Port>
+<LifeCheck_Port>         8201            </LifeCheck_Port>
+<RLOG_Port>              8301            </RLOG_Port>
+<Response_Mode>        normal            </Response_Mode>
+<Use_Replication_Log>      no            </Use_Replication_Log>
+<Reserved_Connections>      1            </Reserved_Connections>
diff -ruN postgresql-7.4.13-old/src/pgcluster/pgrp/pgreplicate.h postgresql-7.4.13/src/pgcluster/pgrp/pgreplicate.h
--- postgresql-7.4.13-old/src/pgcluster/pgrp/pgreplicate.h	1970-01-01 01:00:00.000000000 +0100
+++ postgresql-7.4.13/src/pgcluster/pgrp/pgreplicate.h	2006-08-05 16:53:43.000000000 +0200
@@ -0,0 +1,351 @@
+/*--------------------------------------------------------------------
+ * FILE:
+ *     pgreplicate.h
+ *
+ * Portions Copyright (c) 2003-2005, Atsushi Mitani
+ *--------------------------------------------------------------------
+ */
+#ifndef PGREPLICATE_H
+#define PGREPLICATE_H
+
+#define PGREPLICATE_VERSION		"1.1.1a"
+
+#if 0
+#define COMMIT_ABORT_TEST	(1)
+#define INSERT_ABORT_TEST	(1)
+#endif
+
+/* cascade packet id */
+#define	CMD_SYS_CASCADE	'C'
+#define CMD_STS_TO_UPPER 'U'
+#define CMD_STS_TO_LOWER 'L'
+#define CMD_TYPE_ADD 'A'
+#define CMD_TYPE_DELTE 'D'
+#define CMD_TYPE_UPDATE_ALL 'F'
+
+/* log packet id */
+#define	CMD_SYS_LOG	'L'
+#define CMD_STS_DELETE_QUERY 'q'
+#define CMD_STS_DELETE_TRANSACTION 't'
+#define CMD_STS_UPDATE_QUERY 'r'
+#define CMD_STS_UPDATE_TRANSACTION 'u'
+
+#define MAX_HOST_NAME_LEN	(128)
+#define MAX_DB_SERVER	(32)
+#define PGR_MAX_SOCKET_QUEUE (10000)
+#define	MAX_CONNECTIONS	(128)
+#define PGR_MAX_TICKETS (0x7FFFFFFF)
+#define PGR_MAX_QUERY_ID (0x7FFFFFFF)
+#define PGR_CONNECT_RETRY_TIME  (3)
+#define PGR_EXEC_RETRY_TIME  (5)
+#define RECOVERY_HEADER_MTYPE	(1)
+#define QUERY_LOG_MTYPE (2)
+#define PGREPLICATE_CONF_FILE	"pgreplicate.conf"
+#define PGREPLICATE_LOG_FILE	"pgreplicate.log"
+#define PGREPLICATE_STATUS_FILE	"pgreplicate.sts"
+#define PGREPLICATE_PID_FILE	"pgreplicate.pid"
+#define RECOVERY_QUEUE_FILE	".pgr_recovery."
+#define CLUSTER_SERVER_TAG	"Cluster_Server_Info"
+#define LOAD_BALANCE_SERVER_TAG	"LoadBalance_Server_Info"
+#define REPLICATE_PORT_TAG	"Replication_Port"
+#define RECOVERY_PORT_TAG	"Recovery_Port"
+#define LIFECHECK_PORT_TAG	"LifeCheck_Port"
+#define RLOG_PORT_TAG		"RLOG_Port"
+#define RESPONSE_MODE_TAG	"Response_Mode"
+#define	RESPONSE_MODE_FAST	"fast"
+#define	RESPONSE_MODE_NORMAL	"normal"
+#define	RESPONSE_MODE_RELIABLE	"reliable"
+#define	USE_REPLICATION_LOG_TAG	"Use_Replication_Log"
+#define	RESERVED_CONNECTIONS_TAG	"Reserved_Connections"
+/* semapho numner of recovery queue */
+#define SEM_NUM_OF_RECOVERY	(1)
+#define SEM_NUM_OF_RECOVERY_QUEUE	(2)
+/* semapho numner of lock tickets */
+#define SEM_NUM_OF_LOCK	(1)
+
+#define STATUS_LOCK_CONFLICT (2)
+#define STATUS_DEADLOCK_DETECT (3)
+#define STATUS_ABORTED (4)
+#define STATUS_NOT_YET_REPLICATE (5)
+#define STATUS_ALREADY_REPLICATED (6)
+#define STATUS_SKIP_REPLICATE (7)
+#define PGR_NOWAIT_ANSWER (0)
+#define PGR_WAIT_ANSWER (1)
+#define LOOP_CONTINUE	(0)
+#define LOOP_END	(1)
+#define LOWER_CASCADE	(1)
+#define UPPER_CASCADE	(2)
+#define ALL_CASCADE	(3)
+#define NOTICE_SYSTEM_CALL_TYPE (10)
+#define RECOVERY_QUERY_TYPE (20)
+
+#define PGR_TIME_OUT	(60)
+#define PGR_SEND_RETRY_CNT (1000)
+#define PGR_SEND_WAIT_MSEC (50)
+#define PGR_RECV_RETRY_CNT (1000)
+#define PGR_RECV_WAIT_MSEC (50)
+#define PGR_SEM_UNLOCK_WAIT_MSEC (100)
+#define PGR_SEM_LOCK_WAIT_MSEC (500)
+#define PGR_RECV_TIMEOUT	(10)
+#define PGR_SEND_TIMEOUT	(600)
+#define PGR_LOCK_WAIT_MSEC	(50)
+#define PGR_LOCK_TIMEOUT	(60)
+#define PGR_RECOVERY_RETRY_CNT	(60)
+#define PGR_RECOVERY_WAIT_MSEC	(50)
+
+#define PGR_RECOVERY_1ST_STAGE	(1)
+#define PGR_RECOVERY_2ND_STAGE	(2)
+
+#define IDLE_MODE	(0)
+#define BUSY_MODE	(1)
+
+/*
+ * connection table for transaction query
+ */
+typedef struct {
+	int useFlag;
+	unsigned short port;
+	unsigned short pid;
+	unsigned int hostIP;
+	unsigned int srcHostIP;
+	char host[HOSTNAME_MAX_LENGTH];
+	char srcHost[HOSTNAME_MAX_LENGTH];
+	char dbName[DBNAME_MAX_LENGTH];
+	char userName[USERNAME_MAX_LENGTH];
+	PGconn	* conn;
+	char * last;
+	char * next;
+}TransactionTbl;
+
+/*
+ * status table for recovery
+ */
+typedef struct {
+	int useFlag;
+	int transaction_count;
+	int recovery_status;
+	unsigned int replication_id;
+	HostTbl target_host;
+	int read_queue_no;
+	int write_queue_no;
+} RecoveryStatusInf;
+
+typedef struct {
+	FILE * queue_fp;
+	int current_queue_no;
+} RecoveryQueueInf;
+
+typedef struct {
+	long mtype;
+	char mdata[1];
+} MsgData;
+
+typedef struct {
+	unsigned int entry_ticket;
+	unsigned int lock_wait_queue_length;
+	int overflow;
+} LockWaitInf;
+
+typedef struct {
+	int response_mode;
+	int current_cluster;
+} ResponseInf;
+
+typedef struct {
+	ReplicateHeader * header;
+	char * query;
+	char * next;
+	char * last;
+} QueryLogType;
+
+typedef struct {
+	ReplicateServerInfo * top;
+	ReplicateServerInfo * end;
+	ReplicateServerInfo * lower;
+	ReplicateServerInfo * upper;
+	ReplicateServerInfo * myself;
+	int useFlag;
+} CascadeInf;
+
+typedef struct {
+	union 
+	{
+		int useFlag;
+		int commit_log_num;
+	} inf;
+	ReplicateHeader header;
+} CommitLogInf;
+
+typedef struct {
+	int useFlag;
+	char * RLog_Sock_Path;
+	uint16_t RLog_Port_Number;
+	int r_log_sock;
+	ReplicateHeader * header;
+	char * query;
+} ReplicationLogInf;
+
+typedef struct {
+	char hostName[HOSTNAME_MAX_LENGTH];
+	uint16_t port;
+	uint16_t pid;
+	uint32_t request_id;
+} QueryLogID; 
+
+typedef struct {
+	QueryLogID query_log_id;
+	char * last;
+	char * next;
+} ConfirmQueryList;
+
+typedef struct {
+	ReplicateHeader * header;
+	char * query;
+	int dest;
+	HostTbl * host_ptr;
+} ThreadArgInf;
+
+
+extern PGR_Com_Info Com_Info;
+
+/* replication server data */
+extern uint16_t Port_Number;
+extern uint16_t LifeCheck_Port_Number;
+extern uint16_t Recovery_Port_Number;
+extern int Reserved_Connections;
+
+/* global tables */
+extern HostTbl * Host_Tbl_Begin;
+extern TransactionTbl * Transaction_Tbl_Begin;
+extern TransactionTbl * Transaction_Tbl_End;
+extern TransactionTbl * PGconn_Tbl_Begin;
+extern TransactionTbl * PGconn_Tbl_End;
+extern RecoveryTbl * LoadBalanceTbl;
+extern RecoveryStatusInf * Recovery_Status_Inf;
+extern LockWaitInf * Lock_Wait_Tbl;
+extern ReplicateHeader * PGR_Log_Header;
+extern ReplicateServerInfo * Cascade_Tbl;
+extern CascadeInf * Cascade_Inf;
+extern CommitLogInf * Commit_Log_Tbl;
+extern QueryLogType * Query_Log_Top;
+extern QueryLogType * Query_Log_End;
+extern ReplicationLogInf * Replicateion_Log;
+/* IPC's id data */
+extern int RecoveryShmid;
+extern int RecoveryMsgid;
+extern int HostTblShmid;
+extern int LockWaitTblShmid;
+extern int LoadBalanceTblShmid;
+extern int CascadeTblShmid;
+extern int CascadeInfShmid;
+extern int CommitLogShmid;
+extern int QueryLogMsgid;
+extern int QueryLogAnsMsgid;
+extern int PGconnMsgid;
+extern int SemID;
+extern int RecoverySemID;
+
+extern int MaxBackends;
+extern char * PGR_Result;
+extern char * PGR_Data_Path;
+extern char * PGR_Write_Path;
+
+extern char * Function;
+
+extern int IS_SESSION_AUTHORIZATION;
+extern ResponseInf * PGR_Response_Inf;
+extern bool StartReplication[MAX_DB_SERVER];
+extern bool PGR_Cascade;
+extern bool	PGR_Use_Replication_Log;
+extern bool	PGR_AutoCommit;
+extern unsigned int * PGR_Send_Query_ID;
+extern unsigned int PGR_Query_ID;
+extern RecoveryQueueInf RecoveryQueue;
+
+/* smart shutdown */
+extern int Idle_Flag;
+extern bool Exit_Request;
+
+/*
+ * external prototype in main.c
+ */
+extern void PGRstop_pgreplicate(int sig);
+
+/*
+ * external prototype in conf.c
+ */
+extern int PGRset_Conf_Data(char * path);
+
+/*
+ * external prototype in replicate.c
+ */
+extern bool PGRis_same_host(char * host1, unsigned short port1 , char * host2, unsigned short port2);
+extern HostTbl * PGRadd_HostTbl(HostTbl *  conf_data, int useFlag);
+extern HostTbl * PGRget_master(void);
+extern void PGRset_recovery_status(int status);
+extern int PGRget_recovery_status(void);
+extern int PGRcheck_recovered_host(void);
+extern int PGRset_recovered_host(HostTbl * target,int useFlag);
+extern int PGRinit_recovery(void);
+extern void PGRreplicate_exit(int signal_arg);
+extern int PGRsend_replicate_packet_to_server( HostTbl * host_ptr, ReplicateHeader * header, char *query , char * result, int type);
+extern int PGRreplicate_packet_send_each_server( HostTbl * ptr, bool return_response, ReplicateHeader * header, char * query,int dest);
+extern HostTbl * PGRget_HostTbl(char * hostName,int port);
+extern int PGRset_queue(ReplicateHeader * header,char * query);
+extern int PGRset_host_status(HostTbl * host_ptr,int status);
+extern void PGRclear_transactions(void);
+extern void PGRclear_connections(int use_flag);
+extern int PGRset_replication_id(uint32_t id);
+extern int PGRdo_replicate(int sock,ReplicateHeader *header, char * query);
+extern int PGRreturn_result(int dest, int wait);
+extern int PGRreplicate_packet_send( ReplicateHeader * header, char * query,int dest);
+extern char * PGRread_packet(int sock, ReplicateHeader *header);
+extern void PGRnotice_replication_server(char * hostName, unsigned short portNumber,unsigned short recoveryPortNumber, unsigned short lifecheckPortNumber, char * userName);
+extern char * PGRread_query(int sock, ReplicateHeader *header);
+extern int PGRwait_transaction_count_clear(void);
+extern int PGRsync_oid(ReplicateHeader *header);
+extern unsigned int PGRget_next_query_id(void);
+extern int PGRget_pgconn_queue(void);
+
+/*
+ * external prototype in recovery.c
+ */
+extern int PGRsend_load_balance_packet(RecoveryPacket * packet);
+extern void PGRrecovery_main(void);
+extern FILE * PGRget_recovery_queue_file_for_write(void);
+extern FILE * PGRget_recovery_queue_file_for_read(int next);
+
+/*
+ * external prototype in rlog.c
+ */
+extern int PGRwrite_rlog(ReplicateHeader * header, char * query);
+extern ReplicateHeader * PGRget_requested_query(ReplicateHeader * header);
+extern void PGRreconfirm_commit(int sock, ReplicateHeader * header);
+extern void PGRset_rlog(ReplicateHeader * header, char * query);
+extern void PGRunset_rlog(ReplicateHeader * header, char * query);
+extern int PGRresend_rlog_to_db(void);
+extern void PGRreconfirm_query(int sock, ReplicateHeader * header);
+extern pid_t  PGR_RLog_Main(void);
+extern int PGRcreate_send_rlog_socket(void);
+extern int PGRsend_rlog_packet(int sock,ReplicateHeader * header, const char * query_string);
+extern int PGRrecv_rlog_result(int sock,void * result, int size);
+extern int PGRsend_rlog_to_local(ReplicateHeader * header,char * query);
+extern int PGRget_rlog_header(ReplicateHeader * header);
+
+/*
+ * external prototype in cascade.c
+ */
+extern int PGRstartup_cascade(void);
+extern int PGRsend_lower_cascade(ReplicateHeader * header, char * query);
+extern int PGRsend_upper_cascade(ReplicateHeader * header, char * query);
+extern int PGRwait_answer_cascade(int  sock);
+extern ReplicateServerInfo * PGRget_lower_cascade(void);
+extern ReplicateServerInfo * PGRget_upper_cascade(void);
+extern void PGRset_cascade_server_status(ReplicateServerInfo * cascade, int status);
+extern ReplicateServerInfo * PGRrecv_cascade_answer(ReplicateServerInfo * cascade,ReplicateHeader * header);
+extern int PGRsend_cascade(int sock , ReplicateHeader * header, char * query);
+extern int PGRcascade_main(int sock, ReplicateHeader * header, char * query);
+extern int PGRwait_notice_rlog_done(void);
+extern int PGRsend_notice_rlog_done(int sock);
+
+#endif /* PGREPLICATE_H */
diff -ruN postgresql-7.4.13-old/src/pgcluster/pgrp/recovery.c postgresql-7.4.13/src/pgcluster/pgrp/recovery.c
--- postgresql-7.4.13-old/src/pgcluster/pgrp/recovery.c	1970-01-01 01:00:00.000000000 +0100
+++ postgresql-7.4.13/src/pgcluster/pgrp/recovery.c	2006-08-05 16:53:43.000000000 +0200
@@ -0,0 +1,1098 @@
+/*--------------------------------------------------------------------
+ * FILE:
+ *     recovery.c
+ *
+ * NOTE:
+ *     This file is composed of the functions to call with the source
+ *     at pgreplicate for the recovery.
+ *
+ * Portions Copyright (c) 2003, Atsushi Mitani
+ *--------------------------------------------------------------------
+ */
+#ifdef USE_REPLICATION
+
+#include "postgres.h"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sys/wait.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <sys/msg.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <time.h>
+#include <arpa/inet.h>
+#include <sys/param.h>
+#include <sys/file.h>
+
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+
+#ifdef HAVE_CRYPT_H
+#include <crypt.h>
+#endif
+
+#include "miscadmin.h"
+#include "nodes/nodes.h"
+#include "libpq-fe.h"
+#include "libpq/libpq-fs.h"
+#include "libpq-int.h"
+#include "fe-auth.h"
+#include "access/xact.h"
+#include "replicate_com.h"
+#include "pgreplicate.h"
+
+
+#ifdef WIN32
+#include "win32.h"
+#else
+#ifdef HAVE_NETINET_TCP_H
+#include <netinet/tcp.h>
+#endif
+#include <arpa/inet.h>
+#endif
+
+#ifdef HAVE_CRYPT_H
+#include <crypt.h>
+#endif
+
+#ifdef MULTIBYTE
+#include "mb/pg_wchar.h"
+#endif
+
+
+/*--------------------------------------
+ * GLOBAL VARIABLE DECLARATION
+ *--------------------------------------
+ */
+RecoveryPacket MasterPacketData;
+RecoveryTbl Master;
+RecoveryTbl Target;
+
+
+/*--------------------------------------
+ * PROTOTYPE DECLARATION
+ *--------------------------------------
+ */
+static int read_packet(int sock,RecoveryPacket * packet);
+static int read_packet_from_master( RecoveryTbl * host, RecoveryPacket * packet );
+static int send_recovery_packet(int  sock, RecoveryPacket * packet);
+static int send_packet(RecoveryTbl * host, RecoveryPacket * packet );
+static void start_recovery_prepare(void);
+static void reset_recovery_prepare(void);
+static void start_recovery(void);
+static void finish_recovery(void);
+static bool first_setup_recovery(int * sock, RecoveryPacket * packet);
+static bool second_setup_recovery (RecoveryPacket * packet);
+static void pgrecovery_loop(int fd);
+static void show_recovery_packet(RecoveryPacket * packet);
+static int PGRsend_queue(RecoveryTbl * master, RecoveryTbl * target);
+static int send_vacuum(HostTbl *host, char * userName, int stage);
+static int send_recovery_queue( HostTbl * master_ptr, HostTbl * target_ptr, ReplicateHeader *header, char * query);
+static void clear_recovery_queue_file(void);
+
+int PGRsend_load_balance_packet(RecoveryPacket * packet);
+void PGRrecovery_main(void);
+FILE * PGRget_recovery_queue_file_for_write(void);
+FILE * PGRget_recovery_queue_file_for_read(int next);
+
+/*-----------------------------------------------------------
+ * SYMBOL
+ *    read_packet()
+ * NOTES
+ *    Read recovery packet data 
+ * ARGS
+ *    int sock : socket
+ *    RecoveryPacket * packet : read packet buffer
+ * RETURN
+ *    -1 : error
+ *    >0 : read size
+ *-----------------------------------------------------------
+ */
+static int
+read_packet(int sock,RecoveryPacket * packet)
+{
+	int r = 0;
+	int cnt = 0;
+	char * read_ptr = NULL;
+	int read_size = 0;
+	int packet_size = 0;
+
+	if (packet == NULL)
+	{
+		return -1;
+	}
+	read_ptr = (char*)packet;
+	packet_size = sizeof(RecoveryPacket);
+	for (;;)
+	{
+		r = recv(sock,read_ptr + read_size ,packet_size - read_size, MSG_WAITALL);
+		if (r < 0)
+		{
+			if (errno == EINTR)
+			{
+				usleep(PGR_RECV_WAIT_MSEC);
+				continue;
+			}
+#ifdef EAGAIN
+			if (errno == EAGAIN)
+			{
+				usleep(PGR_RECV_WAIT_MSEC);
+				continue;
+			}
+#endif /* EAGAIN */
+			if (cnt < PGR_RECV_RETRY_CNT )
+			{
+				cnt ++;
+				usleep(PGR_RECV_WAIT_MSEC);
+				continue;
+			}
+			else
+			{
+				return -1;
+			}
+		}
+		if (r > 0)
+		{
+			read_size += r;
+			if (read_size == PGR_MESSAGE_BUFSIZE)
+			{
+				show_recovery_packet(packet);
+				return read_size;
+			}
+		}
+		return -1;
+	}
+}
+
+static int
+read_packet_from_master( RecoveryTbl * host, RecoveryPacket * packet )
+{
+	int read_size = 0;
+	int rtn;
+	fd_set	  rmask;
+	struct timeval timeout;
+
+	timeout.tv_sec = PGR_RECV_TIMEOUT;
+	timeout.tv_usec = 0;
+
+	/*
+	 * Wait for something to happen.
+	 */
+	FD_ZERO(&rmask);
+	FD_SET(host->recovery_sock,&rmask);
+	for(;;)
+	{
+		rtn = select(host->recovery_sock+1, &rmask, (fd_set *)NULL, (fd_set *)NULL, &timeout);
+		if (rtn && FD_ISSET(host->recovery_sock, &rmask))
+		{
+			read_size = read_packet(host->recovery_sock, packet);
+			return read_size;
+		}
+	}
+}
+
+static int
+send_recovery_packet(int  sock, RecoveryPacket * packet)
+{
+	char * func = "send_recovery_packet()";
+	char * send_ptr;
+	int send_size= 0;
+	int buf_size = 0;
+	int s;
+	
+	errno = 0;
+	send_ptr = (char *)packet;
+	buf_size = sizeof(RecoveryPacket);
+
+	for (;;)
+	{
+		s = send(sock, send_ptr + send_size,buf_size - send_size ,0);
+		if (s < 0){
+			if (errno == EINTR)
+			{
+				continue;
+			}
+			show_error("%s:send() failed. (%s)",func,strerror(errno));
+			return STATUS_ERROR;
+		}
+		if (s == 0)
+		{
+			return STATUS_OK;
+		}
+		send_size += s;
+	}
+}
+
+static int
+send_packet(RecoveryTbl * host, RecoveryPacket * packet )
+{
+	char * func = "send_packet()";
+	int count = 0;
+
+	if (host->recovery_sock == -1)
+	{
+		while(PGR_Create_Socket_Connect(&(host->recovery_sock), host->hostName , host->recoveryPort) != STATUS_OK )
+		{
+			if (count > MAX_RETRY_TIMES )
+			{
+				show_error("%s:PGR_Create_Socket_Connect failed",func);
+				return STATUS_ERROR;
+			}
+			count ++;
+		}
+	}
+	count = 0;
+	while (send_recovery_packet(host->recovery_sock,packet) != STATUS_OK)
+	{
+		close(host->recovery_sock);
+		host->recovery_sock = -1;
+		PGR_Create_Socket_Connect(&(host->recovery_sock), host->hostName , host->recoveryPort);
+		if (count > PGR_CONNECT_RETRY_TIME )
+		{
+
+			show_error("%s:send failed and PGR_Create_Socket_Connect failed",func);
+			return STATUS_ERROR;
+		}
+		count ++;
+	}
+	return STATUS_OK;
+}
+
+static void
+start_recovery_prepare(void)
+{
+	PGRset_recovery_status (RECOVERY_PREPARE_START);	
+}
+
+static void
+reset_recovery_prepare(void)
+{
+	PGRset_recovery_status (RECOVERY_INIT);
+}
+
+static void
+start_recovery(void)
+{
+	PGRset_recovery_status (RECOVERY_START);
+}
+
+static void
+finish_recovery(void)
+{
+	PGRset_recovery_status (RECOVERY_INIT);
+}
+
+int
+PGRsend_load_balance_packet(RecoveryPacket * packet)
+{
+	char * func = "PGRsend_load_balance_packet()";
+	RecoveryTbl * lbp;
+	int status;
+
+	lbp = LoadBalanceTbl;
+	if (lbp == (RecoveryTbl *)NULL)
+	{
+		show_error("%s:recovery table is NULL",func);
+		return STATUS_ERROR;
+	}
+	while (lbp->hostName[0] != 0)
+	{
+		status = send_packet(lbp,packet);
+		if (lbp->recovery_sock != -1)
+		{
+			close(lbp->recovery_sock);
+			lbp->recovery_sock = -1;
+		}
+		lbp ++;
+	}
+	return STATUS_OK;
+}
+
+static int
+send_vacuum(HostTbl *host, char * userName, int stage)
+{
+	int rtn = STATUS_OK;
+	ReplicateHeader header;
+	char * query = NULL;
+
+	if (stage == PGR_RECOVERY_1ST_STAGE)
+	{
+		query = strdup("VACUUM");
+	}
+	else
+	{
+		query = strdup("VACUUM FULL");
+	}
+	memset(&header,0,sizeof(header));
+	header.query_size = strlen(query) + 1;
+	strncpy(header.dbName,"template1",sizeof(header.dbName));
+	strncpy(header.userName,userName,sizeof(header.userName));
+	header.cmdSys = CMD_SYS_REPLICATE;
+	header.cmdSts = CMD_STS_QUERY;
+	header.cmdType = CMD_TYPE_VACUUM;
+	header.pid = getpid();
+	header.query_id = getpid();
+	rtn = PGRsend_replicate_packet_to_server(host,&header,query,PGR_Result, RECOVERY_QUERY_TYPE);
+	if (query !=NULL)
+		free(query);
+	return rtn;	
+}
+
+static bool
+first_setup_recovery(int * sock, RecoveryPacket * packet)
+{
+	char * func = "first_setup_recovery()";
+	int status;
+	HostTbl * master = (HostTbl *)NULL;
+	bool loop_end = false;
+	HostTbl host_tbl;
+	char * userName = NULL;
+
+	strncpy(Target.hostName,packet->hostName,sizeof(Target.hostName));
+	Target.port = ntohs(packet->port);
+	Target.recoveryPort = ntohs(packet->recoveryPort);
+	Target.sock = *sock;
+	Target.recovery_sock = *sock;
+#ifdef PRINT_DEBUG
+	show_debug("%s:1st setup target %s",func,Target.hostName);
+	show_debug("%s:1st setup port %d",func,Target.port);
+#endif			
+	/*
+	 * check another recovery process 
+	 */
+	if (PGRget_recovery_status() != RECOVERY_INIT)
+	{
+		/*
+		 * recovery process is already running
+		 */
+		show_error("%s:already recovery job runing",func);
+		memset(packet,0,sizeof(packet));
+		PGRset_recovery_packet_no(packet, RECOVERY_ERROR_OCCUPIED) ;
+		status = send_packet(&Target,packet);
+		loop_end = true;
+		return loop_end;
+	}
+	/*
+	 * add recovery target to host table
+	 */
+	strncpy(host_tbl.hostName,packet->hostName,sizeof(host_tbl.hostName));
+	host_tbl.port = ntohs(packet->port);
+	PGRset_recovered_host(&host_tbl,DATA_INIT);
+	PGRadd_HostTbl(&host_tbl,DATA_INIT);
+	/*
+	 * send prepare recovery to load balancer
+	 */
+	PGRsend_load_balance_packet(packet);
+	userName = strdup(packet->userName);
+
+	/*
+	 * set RECOVERY_PGDATA_REQ packet data
+	 */
+	memset(packet,0,sizeof(RecoveryPacket));
+	PGRset_recovery_packet_no(packet, RECOVERY_PGDATA_REQ );
+
+retry_connect_master:
+	master = PGRget_master();
+	if (master == (HostTbl *)NULL)
+	{
+		/*
+		 * connection error , master may be down
+		 */
+		show_error("%s:get master info error , master may be down",func);
+		PGRset_recovery_packet_no(packet, RECOVERY_ERROR_CONNECTION);
+		status = send_packet(&Target, packet);
+		reset_recovery_prepare();
+		loop_end = true;
+		if (userName != NULL)
+		{
+			free(userName);
+		}
+		return loop_end;
+	}
+	/* send vauum command to master server */
+	status = send_vacuum(master, userName, PGR_RECOVERY_1ST_STAGE );
+	if (status != STATUS_OK)
+	{
+		show_error("%s:vacuum error , master may be down",func);
+		PGRset_recovery_packet_no(packet, RECOVERY_ERROR_CONNECTION);
+		status = send_packet(&Target, packet);
+		reset_recovery_prepare();
+		loop_end = true;
+		if (userName != NULL)
+		{
+			free(userName);
+		}
+		return loop_end;
+	}
+
+	strncpy(Master.hostName,master->hostName,sizeof(Master.hostName));
+	Master.sock = -1;
+	Master.recovery_sock = -1;
+	Master.port = master->port;
+	Master.recoveryPort = master->recoveryPort;
+	status = send_packet(&Master, packet);
+	if (status != STATUS_OK)
+	{
+		/*
+		 * connection error , master may be down
+		 */
+		show_error("%s:connection error , master may be down",func);
+		PGRset_host_status(master,DATA_ERR);
+		goto retry_connect_master ;
+	}
+	
+	/*
+	 * start prepare of recovery
+	 *     set recovery status to "prepare start"
+	 *     start transaction count up
+	 */
+	start_recovery_prepare();
+	/*
+	 * wait answer from master server 
+	 */
+	memset(packet,0,sizeof(RecoveryPacket));
+	read_packet_from_master(&Master, packet);
+	if (ntohs(packet->packet_no) == RECOVERY_PGDATA_ANS)
+	{
+		/*
+		 * send a packet to load balancer that is stopped master's 
+		 * load balancing until all recovery process is finished
+		 */
+		PGRsend_load_balance_packet(packet);
+		memcpy((char *)&MasterPacketData,packet,sizeof(RecoveryPacket));
+
+		/*
+		 * prepare answer from master DB
+		 */
+		PGRset_recovery_packet_no(packet, RECOVERY_PREPARE_ANS );
+		strncpy(packet->hostName,Master.hostName,sizeof(packet->hostName));
+		status = send_packet(&Target, packet);
+		if (status != STATUS_OK)
+		{
+			PGRset_recovery_packet_no(packet, RECOVERY_ERROR_CONNECTION);
+			status = send_packet(&Master,packet);
+			reset_recovery_prepare();
+			loop_end = true;
+		}
+	}
+	if (userName != NULL)
+		free(userName);
+	return loop_end;
+}
+
+static bool
+second_setup_recovery (RecoveryPacket * packet)
+{
+	char * func = "second_setup_recovery()";
+	HostTbl * master = (HostTbl *)NULL;
+	int status;
+	bool loop_end = false;
+	char * userName = NULL;
+
+	start_recovery();
+	/*
+	 * wait until all started transactions are going to finish
+	 */
+	status = PGRwait_transaction_count_clear();
+	if (status != STATUS_OK)
+	{
+		show_error("%s:transaction is too busy, please try again after",func);
+		PGRset_recovery_packet_no(packet, RECOVERY_ERROR_CONNECTION);
+		status = send_packet(&Target,packet);
+		status = send_packet(&Master,packet);
+		reset_recovery_prepare();
+		loop_end = true;
+		return loop_end;
+	}
+
+	/* send vauum command to master server */
+	master = PGRget_master();
+	userName = strdup(packet->userName);
+	status = send_vacuum(master, userName, PGR_RECOVERY_2ND_STAGE );
+	if (status != STATUS_OK)
+	{
+		show_error("%s:vacuum error , master may be down",func);
+		PGRset_recovery_packet_no(packet, RECOVERY_ERROR_CONNECTION);
+		status = send_packet(&Target,packet);
+		status = send_packet(&Master,packet);
+		reset_recovery_prepare();
+		loop_end = true;
+		if (userName != NULL)
+			free(userName);
+		return loop_end;
+	}
+
+	/*
+	 * then, send fsync request to master DB
+	 */
+	PGRset_recovery_packet_no(packet, RECOVERY_FSYNC_REQ );
+	status = send_packet(&Master,packet);
+	if (status != STATUS_OK)
+	{
+		/*
+		 * connection error , master may be down
+		 */
+		show_error("%s:connection error , master may be down",func);
+		PGRset_recovery_packet_no(packet, RECOVERY_ERROR_CONNECTION);
+		status = send_packet(&Target,packet);
+		status = send_packet(&Master,packet);
+		reset_recovery_prepare();
+		loop_end = true;
+		if (userName != NULL)
+			free(userName);
+		return loop_end;
+	}
+	/*
+	 * wait answer from master server 
+	 */
+	memset(packet,0,sizeof(RecoveryPacket));
+	read_packet_from_master(&Master,packet);
+	if (ntohs(packet->packet_no) == RECOVERY_FSYNC_ANS )
+	{
+		/*
+		 * master DB finished fsync
+		 */
+		PGRset_recovery_packet_no(packet, RECOVERY_START_ANS );
+		strncpy(packet->hostName,Master.hostName,sizeof(packet->hostName));
+		status = send_packet(&Target,packet);
+		if (status != STATUS_OK)
+		{
+			finish_recovery();
+		}
+		loop_end = true;
+	}
+	else
+	{
+		show_error("%s:failer answer returned",func);
+		PGRset_recovery_packet_no(packet, RECOVERY_ERROR_CONNECTION);
+		status = send_packet(&Target,packet);
+		status = send_packet(&Master,packet);
+		reset_recovery_prepare();
+		loop_end = true;
+	}
+	if (userName != NULL)
+		free(userName);
+	return loop_end;
+}
+
+static int
+PGRsend_queue(RecoveryTbl * master, RecoveryTbl * target)
+{
+	char * func = "PGRsend_queue()";
+	HostTbl * master_ptr = NULL;
+	HostTbl * target_ptr = NULL;
+	ReplicateHeader header;
+	char * query = NULL;
+	int status = 0;
+	int query_size = 0;
+	int alloc_size = 0;
+	int read_lock;
+
+	if (RecoverySemID == 0)
+	{
+		show_error("%s:initial setup should be failed",func);
+		return STATUS_ERROR;
+	}
+	if (master == (RecoveryTbl *)NULL)
+	{
+		show_error("%s:there is no master ",func);
+		return STATUS_ERROR;
+	}
+#ifdef PRINT_DEBUG
+	show_debug("%s:master %s - %d\n",func,master->hostName,master->port);
+#endif			
+	master_ptr = PGRget_HostTbl(master->hostName,master->port);
+	if (master_ptr == (HostTbl *)NULL)
+	{
+		show_error("%s:master table is null",func);
+		return STATUS_ERROR;
+	}
+	if (target != (RecoveryTbl *)NULL)
+	{
+#ifdef PRINT_DEBUG
+		show_debug("%s:target %s - %d",func,target->hostName,target->port);
+#endif			
+		target_ptr = PGRget_HostTbl(target->hostName,target->port);
+		if (target_ptr == (HostTbl *)NULL)
+		{
+			show_error("%s:target table is null",func);
+			return STATUS_ERROR;
+		}
+	}
+	RecoveryQueue.queue_fp = PGRget_recovery_queue_file_for_read(0);
+	if (RecoveryQueue.queue_fp == NULL)
+	{
+		return STATUS_OK;
+	}
+	clearerr(RecoveryQueue.queue_fp);
+	fseek(RecoveryQueue.queue_fp,0,SEEK_SET);
+	status = STATUS_OK;
+	read_lock = 0;
+	while (RecoveryQueue.queue_fp != NULL)
+	{
+		if(feof(RecoveryQueue.queue_fp) != 0)
+		{
+			RecoveryQueue.queue_fp = PGRget_recovery_queue_file_for_read(1);
+			if (RecoveryQueue.queue_fp == NULL)
+			{
+				clear_recovery_queue_file();
+				break;
+			}
+			else
+			{
+				clearerr(RecoveryQueue.queue_fp);
+				fseek(RecoveryQueue.queue_fp,0,SEEK_SET);
+			}
+		}
+		if (!read_lock)
+		{
+			read_lock = 1;
+			PGRsem_lock(RecoverySemID, SEM_NUM_OF_RECOVERY_QUEUE);
+		}
+		if (fread(&header,sizeof(ReplicateHeader),1,RecoveryQueue.queue_fp) >0)
+		{
+			query_size = ntohl(header.query_size);
+			if (query_size < 0)
+			{
+				continue;
+			}
+			else if (query_size > 0)
+			{
+				if (alloc_size < query_size +4)
+				{
+					if (alloc_size == 0)
+					{
+						query = (char *)malloc(query_size+4);
+					}
+					else
+					{
+						query = (char*)realloc(query,query_size+4);
+					}
+					if (query == (char*)NULL)
+					{
+						show_error("%s:malloc orrealloc faild: (%s)",func,strerror(errno));
+						PGRsem_unlock(RecoverySemID, SEM_NUM_OF_RECOVERY_QUEUE);
+						return STATUS_ERROR;
+					}
+				}
+				memset(query,0,query_size+4);
+				if (fread(query,query_size,1, RecoveryQueue.queue_fp) >0)
+				{
+					read_lock = 0;
+					PGRsem_unlock(RecoverySemID, SEM_NUM_OF_RECOVERY_QUEUE);
+					status = send_recovery_queue(master_ptr,target_ptr, &header, query);
+				}
+			}
+		}
+		if (read_lock)
+		{
+			read_lock = 0;
+			PGRsem_unlock(RecoverySemID, SEM_NUM_OF_RECOVERY_QUEUE);
+		}
+		if (ferror(RecoveryQueue.queue_fp) != 0)
+		{
+			status = STATUS_ERROR;
+			break;
+		}
+	}
+	if (query != NULL)
+	{
+		free(query);
+	}
+	if (read_lock)
+	{
+		read_lock = 0;
+		PGRsem_unlock(RecoverySemID, SEM_NUM_OF_RECOVERY_QUEUE);
+	}
+	return status;
+}
+
+static int
+send_recovery_queue( HostTbl * master_ptr, HostTbl * target_ptr, ReplicateHeader *header, char * query)
+{
+	char * func = "send_recovery_queue()";
+
+	if (PGRsend_replicate_packet_to_server(master_ptr,header,query,PGR_Result, RECOVERY_QUERY_TYPE) != STATUS_OK)
+	{
+		show_error("%s:PGRsend_replicate_packet_to_server to master error",func);
+		return STATUS_ERROR;
+	}
+	if (target_ptr != NULL)
+	{
+		if (PGRsend_replicate_packet_to_server(target_ptr,header,query,PGR_Result, RECOVERY_QUERY_TYPE) != STATUS_OK)
+		{
+			show_error("%s:PGRsend_replicate_packet_to_server to target error",func);
+			return STATUS_ERROR;
+		}
+	}
+	return STATUS_OK;
+}
+
+static void
+pgrecovery_loop(int fd)
+{
+	char * func = "pgrecovery_loop()";
+	int count;
+	int sock;
+	int status;
+	bool loop_end = false;
+	RecoveryPacket packet;
+	HostTbl new_host;
+
+	count = 0;
+	while ((status = PGR_Create_Acception(fd,&sock,"",Recovery_Port_Number)) != STATUS_OK)
+	{
+		show_error("%s:PGR_Create_Acception failed",func);
+		PGR_Close_Sock(&sock);
+		sock = -1;
+		if ( count > PGR_CONNECT_RETRY_TIME)
+		{
+			return;
+		}
+		count ++;
+	}
+	for(;;)
+	{
+		int read_size = 0;
+		int rtn;
+		fd_set	  rmask;
+		struct timeval timeout;
+
+		timeout.tv_sec = RECOVERY_TIMEOUT;
+		timeout.tv_usec = 0;
+
+		/*
+		 * Wait for something to happen.
+		 */
+		FD_ZERO(&rmask);
+		FD_SET(sock,&rmask);
+		/*
+		 * read packet from target cluster server
+		 */
+		rtn = select(sock+1, &rmask, (fd_set *)NULL, (fd_set *)NULL, &timeout);
+		if (rtn && FD_ISSET(sock, &rmask))
+		{
+			read_size = read_packet(sock, &packet);
+		}
+		else
+		{
+			continue;
+		}
+
+#ifdef PRINT_DEBUG
+		show_debug("%s:receive packet no:%d",func,ntohs(packet.packet_no));
+#endif			
+
+		switch (ntohs(packet.packet_no))
+		{
+			case RECOVERY_PREPARE_REQ :
+				/*
+				 * start prepare of recovery
+				 */
+				loop_end = first_setup_recovery(&sock, &packet);
+#ifdef PRINT_DEBUG
+				show_debug("%s:1st master %s - %d",
+					func,Master.hostName,Master.port);
+				show_debug("%s:1st target %s - %d",
+					func,Target.hostName,Target.port);
+#endif			
+				break;
+			case RECOVERY_START_REQ : 
+				/*
+				 * now, recovery process will start
+				 *    stop the transaction count up
+				 *    start queueing and stop send all queries for master DB
+				 */
+				loop_end = second_setup_recovery (&packet);
+#ifdef PRINT_DEBUG
+				show_debug("%s:2nd master %s - %d",
+					func,Master.hostName,Master.port);
+				show_debug("%s:2nd target %s - %d",
+					func,Target.hostName,Target.port);
+				show_debug("%s:second_setup_recovery end :%d ",
+					func,loop_end);
+#endif			
+				break;
+			case RECOVERY_FINISH : 
+				/*
+				 * finished rsync DB datas from master to target 
+				 */
+				/*
+				 * send all queries in queue
+				 */
+#ifdef PRINT_DEBUG
+				show_debug("%s:last master %s - %d",
+					func,Master.hostName,Master.port);
+				show_debug("%s:last target %s - %d",
+					func,Target.hostName,Target.port);
+#endif			
+				status = PGRsend_queue(&Master,&Target);
+				if (status == STATUS_OK)
+				{
+#ifdef PRINT_DEBUG
+					show_debug("%s:PGRsend_queue ok",func);
+#endif			
+					strncpy(new_host.hostName,Target.hostName,sizeof(new_host.hostName));
+					new_host.port = Target.port;
+					new_host.recoveryPort = Target.recoveryPort;
+					PGRset_recovered_host(&new_host,DATA_USE);
+					PGRadd_HostTbl(&new_host,DATA_USE);
+				}
+				else
+				{
+					/* connection error , master or target may be down */
+					show_error("%s:PGRsend_queue failed",func);
+					PGRset_recovery_packet_no(&packet, RECOVERY_ERROR_CONNECTION);
+					status = send_packet(&Target,&packet);
+				}
+				/*
+				 * stop queueing, and initiarise recovery status
+				 */
+				finish_recovery();
+				loop_end = true;
+				/*
+				 * send finish recovery to load balancer
+				 */
+				send_packet(&Master, &packet);
+				MasterPacketData.packet_no = packet.packet_no;
+				PGRsend_load_balance_packet(&MasterPacketData);
+				PGRsend_load_balance_packet(&packet);
+				memset((char *)&MasterPacketData,0,sizeof(RecoveryPacket));
+				break;
+			case RECOVERY_ERROR_ANS : 
+#ifdef PRINT_DEBUG
+				show_debug("%s:recovery error accept. top queueing and initiarse recovery status",func);
+#endif			
+				status = PGRsend_queue(&Master,NULL);
+				memset(&packet,0,sizeof(RecoveryPacket));
+				PGRset_recovery_packet_no(&packet, RECOVERY_ERROR_ANS);
+				send_packet(&Master, &packet);
+				finish_recovery();
+				loop_end = true;
+				PGRset_recovery_packet_no(&MasterPacketData, RECOVERY_FINISH );
+				PGRsend_load_balance_packet(&MasterPacketData);
+				memset((char *)&MasterPacketData,0,sizeof(RecoveryPacket));
+				break;
+		}
+		if (loop_end)
+		{
+			if (Master.sock != -1)
+			{
+				close (Master.sock);
+				Master.sock = -1;
+			}
+			if (Master.recovery_sock != -1)
+			{
+				close (Master.recovery_sock);
+				Master.recovery_sock = -1;
+			}
+			close(sock);
+			sock = -1;
+			return;
+		}
+	}
+}
+
+void
+PGRrecovery_main(void)
+{
+	char * func = "PGRrecovery_main()";
+	int status;
+	int fd = -1;
+	int rtn;
+
+	status = PGR_Create_Socket_Bind(&fd, "", Recovery_Port_Number);
+	if (status != STATUS_OK)
+	{
+		show_error("%s:PGR_Create_Socket_Bind failed",func);
+		exit(1);
+	}
+	memset(&MasterPacketData,0,sizeof(RecoveryPacket));
+	memset(&Master,0,sizeof(RecoveryTbl));
+	memset(&Target,0,sizeof(RecoveryTbl));
+	for (;;)
+	{
+		fd_set	  rmask;
+		struct timeval timeout;
+
+		Idle_Flag = IDLE_MODE;
+		if (Exit_Request)
+		{
+			exit(0);
+		}
+
+		timeout.tv_sec = RECOVERY_TIMEOUT;
+		timeout.tv_usec = 0;
+
+		/*
+		 * Wait for something to happen.
+		 */
+		FD_ZERO(&rmask);
+		FD_SET(fd,&rmask);
+		rtn = select(fd+1, &rmask, (fd_set *)NULL, (fd_set *)NULL, &timeout);
+		if (rtn && FD_ISSET(fd, &rmask))
+		{
+			Idle_Flag = BUSY_MODE;
+			pgrecovery_loop(fd);
+		}
+	}
+}
+
+static void
+show_recovery_packet(RecoveryPacket * packet)
+{
+	char * func = "show_recovery_packet()";
+
+#ifdef PRINT_DEBUG
+	show_debug("%s:no = %d",func,ntohs(packet->packet_no));
+	show_debug("%s:max_connect = %d",func,ntohs(packet->max_connect));
+	show_debug("%s:port = %d",func,ntohs(packet->port));
+	show_debug("%s:recoveryPort = %d",func,ntohs(packet->recoveryPort));
+	if (packet->hostName != NULL)
+		show_debug("%s:hostName = %s",func,packet->hostName);
+	if (packet->pg_data != NULL)
+		show_debug("%s:pg_data = %s",func,packet->pg_data);
+#endif			
+}
+
+FILE *
+PGRget_recovery_queue_file_for_write(void)
+{
+	char * func = "PGRget_recovery_queue_file_for_write()";
+	int write_queue_no = 0;
+	int read_queue_no = 0;
+	char fname[256];
+
+	PGRsem_lock(RecoverySemID, SEM_NUM_OF_RECOVERY_QUEUE);
+	/*
+	 * open recovery queue file
+	 */
+	write_queue_no = Recovery_Status_Inf->write_queue_no;
+	read_queue_no = Recovery_Status_Inf->read_queue_no;
+	if (write_queue_no == read_queue_no)
+	{
+		if (RecoveryQueue.queue_fp != (FILE *)NULL)
+		{
+			fflush(RecoveryQueue.queue_fp);
+			fclose(RecoveryQueue.queue_fp);
+			RecoveryQueue.queue_fp = (FILE *)NULL;
+		}
+		write_queue_no ++;
+		Recovery_Status_Inf->write_queue_no = write_queue_no;
+	}
+	if (write_queue_no != RecoveryQueue.current_queue_no)
+	{
+		if (RecoveryQueue.queue_fp != (FILE *)NULL)
+		{
+			fflush(RecoveryQueue.queue_fp);
+			fclose(RecoveryQueue.queue_fp);
+			RecoveryQueue.queue_fp = (FILE *)NULL;
+		}
+		RecoveryQueue.current_queue_no = write_queue_no;
+	}
+	if (RecoveryQueue.queue_fp == (FILE *)NULL)
+	{
+		snprintf(fname, sizeof(fname), "%s/%s%d", PGR_Write_Path, RECOVERY_QUEUE_FILE,write_queue_no);
+		RecoveryQueue.queue_fp = fopen(fname, "w+");
+		if (!RecoveryQueue.queue_fp)
+		{
+			show_error("%s:could not open recovery queue file as %s. reason: %s",
+					   func,fname, strerror(errno));
+			PGRsem_unlock(RecoverySemID, SEM_NUM_OF_RECOVERY_QUEUE);
+			return (FILE*)NULL;
+		}
+	}
+	PGRsem_unlock(RecoverySemID, SEM_NUM_OF_RECOVERY_QUEUE);
+
+	return RecoveryQueue.queue_fp;
+}
+
+FILE *
+PGRget_recovery_queue_file_for_read(int next)
+{
+	char * func = "PGRget_recovery_queue_file_for_read()";
+	int write_queue_no = 0;
+	int read_queue_no = 0;
+	char fname[256];
+
+	PGRsem_lock(RecoverySemID, SEM_NUM_OF_RECOVERY_QUEUE);
+	/*
+	 * open recovery queue file
+	 */
+	read_queue_no = Recovery_Status_Inf->read_queue_no;
+	if (read_queue_no == 0)
+	{
+		read_queue_no ++;
+		Recovery_Status_Inf->read_queue_no = read_queue_no;
+	}
+	if (next)
+	{
+		if (read_queue_no < write_queue_no)
+		{
+			if (RecoveryQueue.queue_fp != NULL)
+			{
+				fflush(RecoveryQueue.queue_fp);
+				fclose(RecoveryQueue.queue_fp);
+				snprintf(fname, sizeof(fname), "%s/%s%d", PGR_Write_Path, RECOVERY_QUEUE_FILE,read_queue_no);
+				unlink(fname);
+				RecoveryQueue.queue_fp = NULL;
+			}
+			read_queue_no ++;
+			Recovery_Status_Inf->read_queue_no = read_queue_no;
+		}
+	}
+
+	if (RecoveryQueue.queue_fp == NULL)
+	{
+		snprintf(fname, sizeof(fname), "%s/%s%d", PGR_Write_Path, RECOVERY_QUEUE_FILE,read_queue_no);
+		RecoveryQueue.queue_fp = fopen(fname, "r");
+		if (!RecoveryQueue.queue_fp)
+		{
+			show_error("%s:could not open recovery queue file as %s. reason: %s",
+					   func,fname, strerror(errno));
+			PGRsem_unlock(RecoverySemID, SEM_NUM_OF_RECOVERY_QUEUE);
+			return (FILE*)NULL;
+		}
+	}
+	PGRsem_unlock(RecoverySemID, SEM_NUM_OF_RECOVERY_QUEUE);
+
+	return RecoveryQueue.queue_fp;
+}
+
+static void
+clear_recovery_queue_file(void)
+{
+	int write_queue_no = 0;
+	int read_queue_no = 0;
+	char fname[256];
+
+	PGRsem_lock(RecoverySemID, SEM_NUM_OF_RECOVERY_QUEUE);
+	write_queue_no = Recovery_Status_Inf->write_queue_no;
+	read_queue_no = Recovery_Status_Inf->read_queue_no;
+	if (write_queue_no != read_queue_no)
+	{
+		PGRsem_unlock(RecoverySemID, SEM_NUM_OF_RECOVERY_QUEUE);
+		return;
+	}
+	if (RecoveryQueue.queue_fp != NULL)
+	{
+		fflush(RecoveryQueue.queue_fp);
+		fclose(RecoveryQueue.queue_fp);
+		RecoveryQueue.queue_fp = (FILE *)NULL;
+	}
+	RecoveryQueue.current_queue_no = 0;
+	snprintf(fname, sizeof(fname), "%s/%s%d", PGR_Write_Path, RECOVERY_QUEUE_FILE,read_queue_no);
+	unlink(fname);
+	PGRsem_unlock(RecoverySemID, SEM_NUM_OF_RECOVERY_QUEUE);
+}
+
+#endif /* USE_REPLICATION */
diff -ruN postgresql-7.4.13-old/src/pgcluster/pgrp/replicate.c postgresql-7.4.13/src/pgcluster/pgrp/replicate.c
--- postgresql-7.4.13-old/src/pgcluster/pgrp/replicate.c	1970-01-01 01:00:00.000000000 +0100
+++ postgresql-7.4.13/src/pgcluster/pgrp/replicate.c	2006-08-05 16:53:43.000000000 +0200
@@ -0,0 +1,3548 @@
+/*--------------------------------------------------------------------
+ * FILE:
+ *     replicate.c
+ *
+ * NOTE:
+ *     This file is composed of the functions to call with the source
+ *     at pgreplicate for the replication.
+ *
+ * Portions Copyright (c) 2003-2004, Atsushi Mitani
+ *--------------------------------------------------------------------
+ */
+#ifdef USE_REPLICATION
+
+#include "postgres.h"
+#include "postgres_fe.h"
+
+#include <pthread.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <ctype.h>
+#include <time.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <sys/sem.h>
+#include <sys/msg.h>
+#include <signal.h>
+
+#include "libpq-fe.h"
+#include "libpq-int.h"
+#include "fe-auth.h"
+
+#include <sys/socket.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <arpa/inet.h>
+
+#ifdef HAVE_NETINET_TCP_H
+#include <netinet/tcp.h>
+#endif
+
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+
+#ifdef HAVE_CRYPT_H
+#include <crypt.h>
+#endif
+
+#ifdef MULTIBYTE
+#include "mb/pg_wchar.h"
+#endif
+#include "access/xact.h"
+#include "replicate_com.h"
+#include "pgreplicate.h"
+
+#define IPC_NMAXSEM (32)
+
+/*--------------------------------------
+ * PROTOTYPE DECLARATION
+ *--------------------------------------
+ */
+static PGconn * pgr_createConn( char * host, char * port,char * database, char * userName );
+static TransactionTbl * setTransactionTbl(HostTbl * host_ptr, ReplicateHeader * header);
+static TransactionTbl * insertTransactionTbl( HostTbl * host_ptr, TransactionTbl * datap);
+static TransactionTbl * getTransactionTbl( HostTbl * host_ptr, ReplicateHeader * header);
+static void deleteTransactionTbl(HostTbl * host_ptr,ReplicateHeader * header);
+static TransactionTbl * setPGconnTbl(HostTbl * host_ptr, ReplicateHeader * header, int use_flag);
+static TransactionTbl * insertPGconnTbl( HostTbl * host_ptr, TransactionTbl * datap);
+static TransactionTbl * getPGconnTbl( HostTbl * host_ptr, ReplicateHeader * header);
+static void deletePGconnTbl(HostTbl * host_ptr,ReplicateHeader * header);
+static HostTbl * deleteHostTbl(HostTbl * ptr);
+static bool is_master_in_recovery(char * host, int port);
+static void sem_quit(int semid);
+static int send_cluster_status_to_load_balance(HostTbl * host_ptr,int status);
+static void end_transaction_status(int recovery_status);
+static void set_transaction_status(int status);
+static void begin_transaction_status(int recovery_status);
+static void check_transaction_status(ReplicateHeader * header,int recovery_status);
+static void clearHostTbl(void);
+static bool is_need_sync_time(ReplicateHeader * header);
+static bool is_need_wait_answer(ReplicateHeader * header);
+static void write_host_status_file(HostTbl * host_ptr);
+static void delete_template(HostTbl * ptr, ReplicateHeader * header);
+static char * check_copy_command(char * query);
+static int read_answer(int dest);
+static int next_replication_id(void);
+static bool is_need_use_rlog(ReplicateHeader * header);
+static bool is_autocommit_off(char * query);
+static bool is_autocommit_on(char * query);
+static unsigned int get_host_ip_from_tbl(char * host);
+static unsigned int get_srcHost_ip_from_tbl(char * srcHost);
+static int check_delete_transaction (HostTbl * host_ptr, ReplicateHeader * header);
+static int send_func(HostTbl * host_ptr,ReplicateHeader * header, char * func,char * result);
+static uint32_t get_oid(HostTbl * host_ptr,ReplicateHeader * header);
+static int set_oid(HostTbl * host_ptr,ReplicateHeader * header, uint32_t oid);
+static int replicate_lo( PGconn * conn, char cmdType, LOArgs * query);
+static bool is_executed_query_in_origin( ReplicateHeader *header );
+static bool is_executed_query( PGconn *conn, ReplicateHeader * header);
+static int send_sync_data(PGconn *conn, ReplicateHeader * header, bool sync_command_flg, int current_cluster);
+static int replicate_query(PGresult * res, PGconn * conn, HostTbl * host_ptr, ReplicateHeader * header, char *query, bool sync_command_flg, int current_cluster);
+static TransactionTbl * get_conn( HostTbl * host_ptr, ReplicateHeader * header);
+static TransactionTbl * recreate_conn( HostTbl* host_ptr, ReplicateHeader* header);
+static void * thread_send_source(void * arg);
+static void * thread_send_cluster(void * arg);
+static int set_pgconn_queue(ReplicateHeader * header);
+
+bool PGRis_same_host(char * host1, unsigned short port1 , char * host2, unsigned short port2);
+HostTbl * PGRadd_HostTbl(HostTbl *  conf_data, int useFlag);
+HostTbl * PGRget_master(void);
+void PGRset_recovery_status(int status);
+int PGRget_recovery_status(void);
+int PGRcheck_recovered_host(void);
+int PGRset_recovered_host(HostTbl * target,int useFlag);
+int PGRinit_recovery(void);
+void PGRreplicate_exit(int signal_arg);
+int PGRsend_replicate_packet_to_server( HostTbl * host_ptr, ReplicateHeader * header, char *query , char * result, int type);
+int PGRreplicate_packet_send_each_server( HostTbl * ptr, bool return_response, ReplicateHeader * header, char * query,int dest);
+HostTbl * PGRget_HostTbl(char * hostName,int port);
+int PGRset_queue(ReplicateHeader * header,char * query);
+int PGRset_host_status(HostTbl * host_ptr,int status);
+void PGRclear_transactions(void);
+void PGRclear_connections(int use_flag);
+int PGRset_replication_id(uint32_t id);
+int PGRdo_replicate(int sock,ReplicateHeader *header, char * query);
+int PGRreturn_result(int dest, int wait);
+int PGRreplicate_packet_send( ReplicateHeader * header, char * query,int dest);
+char * PGRread_packet(int sock, ReplicateHeader *header);
+void PGRnotice_replication_server(char * hostName, unsigned short portNumber,unsigned short recoveryPortNumber, unsigned short lifecheckPortNumber, char * userName);
+char * PGRread_query(int sock, ReplicateHeader *header);
+int PGRwait_transaction_count_clear(void);
+int PGRsync_oid(ReplicateHeader *header);
+unsigned int PGRget_next_query_id(void);
+int PGRget_pgconn_queue(void);
+
+bool
+PGRis_same_host(char * host1, unsigned short port1 , char * host2, unsigned short port2)
+{
+	unsigned int ip1, ip2;
+
+	if ((host1[0] == '\0' ) || (host2[0] == '\0') ||
+		( port1 != port2 ))
+	{
+		return false;
+	}
+	ip1 = PGRget_ip_by_name( host1);
+	ip2 = PGRget_ip_by_name( host2);
+	if ((ip1 == ip2) && (port1 == port2))
+	{
+		return true;
+	}
+	return false;
+}
+
+static PGconn *
+pgr_createConn( char * host, char * port,char * database, char * userName )
+{
+	char *func = "pgr_createConn()";
+	int cnt = 0;
+	PGconn * conn = NULL;
+
+#ifdef PRINT_DEBUG
+	show_debug("%s:PQsetdbLogin host[%s] port[%s] db[%s] user[%s]",
+		func,host,port,database,userName);
+#endif
+	conn = PQsetdbLogin(host, port, NULL, NULL, database, userName, NULL);
+	/* check to see that the backend Connection was successfully made */
+	cnt = 0;
+	while (PQstatus(conn) == CONNECTION_BAD)
+	{
+		show_error("%s:PQsetdbLogin failed. close socket",func);
+		if (conn != NULL)
+		{
+			PQfinish(conn);
+		}
+		conn = PQsetdbLogin(host, port, NULL, NULL, database, userName, NULL);
+		if (cnt > PGR_CONNECT_RETRY_TIME )
+		{
+			if (conn != NULL)
+			{
+				PQfinish(conn);
+			}
+			show_error("%s:PQsetdbLogin  timeout",func);
+			return (PGconn *)NULL;
+		}
+		cnt ++;
+	}
+#ifdef PRINT_DEBUG
+	show_debug("%s:PQsetdbLogin ok",func);
+#endif
+	return conn;
+}
+
+static TransactionTbl *
+setTransactionTbl(HostTbl * host_ptr, ReplicateHeader * header)
+{
+	char * func = "setTransactionTbl()";
+	TransactionTbl * ptr = NULL;
+	TransactionTbl work ;
+	char port[8];
+	char * hostName, *dbName, *userName;
+
+	if ((host_ptr == NULL) || (header == NULL))
+	{
+		return (TransactionTbl *)NULL;
+	}
+	dbName = (char *)header->dbName;
+	snprintf(port,sizeof(port),"%d", host_ptr->port);
+	userName = (char *)header->userName;
+	hostName = (char *)host_ptr->hostName;
+
+	ptr = getTransactionTbl(host_ptr,header);
+	if (ptr != NULL)
+	{
+		ptr->conn = pgr_createConn(hostName,port,dbName,userName);
+		if (ptr->conn == NULL)
+		{
+			show_error("%s:Transaction is pooling but pgr_createConn failed",func);
+			deleteTransactionTbl(host_ptr, header);
+			PGRset_host_status(host_ptr,DATA_ERR);
+			ptr = NULL;
+		}
+		return ptr;
+	}
+
+	memset(&work,0,sizeof(work));
+	strncpy(work.host, hostName, sizeof(work.host));
+	strncpy(work.srcHost, header->from_host, sizeof(work.srcHost));
+	work.hostIP = PGRget_ip_by_name(hostName);
+	work.port = host_ptr->port;
+	work.srcHostIP = PGRget_ip_by_name(header->from_host);
+	work.pid = ntohs(header->pid);
+	strncpy(work.dbName,header->dbName,sizeof(work.dbName));
+	strncpy(work.userName,header->userName,sizeof(work.userName));
+	work.conn = pgr_createConn(hostName,port,dbName,userName);
+	if (work.conn == NULL)
+	{
+		show_error("%s:New Transaction but pgr_createConn%s@%s failed",func,port,hostName);
+		return (TransactionTbl *)NULL;
+	}
+	work.useFlag = DATA_USE ;
+	ptr = insertTransactionTbl(host_ptr,&work);
+	if (ptr == (TransactionTbl *)NULL)
+	{
+		show_error("%s:insertTransactionTbl failed",func);
+		return (TransactionTbl *)NULL;
+	}
+	return ptr;
+}
+
+static TransactionTbl *
+insertTransactionTbl( HostTbl * host_ptr, TransactionTbl * datap)
+{
+	char * func = "insertTransactionTbl()";
+	TransactionTbl * workp = NULL;
+
+	if ((host_ptr == (HostTbl *)NULL) || (datap == (TransactionTbl*)NULL))
+	{
+		show_error("%s:host table or transaction table is NULL",func);
+		return (TransactionTbl *)NULL;
+	}
+	workp = Transaction_Tbl_End;
+	if (workp == (TransactionTbl *)NULL)
+	{
+		workp = (TransactionTbl*)malloc(sizeof(TransactionTbl));
+		if (workp == (TransactionTbl*)NULL)
+		{
+			show_error("%s:malloc() failed. (%s)",func,strerror(errno));
+			return (TransactionTbl *)NULL;
+		}
+		Transaction_Tbl_Begin = workp;
+	}
+	else
+	{
+		workp->next = malloc(sizeof(TransactionTbl));
+		if ( workp->next  == NULL)
+		{
+			show_error("%s:malloc() failed. (%s)",func,strerror(errno));
+			return (TransactionTbl *)NULL;
+		}
+		workp = (TransactionTbl*)workp->next;
+	}
+	memset(workp,0,sizeof(TransactionTbl));
+	workp->next = NULL;
+	workp->last = (char *)Transaction_Tbl_End;
+	Transaction_Tbl_End = workp;
+	workp->hostIP = datap->hostIP;
+	workp->port = datap->port;
+	workp->pid = datap->pid;
+	workp->srcHostIP = datap->srcHostIP;
+	strncpy(workp->host,datap->host,sizeof(workp->host));
+	strncpy(workp->srcHost,datap->srcHost,sizeof(workp->srcHost));
+	strncpy(workp->dbName,datap->dbName,sizeof(workp->dbName));
+	strncpy(workp->userName,datap->userName,sizeof(workp->userName));
+	workp->conn = datap->conn;
+	workp->useFlag = DATA_USE;
+	return workp;
+}
+
+static TransactionTbl *
+getTransactionTbl( HostTbl * host_ptr, ReplicateHeader * header)
+{
+	TransactionTbl * ptr = NULL;
+	unsigned int host_ip,srcHost_ip;
+	unsigned short pid = 0;
+
+
+	if (Transaction_Tbl_Begin == (TransactionTbl *) NULL)
+	{
+		return (TransactionTbl * )NULL;
+	}
+	if ((host_ptr == (HostTbl *)NULL) ||
+		(header == (ReplicateHeader *)NULL))
+	{
+		return (TransactionTbl * )NULL;
+	}
+	host_ip = get_host_ip_from_tbl(host_ptr->hostName);
+	if (host_ip == 0)
+	{
+		host_ip = PGRget_ip_by_name(host_ptr->hostName);
+	}
+	srcHost_ip = get_srcHost_ip_from_tbl(header->from_host);
+	if (srcHost_ip == 0)
+	{
+		srcHost_ip = PGRget_ip_by_name(header->from_host);
+	}
+	pid = ntohs(header->pid);
+	ptr = Transaction_Tbl_Begin;
+	while (ptr != NULL)
+	{
+		if ((ptr->useFlag == DATA_USE) &&
+			(ptr->hostIP == host_ip) &&
+			(ptr->port == host_ptr->port) &&
+			(ptr->srcHostIP == srcHost_ip) &&
+			(!strncmp(ptr->dbName,header->dbName,sizeof(ptr->dbName))) &&
+			(!strncmp(ptr->userName,header->userName,sizeof(ptr->userName))) &&
+			(ptr->pid == pid))
+		{
+			return ptr;
+		}
+		ptr = (TransactionTbl*)ptr->next;
+	}
+	return (TransactionTbl * )NULL;
+}
+
+static void
+deleteTransactionTbl(HostTbl * host_ptr,ReplicateHeader * header)
+{
+	char * func ="deleteTransactionTbl()";
+
+	TransactionTbl *ptr = (TransactionTbl*)NULL;
+	TransactionTbl *last = (TransactionTbl*)NULL;
+	TransactionTbl *next = (TransactionTbl*)NULL;
+
+	ptr = getTransactionTbl(host_ptr,header);
+	if (ptr != (TransactionTbl*)NULL)
+	{
+		last = (TransactionTbl*)ptr->last;
+		next = (TransactionTbl*)ptr->next;
+		if (ptr->conn != NULL)
+		{
+			PQfinish(ptr->conn);
+		}
+		if (last != (TransactionTbl*)NULL)
+		{
+			last->next = (char *)next;
+		}
+		else
+		{
+			Transaction_Tbl_Begin = next;
+		}
+		if (next != (TransactionTbl*)NULL)
+		{
+			next->last = (char *)last;
+		}
+		else
+		{
+			Transaction_Tbl_End = last;
+		}
+		free(ptr);
+		ptr = NULL;
+	}
+	else
+	{
+#ifdef PRINT_DEBUG
+		show_debug("%s: getTransactionTbl failed",func);
+#endif
+	}
+}
+
+static TransactionTbl *
+setPGconnTbl(HostTbl * host_ptr, ReplicateHeader * header, int use_flag)
+{
+	char * func ="setPGconnTbl()";
+	TransactionTbl * ptr = NULL;
+	TransactionTbl work ;
+	char port[8];
+	char * hostName, *dbName, *userName;
+
+	if ((host_ptr == NULL) || (header == NULL))
+	{
+		return (TransactionTbl *)NULL;
+	}
+	dbName = (char *)header->dbName;
+	snprintf(port,sizeof(port),"%d", host_ptr->port);
+	userName = (char *)header->userName;
+	hostName = (char *)host_ptr->hostName;
+
+	ptr = getPGconnTbl(host_ptr,header);
+	if (ptr != NULL)
+	{
+		if (ptr->conn != NULL)
+			PQfinish(ptr->conn);
+		ptr->conn = pgr_createConn(hostName,port,dbName,userName);
+		if (ptr->conn == NULL)
+		{
+			show_error("%s:Transaction is pooling but pgr_createConn failed",func);
+			deletePGconnTbl(host_ptr, header);
+			PGRset_host_status(host_ptr,DATA_ERR);
+			ptr = NULL;
+		}
+		return ptr;
+	}
+
+	memset(&work,0,sizeof(work));
+	work.hostIP = PGRget_ip_by_name(hostName);
+	work.port = host_ptr->port;
+	work.pid = (ntohs(header->pid) % Reserved_Connections);
+	strncpy(work.dbName,header->dbName,sizeof(work.dbName));
+	strncpy(work.userName,header->userName,sizeof(work.userName));
+	work.conn = pgr_createConn(hostName,port,dbName,userName);
+	if (work.conn == NULL)
+	{
+#ifdef PRINT_DEBUG
+		show_debug("%s: %s@%s is not ready",func,port,hostName);
+#endif
+		return (TransactionTbl *)NULL;
+	}
+	work.useFlag = use_flag ;
+	ptr = insertPGconnTbl(host_ptr,&work);
+	if (ptr == (TransactionTbl *)NULL)
+	{
+		show_error("%s:insertPGconnTbl failed",func);
+		return (TransactionTbl *)NULL;
+	}
+	return ptr;
+}
+
+static TransactionTbl *
+insertPGconnTbl( HostTbl * host_ptr, TransactionTbl * datap)
+{
+	char * func = "insertPGconnTbl()";
+	TransactionTbl * workp = NULL;
+
+	if ((host_ptr == (HostTbl *)NULL) || (datap == (TransactionTbl*)NULL))
+	{
+		show_error("%s:host table or transaction table is NULL",func);
+		return (TransactionTbl *)NULL;
+	}
+	workp = PGconn_Tbl_End;
+	if (workp == (TransactionTbl *)NULL)
+	{
+		workp = (TransactionTbl*)malloc(sizeof(TransactionTbl));
+		if (workp == (TransactionTbl*)NULL)
+		{
+			show_error("%s:malloc() failed. (%s)",func,strerror(errno));
+			return (TransactionTbl *)NULL;
+		}
+		PGconn_Tbl_Begin = workp;
+	}
+	else
+	{
+		workp->next = (char *)malloc(sizeof(TransactionTbl));
+		if ( workp->next  == (char*)NULL)
+		{
+			show_error("%s:malloc() failed. (%s)",func,strerror(errno));
+			return (TransactionTbl *)NULL;
+		}
+		workp = (TransactionTbl*)workp->next;
+	}
+	memset(workp,0,sizeof(TransactionTbl));
+	workp->next = NULL;
+	workp->last = (char *)PGconn_Tbl_End;
+	PGconn_Tbl_End = workp;
+	workp->hostIP = datap->hostIP;
+	workp->port = datap->port;
+	workp->pid = datap->pid;
+	strncpy(workp->dbName,datap->dbName,sizeof(workp->dbName));
+	strncpy(workp->userName,datap->userName,sizeof(workp->userName));
+	workp->conn = datap->conn;
+	workp->useFlag = datap->useFlag;
+	return workp;
+}
+
+static TransactionTbl *
+getPGconnTbl( HostTbl * host_ptr, ReplicateHeader * header)
+{
+	TransactionTbl * ptr = NULL;
+	unsigned int host_ip;
+	unsigned short pid = 0;
+
+	if (PGconn_Tbl_Begin == (TransactionTbl *) NULL)
+	{
+		return (TransactionTbl * )NULL;
+	}
+	if ((host_ptr == (HostTbl *)NULL) ||
+		(header == (ReplicateHeader *)NULL))
+	{
+		return (TransactionTbl * )NULL;
+	}
+	host_ip = get_host_ip_from_tbl(host_ptr->hostName);
+	if (host_ip == 0)
+	{
+		host_ip = PGRget_ip_by_name(host_ptr->hostName);
+	}
+	pid = (ntohs(header->pid) % Reserved_Connections);
+	ptr = PGconn_Tbl_Begin;
+	while (ptr != NULL)
+	{
+		if ( ((ptr->useFlag == DATA_USE)  || (ptr->useFlag == DATA_TEMP_USE)) &&
+			(ptr->hostIP == host_ip) &&
+			(ptr->port == host_ptr->port) &&
+			(!strncmp(ptr->dbName,header->dbName,sizeof(ptr->dbName))) &&
+			(!strncmp(ptr->userName,header->userName,sizeof(ptr->userName))) &&
+			(ptr->pid == pid))
+		{
+			return ptr;
+		}
+		ptr = (TransactionTbl*)ptr->next;
+	}
+	return (TransactionTbl * )NULL;
+}
+
+static void
+deletePGconnTbl(HostTbl * host_ptr,ReplicateHeader * header)
+{
+	TransactionTbl *ptr = (TransactionTbl*)NULL;
+	TransactionTbl *last = (TransactionTbl*)NULL;
+	TransactionTbl *next = (TransactionTbl*)NULL;
+
+	ptr = getPGconnTbl(host_ptr,header);
+	if (ptr != (TransactionTbl*)NULL)
+	{
+		last = (TransactionTbl*)ptr->last;
+		next = (TransactionTbl*)ptr->next;
+		if (ptr->conn != NULL)
+		{
+			PQfinish(ptr->conn);
+		}
+		if (last != (TransactionTbl*)NULL)
+		{
+			last->next = (char *)next;
+		}
+		else
+		{
+			PGconn_Tbl_Begin = next;
+		}
+		if (next != (TransactionTbl*)NULL)
+		{
+			next->last = (char *)last;
+		}
+		else
+		{
+			PGconn_Tbl_End = last;
+		}
+		free(ptr);
+		ptr = NULL;
+	}
+}
+
+static HostTbl *
+deleteHostTbl(HostTbl * ptr)
+{
+	if (ptr != (HostTbl*)NULL)
+	{
+		memset(ptr,0,sizeof(HostTbl));
+	}
+	return ++ptr;
+}
+
+HostTbl *
+PGRadd_HostTbl(HostTbl *conf_data, int useFlag)
+{
+	HostTbl * ptr = NULL;
+	int cnt = 0;
+
+
+	ptr = PGRget_HostTbl(conf_data->hostName, conf_data->port);
+	if (ptr != (HostTbl*)NULL)
+	{
+		PGRset_host_status(ptr,useFlag);
+		return ptr;
+	}
+
+	ptr = Host_Tbl_Begin;
+	cnt = 1;
+	while (ptr->useFlag != DATA_END)
+	{
+		if (ptr->useFlag == DATA_FREE)
+		{
+			break;
+		}
+		ptr ++;
+		cnt ++;
+	}
+	if (cnt >= MAX_DB_SERVER)
+	{
+		return (HostTbl*)NULL;
+	}
+	if (ptr->useFlag == DATA_END)
+	{
+		(ptr + 1) -> useFlag = DATA_END;
+	}
+	memset(ptr,0,sizeof(HostTbl));
+	ptr->hostNum = cnt;
+	strncpy(ptr->hostName,conf_data->hostName,sizeof(ptr->hostName));
+	ptr->port = conf_data->port;
+	ptr->recoveryPort = conf_data->recoveryPort;
+	ptr->lifecheckPort = conf_data->lifecheckPort;
+	PGRset_host_status(ptr,useFlag);
+
+	return ptr;
+}
+
+HostTbl *
+PGRget_master(void)
+{
+	HostTbl * host_tbl = NULL;
+
+	host_tbl = Host_Tbl_Begin;
+	while(host_tbl->useFlag != DATA_END)
+	{
+		if (host_tbl->useFlag == DATA_USE)
+		{
+			return host_tbl;
+		}
+		host_tbl ++;
+	}
+	return (HostTbl *)NULL;
+}
+
+void
+PGRset_recovery_status(int status)
+{
+	if (RecoverySemID <= 0)
+		return;
+	PGRsem_lock(RecoverySemID,SEM_NUM_OF_RECOVERY);
+	if (Recovery_Status_Inf != (RecoveryStatusInf *)NULL)
+	{
+		Recovery_Status_Inf->recovery_status = status;
+	}
+	PGRsem_unlock(RecoverySemID,SEM_NUM_OF_RECOVERY);
+}
+
+int
+PGRget_recovery_status(void)
+{
+	int status = 0;
+
+	if (RecoverySemID <= 0)
+		return -1;
+	PGRsem_lock(RecoverySemID,SEM_NUM_OF_RECOVERY);
+	if (Recovery_Status_Inf != (RecoveryStatusInf *)NULL)
+	{
+		status = Recovery_Status_Inf->recovery_status;
+		PGRsem_unlock(RecoverySemID,SEM_NUM_OF_RECOVERY);
+		return status;
+	}
+	PGRsem_unlock(RecoverySemID,SEM_NUM_OF_RECOVERY);
+	return -1;
+}
+
+static void
+begin_transaction_status(int recovery_status)
+{
+	if (RecoverySemID <= 0)
+	{
+		return ;
+	}
+	PGRsem_lock(RecoverySemID, SEM_NUM_OF_RECOVERY);
+	if (Recovery_Status_Inf != (RecoveryStatusInf *)NULL)
+	{
+		if (recovery_status == RECOVERY_PREPARE_START)
+		{
+			Recovery_Status_Inf->transaction_count ++;
+		}
+	}
+	PGRsem_unlock(RecoverySemID, SEM_NUM_OF_RECOVERY);
+}
+
+static void
+end_transaction_status(int recovery_status)
+{
+	if (RecoverySemID <= 0)
+	{
+		return ;
+	}
+	PGRsem_lock(RecoverySemID, SEM_NUM_OF_RECOVERY);
+	if (Recovery_Status_Inf != (RecoveryStatusInf *)NULL)
+	{
+		if (recovery_status == RECOVERY_PREPARE_START)
+		{
+			Recovery_Status_Inf->transaction_count --;
+		}
+	}
+	PGRsem_unlock(RecoverySemID, SEM_NUM_OF_RECOVERY);
+}
+
+static void
+set_transaction_status(int status)
+{
+	if (RecoverySemID <= 0)
+	{
+		return ;
+	}
+	PGRsem_lock(RecoverySemID, SEM_NUM_OF_RECOVERY);
+	if (Recovery_Status_Inf != (RecoveryStatusInf *)NULL)
+	{
+		Recovery_Status_Inf->recovery_status = status;
+	}
+	PGRsem_unlock(RecoverySemID, SEM_NUM_OF_RECOVERY);
+}
+
+int
+PGRwait_transaction_count_clear(void)
+{
+	int cnt = 0;
+
+	if (RecoverySemID <= 0)
+	{
+		return STATUS_ERROR;
+	}
+	PGRsem_lock(RecoverySemID, SEM_NUM_OF_RECOVERY);
+	if (Recovery_Status_Inf != (RecoveryStatusInf *)NULL)
+	{
+		while(Recovery_Status_Inf->transaction_count > 0)
+		{
+			if (cnt > PGR_RECOVERY_RETRY_CNT)
+			{
+				PGRsem_unlock(RecoverySemID, SEM_NUM_OF_RECOVERY);
+				return STATUS_ERROR;
+			}
+			usleep( PGR_RECOVERY_WAIT_MSEC );
+			cnt ++;
+		}
+		PGRsem_unlock(RecoverySemID, SEM_NUM_OF_RECOVERY);
+		return STATUS_OK;
+	}
+	PGRsem_unlock(RecoverySemID, SEM_NUM_OF_RECOVERY);
+	return STATUS_ERROR;
+}
+
+int
+PGRcheck_recovered_host(void)
+{
+	char * func = "PGRcheck_recovered_host()";
+	HostTbl * ptr = NULL;
+	int rtn = STATUS_OK;
+
+	if (RecoverySemID <= 0 )
+	{
+		return STATUS_ERROR;
+	}
+	PGRsem_lock(RecoverySemID, SEM_NUM_OF_RECOVERY);
+	if (Recovery_Status_Inf != (RecoveryStatusInf *)NULL)
+	{
+		if (Recovery_Status_Inf->useFlag != DATA_FREE)
+		{
+			ptr = PGRadd_HostTbl((HostTbl *)&(Recovery_Status_Inf->target_host),Recovery_Status_Inf->useFlag);
+			if (ptr == (HostTbl *) NULL)
+			{
+				show_error("%s:PGRadd_HostTbl failed",func);
+				rtn = STATUS_ERROR;
+			}
+			Recovery_Status_Inf->useFlag = DATA_FREE;
+			memset((HostTbl *)&(Recovery_Status_Inf->target_host),0,sizeof(HostTbl));
+
+		}
+	}
+	PGRsem_unlock(RecoverySemID, SEM_NUM_OF_RECOVERY);
+	return rtn;
+}
+
+int
+PGRset_recovered_host(HostTbl * target, int useFlag)
+{
+	if (SemID <= 0)
+	{
+		return -1;
+	}
+	PGRsem_lock(RecoverySemID, SEM_NUM_OF_RECOVERY);
+	if (Recovery_Status_Inf != (RecoveryStatusInf *)NULL)
+	{
+		Recovery_Status_Inf->useFlag = useFlag;
+		if (target != (HostTbl*)NULL)
+		{
+			memcpy((HostTbl *)&(Recovery_Status_Inf->target_host),target,sizeof(HostTbl));
+			PGRset_host_status(target,useFlag);
+		}
+	}
+	PGRsem_unlock(RecoverySemID, SEM_NUM_OF_RECOVERY);
+	return 0;
+}
+
+static bool
+is_master_in_recovery(char * host , int port)
+{
+	int status = 0;
+	HostTbl * master = NULL;
+
+	status = PGRget_recovery_status();
+	if (status == RECOVERY_START)
+	{
+		master = PGRget_master();
+		if (master == (HostTbl *)NULL)
+		{
+			return false;
+		}
+		if ((!strcmp(host,master->hostName)) &&
+			(port == master->port))
+		{
+			return true;
+		}
+	}
+	return false;
+}
+
+int
+PGRinit_recovery(void)
+{
+	char * func = "PGRinit_recovery()";
+	int size = 0;
+	union semun sem_arg;
+	int i = 0;
+
+	if ((RecoverySemID = semget(IPC_PRIVATE,4,IPC_CREAT | IPC_EXCL | 0600)) < 0)
+	{
+		show_error("%s:semget() failed. (%s)",func,strerror(errno));
+		return STATUS_ERROR;
+	}
+	for ( i = 0 ; i < 4 ; i ++)
+	{
+		semctl(RecoverySemID, i, GETVAL, sem_arg);
+		sem_arg.val = 1;
+		semctl(RecoverySemID, i, SETVAL, sem_arg);
+	}
+
+	size = sizeof(RecoveryStatusInf);
+	RecoveryShmid = shmget(IPC_PRIVATE,size,IPC_CREAT | IPC_EXCL | 0600);
+	if (RecoveryShmid < 0)
+	{
+		show_error("%s:shmget() failed. (%s)",func,strerror(errno));
+		return STATUS_ERROR;
+	}
+	Recovery_Status_Inf = (RecoveryStatusInf *)shmat(RecoveryShmid,0,0);
+	if (Recovery_Status_Inf == (RecoveryStatusInf *)-1)
+	{
+		show_error("%s:shmat() failed. (%s)",func,strerror(errno));
+		return STATUS_ERROR;
+	}
+	memset(Recovery_Status_Inf,0,sizeof(RecoveryStatusInf));
+	PGRset_recovery_status(RECOVERY_INIT);
+	PGRset_recovered_host((HostTbl *)NULL, DATA_FREE);
+	set_transaction_status(0);
+
+	/*
+	 * create message queue
+	 */
+	QueryLogMsgid = msgget (IPC_PRIVATE, 00666 | IPC_CREAT );
+	if (QueryLogMsgid < 0)
+	{
+		show_error("%s,msgget() failed. (%s)",func,strerror(errno));
+		return STATUS_ERROR;
+	}
+
+	QueryLogAnsMsgid = msgget (IPC_PRIVATE, 00666 | IPC_CREAT );
+	if (QueryLogAnsMsgid < 0)
+	{
+		show_error("%s:msgget() failed. (%s)",func,strerror(errno));
+		return STATUS_ERROR;
+	}
+
+	return STATUS_OK;
+}
+
+static void
+clearHostTbl(void)
+{
+	HostTbl * ptr = NULL;
+
+	if (Host_Tbl_Begin == NULL)
+	{
+		return;
+	}
+	/* normal socket close */
+	ptr = Host_Tbl_Begin;
+	while(ptr->useFlag != DATA_END)
+	{
+		ptr = deleteHostTbl(ptr);
+	}	
+}
+
+void
+PGRreplicate_exit(int sig)
+{
+	char fname[PGR_MESSAGE_BUFSIZE];
+	int rtn = 0;
+
+	Exit_Request = true;
+	if (sig == SIGTERM)
+	{
+		if (Idle_Flag == BUSY_MODE)
+		{
+			return;
+		}
+	}
+
+	signal(SIGCHLD,SIG_IGN);
+	signal(sig,SIG_IGN);
+	kill (0,sig);
+	while (wait(NULL) > 0 )
+	{
+		fprintf(stderr,".");
+	}
+	fprintf(stderr,"\n ok. stop all child processes\n");
+
+	/* recovery status clear */	
+	PGRset_recovery_status(RECOVERY_INIT);
+
+	/* normal socket close */
+	clearHostTbl();
+
+	if (Host_Tbl_Begin != (HostTbl *)NULL)
+	{
+		rtn = shmdt((char *)Host_Tbl_Begin);
+		shmctl(HostTblShmid,IPC_RMID,(struct shmid_ds *)NULL);
+		Host_Tbl_Begin = NULL;
+	}
+
+	if (LoadBalanceTbl != (RecoveryTbl *)NULL)
+	{
+		rtn = shmdt((char *)LoadBalanceTbl);
+		shmctl(LoadBalanceTblShmid,IPC_RMID,(struct shmid_ds *)NULL);
+		LoadBalanceTbl = (RecoveryTbl *)NULL;
+	}
+
+	if (Cascade_Tbl != (ReplicateServerInfo *)NULL)
+	{
+		rtn = shmdt((char *)Cascade_Tbl);
+		shmctl(CascadeTblShmid,IPC_RMID,(struct shmid_ds *)NULL);
+		Cascade_Tbl = NULL;
+	}
+
+	if (Cascade_Inf != (CascadeInf *)NULL)
+	{
+		rtn = shmdt((char *)Cascade_Inf);
+		shmctl(CascadeInfShmid,IPC_RMID,(struct shmid_ds *)NULL);
+		Cascade_Inf = NULL;
+	}
+
+	if (Commit_Log_Tbl != (CommitLogInf *)NULL)
+	{
+		rtn = shmdt((char *)Commit_Log_Tbl);
+		shmctl(CommitLogShmid,IPC_RMID,(struct shmid_ds *)NULL);
+		Commit_Log_Tbl = NULL;
+	}
+
+	if (Recovery_Status_Inf != (RecoveryStatusInf *)NULL)
+	{
+		rtn = shmdt((char *)Recovery_Status_Inf);
+		shmctl(RecoveryShmid,IPC_RMID,(struct shmid_ds *)NULL);
+		Recovery_Status_Inf = NULL;
+	}
+
+	if (Lock_Wait_Tbl != (LockWaitInf *)NULL)
+	{
+		rtn = shmdt((char *)Lock_Wait_Tbl);
+		shmctl(LockWaitTblShmid,IPC_RMID,(struct shmid_ds *)NULL);
+		Lock_Wait_Tbl = NULL;
+	}
+
+	if (PGconnMsgid >= 0)
+	{
+		msgctl(PGconnMsgid, IPC_RMID,(struct msqid_ds *)NULL);
+	}
+
+	if (QueryLogMsgid >= 0)
+	{
+		msgctl(QueryLogMsgid,IPC_RMID,(struct msqid_ds *)NULL);
+		QueryLogMsgid  = -1;
+	}
+	if (QueryLogAnsMsgid >= 0)
+	{
+		msgctl(QueryLogAnsMsgid,IPC_RMID,(struct msqid_ds *)NULL);
+		QueryLogAnsMsgid = -1;
+	}
+
+	if (Com_Info.Log_Info.StatusFp != NULL)
+	{
+		fflush(Com_Info.Log_Info.StatusFp);
+		fclose(Com_Info.Log_Info.StatusFp);
+		Com_Info.Log_Info.StatusFp = NULL;
+	}
+	if (Com_Info.Log_Info.LogFp != NULL)
+	{
+		fflush(Com_Info.Log_Info.LogFp);
+		fclose(Com_Info.Log_Info.LogFp);
+		Com_Info.Log_Info.LogFp = NULL;
+	}
+
+	if (PGR_Result != NULL)
+	{
+		free(PGR_Result);
+		PGR_Result = NULL;
+	}
+	if (PGR_Response_Inf != NULL)
+	{
+		free(PGR_Response_Inf);
+		PGR_Response_Inf = NULL;
+	}
+
+	if (LoadBalanceTbl != NULL)
+	{
+		free(LoadBalanceTbl);
+		LoadBalanceTbl = NULL;
+	}
+
+	if (PGR_Log_Header != NULL)
+	{
+		free(PGR_Log_Header);
+		PGR_Log_Header = NULL;
+	}
+
+	if (PGR_Send_Query_ID != NULL)
+	{
+		free(PGR_Send_Query_ID);
+		PGR_Send_Query_ID = NULL;
+	}
+
+	if (SemID > 0)
+	{
+		sem_quit(SemID);
+		SemID = 0;
+	}
+	if (RecoverySemID > 0)
+	{
+		sem_quit(RecoverySemID);
+		RecoverySemID = 0;
+	}
+
+	snprintf(fname, sizeof(fname), "%s/%s", PGR_Data_Path, PGREPLICATE_PID_FILE);
+	unlink(fname);
+
+	/* close socket between rlog process */
+	if (Replicateion_Log->r_log_sock >= 0)
+	{
+		close(Replicateion_Log->r_log_sock);
+		Replicateion_Log->r_log_sock = -1;
+	}
+	if (Replicateion_Log->RLog_Sock_Path != NULL)
+	{
+		unlink(Replicateion_Log->RLog_Sock_Path);
+		free(Replicateion_Log->RLog_Sock_Path);
+		Replicateion_Log->RLog_Sock_Path = NULL;
+	}
+
+	PGRsyn_quit();
+
+	pthread_exit((void *) 0);
+}
+
+static int
+send_cluster_status_to_load_balance(HostTbl * host_ptr,int status)
+{
+	RecoveryPacket packet;
+	int rtn = 0;
+
+	memset(&packet,0,sizeof(RecoveryPacket));
+	packet.packet_no = htons(status);
+	strncpy(packet.hostName,host_ptr->hostName,sizeof(packet.hostName));
+	packet.port = htons(host_ptr->port);
+	rtn = PGRsend_load_balance_packet(&packet);
+	return rtn;
+}
+
+int
+PGRset_host_status(HostTbl * host_ptr,int status)
+{
+	if (host_ptr == NULL)
+	{
+		return STATUS_ERROR;
+	}
+	if (host_ptr->useFlag != status)
+	{
+		host_ptr->useFlag = status;
+		if (status == DATA_ERR )
+		{
+			send_cluster_status_to_load_balance(host_ptr,RECOVERY_ERROR_CONNECTION);
+		}
+		write_host_status_file(host_ptr);
+	}
+	return STATUS_OK;
+}
+
+static void
+write_host_status_file(HostTbl * host_ptr)
+{
+	switch( host_ptr->useFlag)
+	{
+		case DATA_FREE:
+			PGRwrite_log_file(Com_Info.Log_Info.StatusFp,"port(%d) host:%s free",
+					host_ptr->port,
+					host_ptr->hostName);
+			break;
+		case DATA_INIT:
+			PGRwrite_log_file(Com_Info.Log_Info.StatusFp,"port(%d) host:%s initialize",
+					host_ptr->port,
+					host_ptr->hostName);
+			break;
+		case DATA_USE:
+		case DATA_NEW:
+			PGRwrite_log_file(Com_Info.Log_Info.StatusFp,"port(%d) host:%s start use",
+					host_ptr->port,
+					host_ptr->hostName);
+			break;
+		case DATA_ERR:
+			PGRwrite_log_file(Com_Info.Log_Info.StatusFp,"port(%d) host:%s error",
+					host_ptr->port,
+					host_ptr->hostName);
+			break;
+		case DATA_END:
+			PGRwrite_log_file(Com_Info.Log_Info.StatusFp,"port(%d) host:%s end",
+					host_ptr->port,
+					host_ptr->hostName);
+			break;
+	}
+}
+
+/*--------------------------------------------------
+ * SYMBOL
+ *     PGRsend_replicate_packet_to_server()
+ * NOTES
+ *     Send query data to the cluster DB and recieve result data. 
+ * ARGS
+ *     HostTbl * host_ptr: the record of cluster DB table (target)
+ *     ReplicateHeader * header: header data
+ *     char *query: query data 
+ *     char * result: returned result data 
+ * RETURN
+ *     STATUS_OK: OK
+ *     STATUS_ERROR: NG
+ *     STATUS_LOCK_CONFLICT: Lock conflicted
+ *---------------------------------------------------
+ */
+int
+PGRsend_replicate_packet_to_server( HostTbl * host_ptr, ReplicateHeader * header, char *query , char * result,int type)
+{
+	char * func = "PGRsend_replicate_packet_to_server()";
+	TransactionTbl * transaction_tbl = NULL;
+	char *database = NULL;
+	char port[8];
+	char *userName = NULL;
+	char * host = NULL;
+	char * str = NULL;
+	PGresult * res = (PGresult *)NULL;
+	PGconn * conn = (PGconn *)NULL;
+	bool sync_command_flg = false;
+	int rtn = 0;
+	int current_cluster = 0;
+	int hostNum = 0;
+	int query_size = 0;
+	int status = STATUS_OK;
+
+	if ((query == NULL) || (header == NULL))
+	{
+		show_error("%s:query is broken",func);
+		return STATUS_ERROR;
+	}
+	query_size = ntohl(header->query_size);
+	if (query_size < 0)
+	{
+		show_error("%s:query is broken",func);
+		return STATUS_ERROR;
+	}
+	if (host_ptr == NULL)
+	{
+		show_error("%s:host table is empty",func);
+		return STATUS_ERROR;
+	}
+
+	hostNum = host_ptr->hostNum;
+	
+	/* check query id */
+	if ((*(PGR_Send_Query_ID + hostNum ) == ntohl(header->request_id)) &&
+		( ntohl(header->request_id) != 0))
+	{
+		return STATUS_OK;
+	}
+
+	/*
+	 * set up the connection
+	 */
+	database = (char *)header->dbName;
+	snprintf(port,sizeof(port),"%d", host_ptr->port);
+	userName = (char *)header->userName;
+	host = host_ptr->hostName;
+	if (PGR_Response_Inf != NULL)
+	{
+		current_cluster = PGR_Response_Inf->current_cluster;
+	}
+	/*
+	 * When the query is transaction query...
+	 */
+	if (is_need_sync_time(header) == true)
+	{
+		sync_command_flg = true;
+	}
+	if ((header->cmdSts == CMD_STS_TRANSACTION ) ||
+		(header->cmdSts == CMD_STS_SET_SESSION_AUTHORIZATION ))
+	{
+		if ((header->cmdSts == CMD_STS_TRANSACTION ) &&
+			(header->cmdType != CMD_TYPE_BEGIN))
+		{
+			sync_command_flg = false;
+		}
+	}
+	/*
+	 * get the transaction table data
+	 * it has the connection data with each cluster DB
+	 */
+	transaction_tbl = get_conn(host_ptr, header);
+	if (transaction_tbl == NULL)
+	{
+		if (header->cmdSts != CMD_STS_NOTICE ) 
+		{
+			show_error("%s: could not get connection",func);
+			PGRset_host_status(host_ptr,DATA_ERR);
+		}
+		return STATUS_ERROR;
+	}
+	conn = transaction_tbl->conn;
+	if (conn == NULL)
+	{
+		show_error("%s:[%d@%s] may be down",func,host_ptr->port,host_ptr->hostName);
+		if ( header->cmdSts != CMD_STS_NOTICE )
+		{
+			PGRset_host_status(host_ptr,DATA_ERR);
+		}
+		return STATUS_ERROR;
+	}
+
+	if (header->rlog > 0)
+	{
+		if (is_executed_query( conn, header) == true)
+		{
+			return STATUS_OK;
+		}
+	}
+	else
+	{
+		send_sync_data(conn,header,sync_command_flg,current_cluster);
+	}
+	if ((header->cmdType == CMD_TYPE_COPY_DATA) ||
+		(header->cmdType == CMD_TYPE_COPY_DATA_END))
+	{
+		/* copy data replication */
+		rtn =PQputnbytes(conn, query,query_size);
+		if (header->cmdType == CMD_TYPE_COPY_DATA_END)
+		{
+			rtn = PQendcopy(conn);
+			if (rtn == 1)
+			{
+				PQfinish(transaction_tbl->conn);
+				transaction_tbl->conn = (PGconn *)NULL;
+				StartReplication[current_cluster] = true;
+			}
+		}
+		*(PGR_Send_Query_ID + hostNum ) = ntohl(header->request_id);
+		return STATUS_OK;
+	}
+	else if (header->cmdSts == CMD_STS_LARGE_OBJECT)
+	{
+		replicate_lo(conn,header->cmdType,(LOArgs *)query);
+		return STATUS_OK;
+	}
+	else
+	{
+		status = replicate_query(res, conn, host_ptr,header, query, sync_command_flg, current_cluster);
+		if ((status == STATUS_OK) && (res == NULL))
+		{
+			return STATUS_OK;
+		}
+	}
+
+	if (res == NULL)
+	{
+		StartReplication[current_cluster] = true;
+		return STATUS_ERROR;
+	}
+#ifdef PRINT_DEBUG
+	show_debug("%s:PQexec send :%s",func,query);
+#endif			
+	str = PQcmdStatus(res);
+	if ((str == NULL) || (*str == '\0'))
+	{
+		if ((result != NULL) && (res != NULL) && (res->errMsg != NULL))
+		{
+			snprintf(result,PGR_MESSAGE_BUFSIZE,"E%s",res->errMsg);
+		}
+		else
+		{
+			strcpy(result,"E");
+		}
+		StartReplication[current_cluster] = true;
+	}
+	else
+	{
+		if (!strncmp(str,PGR_LOCK_CONFLICT_NOTICE_CMD,strlen(PGR_LOCK_CONFLICT_NOTICE_CMD)))
+		{
+#ifdef PRINT_DEBUG
+			show_debug("%s:LOCK CONFLICT from PQexec",func);
+#endif			
+			if (res != NULL)
+				PQclear(res);
+			return STATUS_LOCK_CONFLICT;
+		}
+		else if (!strncmp(str,PGR_DEADLOCK_DETECT_NOTICE_CMD,strlen(PGR_DEADLOCK_DETECT_NOTICE_CMD)))
+		{
+#ifdef PRINT_DEBUG
+			show_debug("%s:DEADLOCK DETECTED from PQexec",func);
+#endif			
+			if (res != NULL)
+				PQclear(res);
+			return STATUS_DEADLOCK_DETECT;
+		}
+		snprintf(result,PGR_MESSAGE_BUFSIZE,"C%s",str);
+	}
+
+	if (res != NULL)
+		PQclear(res);
+
+	/* set send query id */
+	*(PGR_Send_Query_ID + hostNum ) = ntohl(header->request_id);
+
+	/*
+	 * if the query is end transaction process...
+	 */
+	check_delete_transaction(host_ptr,header);
+	return STATUS_OK;
+
+}
+
+static TransactionTbl *
+get_conn( HostTbl * host_ptr, ReplicateHeader * header)
+{
+	TransactionTbl * transaction_tbl = NULL;
+	/*
+	 * get the transaction table data
+	 * it has the connection data with each cluster db
+	 */
+	if ((header->cmdSts != CMD_STS_QUERY)  &&
+		(header->cmdSts != CMD_STS_OTHER))
+	{
+		transaction_tbl = getTransactionTbl(host_ptr,header);
+	}
+	else
+	{
+		transaction_tbl = getPGconnTbl(host_ptr,header);
+	}
+	/*
+	 * if the transaction process is new one, 
+	 * create connection data and add the transaction table
+	 */
+	if (transaction_tbl == (TransactionTbl *)NULL)
+	{
+		if ((header->cmdSts != CMD_STS_QUERY)  &&
+			(header->cmdSts != CMD_STS_OTHER))
+		{
+			transaction_tbl = setTransactionTbl(host_ptr, header);
+		}
+		else
+		{
+			transaction_tbl = setPGconnTbl(host_ptr, header, DATA_TEMP_USE);
+			set_pgconn_queue(header);
+		}
+		if (transaction_tbl == (TransactionTbl *)NULL)
+		{
+			return (TransactionTbl*)NULL;
+		}
+	}
+	return (transaction_tbl);
+}
+
+static TransactionTbl *
+recreate_conn( HostTbl* host_ptr, ReplicateHeader* header)
+{
+	TransactionTbl * transaction_tbl = NULL;
+	/*
+	 * re-create connection data
+	 */
+	deletePGconnTbl(host_ptr, header);
+	if ((header->cmdSts != CMD_STS_QUERY)  &&
+		(header->cmdSts != CMD_STS_OTHER))
+	{
+		transaction_tbl = setTransactionTbl(host_ptr, header);
+	}
+	else
+	{
+		transaction_tbl = setPGconnTbl(host_ptr, header, DATA_TEMP_USE);
+		set_pgconn_queue(header);
+	}
+	return transaction_tbl;
+}
+
+static int
+send_sync_data(PGconn *conn, ReplicateHeader * header, bool sync_command_flg, int current_cluster)
+{
+	char * func = "send_sync_data()";
+	static PGresult * res = (PGresult *)NULL;
+	char sync_command[PGR_MESSAGE_BUFSIZE];
+
+	/*
+	 * execute query
+	 */
+	if ((( header->cmdSts != CMD_STS_NOTICE ) &&
+		( header->cmdSts != CMD_STS_LARGE_OBJECT)) &&
+		((sync_command_flg == true)           ||
+		 (StartReplication[current_cluster] == true)))
+	{
+		snprintf(sync_command,sizeof(sync_command),
+			"SELECT %s(%d,%u,%u,%u,%d) ",
+			PGR_SYSTEM_COMMAND_FUNC,
+			PGR_SET_CURRENT_TIME_FUNC_NO,
+			(unsigned int)ntohl(header->tv.tv_sec),
+			(unsigned int)ntohl(header->tv.tv_usec),
+			(unsigned int)ntohl(PGR_Log_Header->replicate_id),
+			PGR_Response_Inf->response_mode);
+#ifdef PRINT_DEBUG
+		show_debug("%s:sync_command(%s)",func,sync_command);
+#endif			
+		res = PQexec(conn, sync_command);
+		if (res != NULL)
+		{
+			PQclear(res);
+		}
+	}
+	res = NULL;
+	return STATUS_OK;
+}
+
+static int
+replicate_query(PGresult * res, PGconn * conn, HostTbl * host_ptr, ReplicateHeader * header, char *query, bool sync_command_flg, int current_cluster)
+{
+	char * func ="replicate_query()";
+	TransactionTbl * transaction_tbl = NULL;
+	int cnt = 0;
+
+	while ((res = PQexec(conn, query)) == NULL)
+	{
+		if (header->cmdSts == CMD_STS_NOTICE )
+		{
+			StartReplication[current_cluster] = true;
+			return STATUS_OK;
+		}
+		if (cnt > MAX_RETRY_TIMES)
+		{
+#ifdef PRINT_DEBUG
+			show_debug("%s:PQexec failed",func);
+#endif			
+			if (header->cmdSts != CMD_STS_NOTICE )
+			{
+				PGRset_host_status(host_ptr,DATA_ERR);
+			}
+			StartReplication[current_cluster] = false;
+			return STATUS_ERROR;
+		}
+		transaction_tbl = recreate_conn(host_ptr,header);
+		if (transaction_tbl == NULL)
+		{
+			if (header->cmdSts != CMD_STS_NOTICE )
+			{
+				show_error("%s: could not get connection",func);
+				PGRset_host_status(host_ptr,DATA_ERR);
+			}
+			StartReplication[current_cluster] = false;
+			return STATUS_ERROR;
+		}
+		conn = transaction_tbl->conn;
+		send_sync_data(conn,header,sync_command_flg,current_cluster);
+		cnt ++;
+	}
+	return STATUS_OK;
+}
+
+static bool
+is_executed_query_in_origin( ReplicateHeader *header )
+{
+	char *database = NULL;
+	char port[8];
+	char *userName = NULL;
+	char * host = NULL;
+	HostTbl * host_ptr = (HostTbl*)NULL;
+	TransactionTbl * transaction_tbl = (TransactionTbl*)NULL;
+	PGconn * conn = (PGconn *)NULL;
+	bool result = false;
+
+	if (Host_Tbl_Begin == NULL)
+	{
+		return STATUS_ERROR;
+	}
+	host_ptr = Host_Tbl_Begin;
+	while(host_ptr->useFlag != DATA_END)
+	{
+		/*
+		 * check the status of the cluster DB
+		 */
+		if (host_ptr->useFlag != DATA_USE)
+		{
+			host_ptr ++;
+			continue;
+		}
+		if (PGRis_same_host(header->from_host,ntohs(header->port),host_ptr->hostName, host_ptr->port) == true)
+		{
+			break;
+		}
+		host_ptr ++;
+	}
+	if (host_ptr->useFlag == DATA_END)
+	{
+		return false;
+	}
+	/*
+	 * set up the connection
+	 */
+	transaction_tbl = getTransactionTbl(host_ptr,header);
+	if (transaction_tbl == (TransactionTbl *)NULL)
+	{
+		transaction_tbl = setTransactionTbl(host_ptr, header);
+		if (transaction_tbl == (TransactionTbl *)NULL)
+		{
+			return false;
+		}
+	}
+	else
+	{
+		if ((transaction_tbl->conn == (PGconn *)NULL) ||
+			(transaction_tbl->conn->sock > 0))
+		{
+			database = (char *)header->dbName;
+			snprintf(port,sizeof(port),"%d", host_ptr->port);
+			userName = (char *)header->userName;
+			host = host_ptr->hostName;
+		 	transaction_tbl->conn = pgr_createConn(host,port,database,userName);
+		}
+	}
+	conn = transaction_tbl->conn;
+	if (conn == NULL)
+	{
+		return false;
+	}
+
+	result = is_executed_query( conn, header);
+	deleteTransactionTbl(host_ptr,header);
+	return result;
+}
+
+static bool
+is_executed_query( PGconn *conn, ReplicateHeader * header)
+{
+	char * func = "is_executed_query()";
+	static PGresult * res = (PGresult *)NULL;
+	char sync_command[PGR_MESSAGE_BUFSIZE];
+	char * str = NULL;
+
+	snprintf(sync_command,sizeof(sync_command),
+		"SELECT %s(%d,%u,%u,%u,%d) ",
+		PGR_SYSTEM_COMMAND_FUNC,
+		PGR_QUERY_CONFIRM_ANSWER_FUNC_NO,
+		(unsigned int)ntohl(header->tv.tv_sec),
+		(unsigned int)ntohl(header->tv.tv_usec),
+		(unsigned int)ntohl(header->replicate_id),
+		PGR_Response_Inf->response_mode);
+#ifdef PRINT_DEBUG
+	show_debug("%s:sync_command(%s)",func,sync_command);
+#endif		
+	res = PQexec(conn, sync_command);
+	if (res != NULL)
+	{
+		str = PQcmdStatus(res);
+#ifdef PRINT_DEBUG
+show_debug("%s:PQcmdStatus return[%s]",func,str);
+#endif		
+		if ((str != NULL) &&
+			(!strncmp(str,PGR_ALREADY_REPLICATED_NOTICE_CMD,strlen(PGR_ALREADY_REPLICATED_NOTICE_CMD))))
+		{
+			PQclear(res);
+			return true;
+		}
+		PQclear(res);
+	}
+	return false;
+}
+
+static int
+replicate_lo( PGconn * conn, char cmdType, LOArgs * query)
+{
+	int status = STATUS_OK;
+	int mode = 0;
+	Oid lobjId = 0;
+	int fd = 0;
+	char * buf = NULL;
+	size_t len = 0;
+	int offset = 0;
+	int whence = 0;
+
+	if ((conn == (PGconn *)NULL) || (query == (LOArgs *)NULL))
+	{
+		return STATUS_ERROR;
+	}
+	switch (cmdType)
+	{
+		case CMD_TYPE_LO_CREATE :
+			mode = (int)ntohl(query->arg1);
+			if (lo_creat(conn, mode) > 0)
+			{
+				status = STATUS_OK;
+			}
+			else
+			{
+				status = STATUS_ERROR;
+			}
+			break;
+		case CMD_TYPE_LO_OPEN :
+			lobjId = (Oid)ntohl(query->arg1);
+			mode = (int)ntohl(query->arg2);
+			if (lo_open(conn, lobjId, mode) > 0)
+			{
+				status = STATUS_OK;
+			}
+			else
+			{
+				status = STATUS_ERROR;
+			}
+			break;
+		case CMD_TYPE_LO_WRITE :
+			fd = (int)ntohl(query->arg1);
+			len = (int)ntohl(query->arg2);
+			buf = query->buf;
+			if (lo_write(conn, fd, buf, len) == len )
+			{
+				status = STATUS_OK;
+			}
+			else
+			{
+				status = STATUS_ERROR;
+			}
+			break;
+		case CMD_TYPE_LO_LSEEK :
+			fd = (int)ntohl(query->arg1);
+			offset = (int)ntohl(query->arg2);
+			whence = (int)ntohl(query->arg3);
+			if (lo_lseek(conn, fd, offset, whence) >= 0)
+			{
+				status = STATUS_OK;
+			}
+			else
+			{
+				status = STATUS_ERROR;
+			}
+			break;
+		case CMD_TYPE_LO_CLOSE :
+			fd = (int)ntohl(query->arg1);
+			if (lo_close(conn, fd) == 0)
+			{
+				status = STATUS_OK;
+			}
+			else
+			{
+				status = STATUS_ERROR;
+			}
+			break;
+		case CMD_TYPE_LO_UNLINK :
+			lobjId = (Oid)ntohl(query->arg1);
+			if (lo_unlink(conn,lobjId) >= 0)
+			{
+				status = STATUS_OK;
+			}
+			else
+			{
+				status = STATUS_ERROR;
+			}
+			break;
+		default :
+			break;
+	}
+	return status;
+}
+
+static int
+check_delete_transaction (HostTbl * host_ptr, ReplicateHeader * header)
+{
+	char	   *database = NULL;
+
+	if ((host_ptr == NULL) || (header == NULL))
+	{
+		return STATUS_ERROR;
+	}
+	database = (char *)header->dbName;
+	if (header->cmdSts == CMD_STS_SET_SESSION_AUTHORIZATION )
+	{
+		if (header->cmdType == CMD_TYPE_SESSION_AUTHORIZATION_END )
+		{
+			deleteTransactionTbl(host_ptr,header);
+		}
+	}
+	else
+	{
+		if (header->cmdSts == CMD_STS_TRANSACTION )
+		{
+			if ((header->cmdType == CMD_TYPE_COMMIT) ||
+		 		(header->cmdType == CMD_TYPE_ROLLBACK))
+			{
+				/*
+				 * logout the cluster DB and delete transaction table
+				 */
+				if (PGR_AutoCommit)
+				{
+					deleteTransactionTbl(host_ptr,header);
+				}
+			}
+		}
+	}
+	delete_template(host_ptr, header);
+	return STATUS_OK;
+}
+
+static void
+check_transaction_status(ReplicateHeader * header,int recovery_status)
+{
+	if (header == (ReplicateHeader *)NULL)
+	{
+		return;
+	}
+
+	if (header->cmdSts == CMD_STS_TRANSACTION )
+	{
+		if (header->cmdType != CMD_TYPE_BEGIN )
+		{
+			begin_transaction_status(recovery_status);
+		}
+		else if ((header->cmdType != CMD_TYPE_COMMIT) &&
+				 (header->cmdType != CMD_TYPE_ROLLBACK))
+		{
+			end_transaction_status(recovery_status);
+		}
+	}
+
+}
+/*
+ * set query in queue 
+ */
+int
+PGRset_queue(ReplicateHeader * header,char * query)
+{
+	char * func = "PGRset_queue()";
+
+	int query_size = 0;
+
+	if ((RecoverySemID <= 0) || (header == NULL))
+	{
+		return STATUS_ERROR;
+	}
+	query_size = ntohl(header->query_size);
+	if (query_size < 0)
+	{
+		return STATUS_ERROR;
+	}
+	PGRsem_lock(RecoverySemID, SEM_NUM_OF_RECOVERY_QUEUE);
+	/*
+	 * open recovery queue file
+	 */
+	RecoveryQueue.queue_fp = PGRget_recovery_queue_file_for_write();
+	if (RecoveryQueue.queue_fp == (FILE *)NULL)
+	{
+		return STATUS_ERROR;
+	}
+	fseek(RecoveryQueue.queue_fp,0,SEEK_END);
+	if (fwrite(header,sizeof(ReplicateHeader),1,RecoveryQueue.queue_fp) < 1)
+	{
+		PGRsem_unlock(RecoverySemID, SEM_NUM_OF_RECOVERY_QUEUE);
+		show_error("%s:recovery queue file header write error:(%s)",func,strerror(errno));
+		return STATUS_ERROR;
+	}
+	/*
+	 * set query data
+	 */
+	if (query_size > 0)
+	{
+		if (fwrite(query,query_size,1,RecoveryQueue.queue_fp) < 1)
+		{
+			PGRsem_unlock(RecoverySemID, SEM_NUM_OF_RECOVERY_QUEUE);
+			show_error("%s:recovery queue file query write error:(%s)",func,strerror(errno));
+			return STATUS_ERROR;
+		}
+	}
+	fflush(RecoveryQueue.queue_fp);
+	PGRsem_unlock(RecoverySemID, SEM_NUM_OF_RECOVERY_QUEUE);
+
+	return STATUS_OK;	
+}
+
+HostTbl *
+PGRget_HostTbl(char * hostName, int port)
+{
+	HostTbl * ptr = NULL;
+	int len = 0;
+
+	if (Host_Tbl_Begin == NULL)
+	{
+		return NULL;
+	}
+	len = strlen(hostName);
+	ptr = Host_Tbl_Begin;
+	if (len > sizeof(ptr->hostName))
+	{
+		len = sizeof(ptr->hostName);
+	}
+	while(ptr->useFlag != DATA_END)
+	{
+		if ((! memcmp(ptr->hostName,hostName,len)) &&
+			(ptr->port == port))
+		{
+			return ptr;
+		}
+		ptr ++;
+	}
+	return (HostTbl*)NULL;
+}
+
+static void
+sem_quit(int semid)
+{
+	semctl(semid, 0, IPC_RMID);
+}
+
+void
+PGRclear_transactions(void)
+{
+	TransactionTbl *t_ptr = (TransactionTbl*)NULL;
+	TransactionTbl *t_last = (TransactionTbl*)NULL;
+
+	t_ptr = Transaction_Tbl_Begin;
+	while (t_ptr != (TransactionTbl*)NULL)
+	{
+		if (t_ptr->conn != NULL)
+		{
+			PQfinish(t_ptr->conn);
+			t_ptr->conn = NULL;
+		}
+		t_last = t_ptr;
+		t_ptr = (TransactionTbl*)t_ptr->next;
+		free(t_last);
+		t_last = NULL;
+	}
+}
+
+void
+PGRclear_connections(int use_flag)
+{
+	TransactionTbl *t_ptr = (TransactionTbl*)NULL;
+	TransactionTbl *t_last = (TransactionTbl*)NULL;
+
+	t_ptr = PGconn_Tbl_Begin;
+	while (t_ptr != (TransactionTbl*)NULL)
+	{
+		if (t_ptr->useFlag != use_flag)
+		{
+			t_ptr = (TransactionTbl*)t_ptr->next;
+			continue;
+		}
+
+		if (t_ptr->conn != NULL)
+		{
+			PQfinish(t_ptr->conn);
+			t_ptr->conn = NULL;
+		}
+		t_last = t_ptr;
+		t_ptr = (TransactionTbl*)t_ptr->next;
+		free(t_last);
+		t_last = NULL;
+	}
+}
+
+static bool
+is_need_sync_time(ReplicateHeader * header)
+{
+	bool rtn = false;
+
+	if ((header->cmdSts == CMD_STS_QUERY ) &&
+		((header->cmdType == CMD_TYPE_INSERT) || 
+		 (header->cmdType == CMD_TYPE_UPDATE) || 
+		 (header->cmdType == CMD_TYPE_DELETE) || 
+		 (header->cmdType == CMD_TYPE_SET) || 
+		 (header->cmdType == CMD_TYPE_EXECUTE)))
+	{
+		rtn = true;	
+	}
+	else
+	{
+		if ((header->cmdType == CMD_TYPE_COPY) ||
+			(header->cmdType == CMD_TYPE_SELECT) ||
+			(header->cmdType == CMD_TYPE_BEGIN))
+		{
+			rtn = true;
+		}
+		if ((header->cmdSts == CMD_STS_TRANSACTION ) &&
+			(header->cmdType != CMD_TYPE_BEGIN))
+		{
+			rtn = false;
+		}
+	}
+	return rtn;
+}
+
+static bool
+is_need_wait_answer(ReplicateHeader * header)
+{
+	bool rtn = false;
+
+	if ((header->cmdType == CMD_TYPE_COPY) ||
+		(header->cmdType == CMD_TYPE_COPY_DATA) ||
+		(header->cmdType == CMD_TYPE_COPY_DATA_END))
+	{
+		rtn = false;
+	}
+	else if ((header->cmdSts == CMD_STS_QUERY ) &&
+		((header->cmdType == CMD_TYPE_INSERT) || 
+		 (header->cmdType == CMD_TYPE_UPDATE) || 
+		 (header->cmdType == CMD_TYPE_DELETE) || 
+		 (header->cmdType == CMD_TYPE_EXECUTE)))
+	{
+		rtn = true;
+	}
+	else if ((header->cmdSts == CMD_STS_TRANSACTION ) ||
+			(header->cmdSts == CMD_STS_SET_SESSION_AUTHORIZATION ) ||
+			(header->cmdSts == CMD_STS_TEMP_TABLE ) ||
+			(header->cmdType == CMD_TYPE_SELECT))
+	{
+		rtn = true;
+	}
+
+	return rtn;
+}
+
+static void
+delete_template(HostTbl * ptr, ReplicateHeader * header)
+{
+	if ((ptr == (HostTbl *)NULL ) ||
+		(header == (ReplicateHeader *)NULL) )
+	{
+		return;
+	}
+
+	if ((! strcmp(header->dbName,"template1")) ||
+		(! strcmp(header->dbName,"template0")))
+	{
+		if ((header->cmdSts == CMD_STS_QUERY)  ||
+			(header->cmdSts == CMD_STS_OTHER))
+		{
+			deletePGconnTbl(ptr,header);
+		}
+		else if (header->cmdSts == CMD_STS_NOTICE )
+		{
+			deleteTransactionTbl(ptr,header);
+		}
+	}
+}
+
+/*--------------------------------------------------------------------
+ * SYMBOL
+ *    check_copy_command()
+ * NOTES
+ *    check the query which it is copy command or not 
+ *    when the query is 'copy from', set 'stdin' after 'from' 
+ * ARGS
+ *    char * query: query strings(I)
+ * RETURN
+ *    copy command : changed copy command
+ *    other command : NULL
+ *--------------------------------------------------------------------
+ */
+static char *
+check_copy_command(char * query)
+{
+	char * p;
+	char * p1, *p2, *wp;
+	char * buf;
+	int size;
+
+	if (query == NULL)
+	{
+		return NULL;
+	}
+	size = strlen(query) + strlen("  stdin  ");
+	p = p1 = query;
+	wp = strstr(p,"FROM");
+	if (wp == NULL)
+		wp = strstr(p,"from");
+	
+	if (wp != NULL)
+	{
+		p = wp + strlen("FROM");
+		*p = '\0';
+		p ++;
+		while ((isspace(*p)) && (*p != '\0')) p++;
+		while ((!isspace(*p)) && (*p != '\0')) p++;
+		p2 = p;
+		buf = malloc(size);
+		if (buf == NULL)
+		{
+			return NULL;
+		}
+		snprintf(buf,size,"%s stdin %s",p1,p2);
+		return buf;
+	}
+	return NULL;
+}
+
+static int
+next_replication_id(void)
+{
+	char * func = "next_replication_id()";
+	uint32_t replication_id = 0;
+
+	if (Recovery_Status_Inf == (RecoveryStatusInf *)NULL)
+	{
+		show_error("%s: Recovery_Status_Inf is NULL",func);
+		return -1;
+	}
+	replication_id = (Recovery_Status_Inf->replication_id & PGR_GET_DATA_FILTER);
+	if (replication_id + 1 >= PGR_MAX_COUNTER)
+	{
+		if ((Recovery_Status_Inf->replication_id & PGR_GET_OVER_FLOW_FILTER) == 0)
+		{
+			Recovery_Status_Inf->replication_id = PGR_SET_OVER_FLOW;
+		}
+		else
+		{
+			Recovery_Status_Inf->replication_id = 0;
+		}
+		Recovery_Status_Inf->replication_id += PGR_MIN_COUNTER;
+	}
+	Recovery_Status_Inf->replication_id ++;
+	return (Recovery_Status_Inf->replication_id);
+}
+
+int
+PGRset_replication_id(uint32_t id)
+{
+	char * func = "set_replication_id()";
+	uint32_t replication_id = 0;
+
+	if (Recovery_Status_Inf == (RecoveryStatusInf *)NULL)
+	{
+		show_error("%s: Recovery_Status_Inf is NULL",func);
+		return -1;
+	}
+	replication_id = (id & PGR_GET_DATA_FILTER);
+	if (replication_id + 1 >= PGR_MAX_COUNTER)
+	{
+		if ((id & PGR_GET_OVER_FLOW_FILTER) == 0)
+		{
+			id = PGR_SET_OVER_FLOW;
+		}
+		else
+		{
+			id = 0;
+		}
+		id += PGR_MIN_COUNTER;
+	}
+	id ++;
+	Recovery_Status_Inf->replication_id = id;
+	return (Recovery_Status_Inf->replication_id);
+}
+
+int
+PGRdo_replicate(int sock,ReplicateHeader *header, char * query)
+{
+	char * func = "PGRdo_replicate()";
+	struct timeval tv;
+	int status = STATUS_OK;
+	int recovery_status = 0;
+	bool need_sync_time = false;
+	char * query_string = NULL;
+
+	if ((header->cmdSts == CMD_STS_COPY) &&
+		(header->cmdType == CMD_TYPE_COPY))
+	{
+		query_string = check_copy_command(query);
+		if (query_string == NULL)
+		{
+			return LOOP_CONTINUE;
+		}
+	}
+	else
+	{
+		query_string = query;
+		if (header->cmdType == CMD_TYPE_SET)
+		{
+			if (is_autocommit_off(query_string) == true)
+			{
+				PGR_AutoCommit = false;
+			}
+			else if (is_autocommit_on(query_string) == true)
+			{
+				PGR_AutoCommit = true;
+			}
+		}
+	}
+	gettimeofday(&tv,NULL);
+	header->tv.tv_sec = htonl(tv.tv_sec);
+	header->tv.tv_usec = htonl(tv.tv_usec);
+	need_sync_time = is_need_sync_time(header);
+	/* save header for logging */
+	if (need_sync_time == true)
+	{
+		if (PGR_Log_Header != NULL)
+		{
+			memcpy(PGR_Log_Header,header,sizeof(ReplicateHeader));
+			if (header->rlog == 0)
+			{
+				PGR_Log_Header->replicate_id = htonl(next_replication_id());
+			}
+		}
+	}
+	/* check rlog */
+	if (header->rlog == CONNECTION_SUSPENDED_TYPE )
+	{
+		if (PGRget_rlog_header(header) == STATUS_OK)
+		{
+			header->rlog = CONNECTION_SUSPENDED_TYPE;
+		}
+	}
+	
+	/* check recovery mode */
+	recovery_status = PGRget_recovery_status();
+	PGRcheck_recovered_host();
+	check_transaction_status(header,recovery_status);
+	if (PGRget_recovery_status() == RECOVERY_START)
+	{
+		PGRset_queue(header,query_string);
+	}
+
+	/* send replication packet */
+	status = PGRreplicate_packet_send( header,query_string,sock);
+
+	if ((header->cmdType == CMD_TYPE_COPY) &&
+		(query_string != NULL))
+	{
+		free(query_string);
+		query_string = NULL;
+		query = NULL;
+	}
+	if (status == STATUS_ABORTED )
+	{
+#ifdef PRINT_DEBUG
+		show_debug("%s:status is STATUS_ABORTED",func);
+#endif			
+		return LOOP_END;
+	}
+	if (status == STATUS_DEADLOCK_DETECT) 
+	{
+#ifdef PRINT_DEBUG
+		show_debug("%s:status is STATUS_DEADLOCK_DETECT",func);
+#endif			
+		return LOOP_END;
+	}
+	return LOOP_CONTINUE;
+}
+
+/*--------------------------------------------------------------------
+ * SYMBOL
+ *    PGRreturn_result()
+ * NOTES
+ *    Return result of execution 
+ * ARGS
+ *    int dest: socket of destination server (I)
+ *    int wait: wait flag (I)
+ * RETURN
+ *    OK: STATUS_OK
+ *    NG: STATUS_ERROR
+ *    NG: STATUS_LOCK_CONFLICT
+ *    NG: STATUS_DEADLOCK_DETECT
+ *--------------------------------------------------------------------
+ */
+int
+PGRreturn_result(int dest, int wait)
+{
+	char * func = "PGRreturn_result()";
+	fd_set	  wmask;
+	struct timeval timeout;
+	int rtn = 0;
+	char * send_ptr = NULL;
+	int send_size= 0;
+	int buf_size = 0;
+	int s = 0;
+	int status = 0;
+	int cnt = 0;
+	int flag = 0;
+	
+	if (PGR_Result == NULL)
+	{
+		show_error("%s:PGR_Result is not initialize",func);
+		return STATUS_ERROR;
+	}
+	if (dest < 0)
+	{
+		show_error("%s:destination socket is closed",func);
+		return STATUS_ERROR;
+	}
+	send_ptr = PGR_Result;
+	buf_size = PGR_MESSAGE_BUFSIZE;
+	if (buf_size < 1)
+	{
+		buf_size = 1;
+	}
+
+	timeout.tv_sec = PGR_SEND_TIMEOUT;
+	timeout.tv_usec = 0;
+
+	/*
+	 * Wait for something to happen.
+	 */
+#ifdef MSG_DONTWAIT
+	flag |= MSG_DONTWAIT;
+#endif
+#ifdef MSG_NOSIGNAL
+	flag |= MSG_NOSIGNAL;
+#endif
+	FD_ZERO(&wmask);
+	FD_SET(dest,&wmask);
+	rtn = select(dest+1, (fd_set *)NULL, &wmask, (fd_set *)NULL, &timeout);
+	if (rtn && FD_ISSET(dest, &wmask))
+	{
+#ifdef PRINT_DEBUG
+		show_debug("%s:PGRreturn_result[%s]",func,send_ptr);
+#endif			
+		for (;;)
+		{
+			s = send(dest,send_ptr + send_size,buf_size - send_size ,flag); 
+			if (s < 0){
+				show_error("%s:send error: %d(%s)",func,errno,strerror(errno));
+				if (errno == EINTR)
+				{
+					usleep(PGR_SEND_WAIT_MSEC);
+				}
+#ifdef EPIPE
+				if (errno == EPIPE)
+				{
+					memset(send_ptr, 0, PGR_MESSAGE_BUFSIZE);
+					return STATUS_ABORTED;
+				}
+#endif /* EPIPE */
+#ifdef EHOSTUNREACH
+				if (errno == EHOSTUNREACH)
+				{
+					memset(send_ptr, 0, PGR_MESSAGE_BUFSIZE);
+					return STATUS_ABORTED;
+				}
+#endif /* EHOSTUNREACH */
+#ifdef ENOTSOCK
+				if (errno == ENOTSOCK)
+				{
+					memset(send_ptr, 0, PGR_MESSAGE_BUFSIZE);
+					return STATUS_ABORTED;
+				}
+#endif /* ENOTSOCK */
+				if (cnt < PGR_SEND_RETRY_CNT )
+				{
+					cnt ++;
+					usleep(PGR_SEND_WAIT_MSEC);
+					continue;
+				}
+				else
+				{
+					memset(send_ptr, 0, PGR_MESSAGE_BUFSIZE);
+					return STATUS_ERROR;
+				}
+			}
+			if (s > 0)
+			{
+				send_size += s;
+				if (send_size == buf_size)
+				{
+					status = STATUS_OK;
+					if (wait == PGR_WAIT_ANSWER)
+					{
+#ifdef PRINT_DEBUG
+						show_debug("%s:wait for answer",func);
+#endif			
+						status = read_answer(dest);
+					}
+#ifdef PRINT_DEBUG
+					show_debug("%s:status of PGRreturn_result[%d]",func,status);
+#endif			
+					return status;
+				}
+			}
+			usleep(PGR_SEND_WAIT_MSEC);
+			if (flag != 0)
+			{
+				if (cnt < PGR_SEND_RETRY_CNT )
+				{
+					cnt ++;
+					usleep(PGR_SEND_WAIT_MSEC);
+					continue;
+				}
+				else
+				{
+					memset(send_ptr, 0, PGR_MESSAGE_BUFSIZE);
+					return STATUS_ERROR;
+				}
+			}
+		}
+	}
+	memset(send_ptr, 0, PGR_MESSAGE_BUFSIZE);
+	return STATUS_ERROR;
+}
+
+/*--------------------------------------------------------------------
+ * SYMBOL
+ *    read_answer()
+ * NOTES
+ *    Receive answer packet
+ * ARGS
+ *    int dest: socket of destination server (I)
+ * RETURN
+ *    OK: STATUS_OK
+ *    NG: STATUS_ERROR
+ *    NG: STATUS_LOCK_CONFLICT
+ *    NG: STATUS_DEADLOCK_DETECT
+ *--------------------------------------------------------------------
+ */
+static int
+read_answer(int dest)
+{
+	char * func = "read_answer()";
+	fd_set	  rmask;
+	struct timeval timeout;
+	int rtn;
+	ReplicateHeader header;
+	char * answer = NULL;
+	int status = STATUS_ERROR;
+
+	for(;;)
+	{
+		if (answer != NULL)
+		{
+			free(answer);
+			answer = NULL;
+		}
+		timeout.tv_sec = PGR_RECV_TIMEOUT;
+		timeout.tv_usec = 0;
+		FD_ZERO(&rmask);
+		FD_SET(dest,&rmask);
+		rtn = select(dest+1, &rmask, (fd_set *)NULL, (fd_set *)NULL, &timeout);
+		if (rtn && FD_ISSET(dest, &rmask))
+		{
+			memset(&header,0,sizeof(ReplicateHeader));
+			answer = PGRread_packet(dest,&header);
+			if (answer == NULL)
+			{
+				status = STATUS_ERROR;
+				break;
+			}
+			if ((header.cmdSts != CMD_STS_RESPONSE) && 
+				(header.cmdSts != CMD_STS_NOTICE))
+			{
+				show_error("%s:none response packet received",func);
+				free(answer);
+				answer = NULL;
+				status = STATUS_ERROR;
+				break;
+			}
+#ifdef PRINT_DEBUG
+			show_debug("answer[%s]",answer);
+#endif			
+			if (answer != NULL)
+			{
+				if (!strncmp(answer,PGR_QUERY_DONE_NOTICE_CMD,strlen(PGR_QUERY_DONE_NOTICE_CMD)))
+				{
+#ifdef PRINT_DEBUG
+					show_debug("%s:QUERY DONE",func);
+#endif			
+					status = STATUS_OK;
+				}
+				else if (!strncmp(answer,PGR_QUERY_ABORTED_NOTICE_CMD,strlen(PGR_QUERY_ABORTED_NOTICE_CMD)))
+				{
+#ifdef PRINT_DEBUG
+					show_debug("%s:QUERY ABORTED",func);
+#endif			
+					status = STATUS_ABORTED;
+				}
+				else if (!strncmp(answer,PGR_LOCK_CONFLICT_NOTICE_CMD,strlen(PGR_LOCK_CONFLICT_NOTICE_CMD)))
+				{
+#ifdef PRINT_DEBUG
+					show_debug("%s:LOCK CONFLICT !!",func);
+#endif			
+					status = STATUS_LOCK_CONFLICT;
+				}
+				else if (!strncmp(answer,PGR_DEADLOCK_DETECT_NOTICE_CMD,strlen(PGR_DEADLOCK_DETECT_NOTICE_CMD)))
+				{
+#ifdef PRINT_DEBUG
+					show_debug("%s:DEADLOCK DETECT !!",func);
+#endif			
+					status = STATUS_DEADLOCK_DETECT;
+				}
+				free(answer);
+				answer = NULL;
+			}
+			return status;
+		}
+	}
+	return status;
+}
+
+/*--------------------------------------------------
+ * SYMBOL
+ *     PGRreplicate_packet_send()
+ * NOTES
+ *     Send query to each cluster DB servers and return result.
+ * ARGS 
+ *     ReplicateHeader * header : packet header (I)
+ *     char * query : query for replication (I)
+ *     int dest : destination socket for return result (I)
+ * RETURN
+ *     OK : STATUS_OK
+ *     NG : STATUS_ERROR
+ *     DEADLOCK : STATUS_DEADLOCK_DETECT
+ *---------------------------------------------------
+ */
+int
+PGRreplicate_packet_send( ReplicateHeader * header, char * query,int dest)
+{
+	char *func = "PGRreplicate_packet_send()";
+	HostTbl * host_ptr = (HostTbl*)NULL;
+	HostTbl * source_host_ptr = (HostTbl*)NULL;
+	int rtn = 0;
+	int status = STATUS_OK;
+	int sem_no = 0;
+	int sem_id = 0;
+	pthread_t thread[MAX_DB_SERVER];
+	pthread_attr_t attr;
+	int rc = 0;
+	int t = 0;
+	int t_cnt = 0;
+	ThreadArgInf thread_arg[MAX_DB_SERVER];
+
+	bool abort_test_flag;
+	abort_test_flag = false;
+
+#ifdef PRINT_DEBUG
+	show_debug("%s:cmdSts=%c",func,header->cmdSts);
+	show_debug("%s:cmdType=%c",func,header->cmdType);
+	show_debug("%s:rlog=%d",func,header->rlog);
+	show_debug("%s:request_id=%d",func,ntohl(header->request_id));
+	show_debug("%s:replicate_id=%d",func,ntohl(header->replicate_id));
+	show_debug("%s:port=%d",func,ntohs(header->port));
+	show_debug("%s:pid=%d",func,ntohs(header->pid));
+	show_debug("%s:from_host=%s",func,header->from_host);
+	show_debug("%s:dbName=%s",func,header->dbName);
+	show_debug("%s:userName=%s",func,header->userName);
+	show_debug("%s:recieve sec=%u",func,ntohl(header->tv.tv_sec));
+	show_debug("%s:recieve usec=%u",func,ntohl(header->tv.tv_usec));
+	show_debug("%s:query_size=%d",func,ntohl(header->query_size));
+	show_debug("%s:query=%s",func,query);
+#endif			
+
+	/* check rlog type */
+	if (header->rlog > 0)
+	{
+		if (header->rlog == FROM_R_LOG_TYPE)
+		{
+			if (is_executed_query_in_origin(header) == false)
+			{
+#ifdef PRINT_DEBUG
+				show_debug("this query is not yet done in source cluster db. so it wait for receive re-replicate request");
+#endif
+				/* wait re-replicate request */
+				return STATUS_SKIP_REPLICATE;
+			}
+		}
+	}
+	/*
+	 * loop while registrated cluster DB exist 
+	 */
+	if (Host_Tbl_Begin == NULL)
+	{
+		return STATUS_ERROR;
+	}
+	host_ptr = Host_Tbl_Begin;
+	PGR_Response_Inf->current_cluster = 0;
+	memset(PGR_Result,0,PGR_MESSAGE_BUFSIZE);
+
+	sem_id = SemID;
+	sem_no = 1;
+#ifdef PRINT_DEBUG
+	show_debug("sem_lock[%d]",sem_no);
+#endif			
+	PGRsem_lock(sem_id,sem_no);
+
+	/* set replication log */
+	if (is_need_use_rlog(header) == true)
+	{
+		PGRset_rlog(header,query);
+	}
+
+	pthread_attr_init(&attr);
+	pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+	PGR_Response_Inf->current_cluster = 0;
+	t_cnt = 0;
+	while(host_ptr->useFlag != DATA_END)
+	{
+		/*
+		 * check the status of the cluster DB
+		 */
+		if ((host_ptr->useFlag != DATA_USE) &&
+			(host_ptr->useFlag != DATA_NEW))
+		{
+			host_ptr ++;
+			continue;
+		}
+		/*
+		 * skip loop during recover and the host name is master DB
+		 */
+		if (is_master_in_recovery(host_ptr->hostName, host_ptr->port) == true)
+		{
+			host_ptr ++;
+			continue;
+		}
+#ifdef INSERT_ABORT_TEST
+		if ((header->cmdSts == CMD_STS_QUERY) &&
+			(header->cmdType == CMD_TYPE_INSERT))
+		{
+			if (t_cnt >= 1)
+			{
+				abort_test_flag = true;
+				break;
+			}
+		}
+#endif
+#ifdef COMMIT_ABORT_TEST
+		if ((header->cmdSts == CMD_STS_TRANSACTION) &&
+			(header->cmdType == CMD_TYPE_COMMIT))
+		{
+			if (t_cnt >= 1)
+			{
+				abort_test_flag = true;
+				break;
+			}
+		}
+#endif
+		/*
+		 *  compare with the host name and the exceptional host name
+		 */
+		thread_arg[t_cnt].header = header;
+		thread_arg[t_cnt].query = query;
+		thread_arg[t_cnt].dest = dest;
+		thread_arg[t_cnt].host_ptr = host_ptr;
+		if (PGRis_same_host(header->from_host,ntohs(header->port),host_ptr->hostName, host_ptr->port) == true)
+		{
+			/* replication to source cluster db */
+			source_host_ptr = host_ptr;
+			if (header->rlog != FROM_R_LOG_TYPE )
+			{
+				rc = pthread_create(&thread[t_cnt], &attr, thread_send_source, (void*)&thread_arg[t_cnt]);
+				t_cnt ++;
+			}
+			else
+			{
+#ifdef PRINT_DEBUG
+				show_debug("%s: This simple query was suspended. Therefore this query is not re-replicated to source cluster db.",func);
+#endif			
+			}
+		}
+		else
+		{
+			/* replication to other cluster db */
+			if ((header->rlog == CONNECTION_SUSPENDED_TYPE ) &&
+				(header->cmdSts == CMD_STS_TRANSACTION) )
+			{
+#ifdef PRINT_DEBUG
+				show_debug("%s: This transaction query was suspended. Therefore this query is not replicated to other cluster dbs.",func);
+#endif			
+			}
+			else
+			{
+				rc = pthread_create(&thread[t_cnt], &attr, thread_send_cluster, (void*)&thread_arg[t_cnt]);
+				t_cnt ++;
+			}
+		}
+		if (rc)
+		{
+			show_error("pthread_create error");
+		}
+		/*
+		 * send replication query to each cluster server
+		 */
+
+		host_ptr ++;
+		PGR_Response_Inf->current_cluster ++;
+		status = STATUS_OK;
+	}	
+	pthread_attr_destroy(&attr);
+	for ( t = 0 ; t < t_cnt; t ++)
+	{
+		rc = pthread_join(thread[t], (void **)&status);
+		pthread_detach(thread[t]);
+	}
+
+#ifdef INSERT_ABORT_TEST
+	if (abort_test_flag)
+	{
+		PGRsem_unlock(sem_id,sem_no);
+		PGRstop_pgreplicate(SIGINT);
+	}
+#endif
+#ifdef COMMIT_ABORT_TEST
+	if (abort_test_flag)
+	{
+		PGRsem_unlock(sem_id,sem_no);
+		PGRstop_pgreplicate(SIGINT);
+	}
+#endif
+
+	/* unset replication log */
+	if (is_need_use_rlog(header) == true)
+	{
+		PGRunset_rlog(header,query);
+	}
+
+#ifdef PRINT_DEBUG
+	show_debug("sem_unlock[%d]",sem_no);
+#endif			
+	PGRsem_unlock(sem_id,sem_no);
+	if ((header->cmdType != CMD_TYPE_COPY)  &&
+		(header->cmdType != CMD_TYPE_COPY_DATA) &&
+		(header->cmdType != CMD_TYPE_COPY_DATA_END) &&
+		(PGR_Response_Inf->response_mode == PGR_RELIABLE_MODE))
+	{
+		snprintf(PGR_Result,PGR_MESSAGE_BUFSIZE,"%d", PGR_RELIABLE_MODE_DONE_FUNC_NO);
+		rtn = PGRreturn_result(dest,PGR_NOWAIT_ANSWER);
+		if (source_host_ptr != NULL)
+		{
+			check_delete_transaction(source_host_ptr,header);
+		}
+	}
+	return status;
+}
+
+static void *
+thread_send_source(void * arg)
+{
+	char * func = "thread_send_source()";
+	ThreadArgInf * thread_arg = NULL;
+	ReplicateHeader * header = (ReplicateHeader*)NULL;
+	char * query = NULL;
+	int dest = 0;
+	HostTbl * host_ptr = (HostTbl*)NULL;
+	int status = STATUS_OK;
+
+	if ((PGR_Result == NULL) || (arg == NULL))
+	{
+		show_error("%s:PGR_Result is not initialize",func);
+		status = STATUS_ERROR;
+		pthread_exit((void *) status);
+	}
+	thread_arg = (ThreadArgInf *)arg;
+	header = thread_arg->header;
+	query = thread_arg->query;
+	dest = thread_arg->dest;
+	host_ptr = thread_arg->host_ptr;
+
+	if (header->rlog == FROM_R_LOG_TYPE )
+	{
+		/* It is not necessary to return rlog to source DB. */
+#ifdef PRINT_DEBUG
+	show_debug("%s: It is not necessary to return rlog to source DB",func);
+#endif
+		status = STATUS_OK;
+		pthread_exit((void *) status);
+	}
+
+	memset (PGR_Result,0,PGR_MESSAGE_BUFSIZE);
+	if (is_need_sync_time(header) == true)
+	{
+		snprintf(PGR_Result,PGR_MESSAGE_BUFSIZE,
+			"%d,%u,%u,%u,%d", 
+			PGR_SET_CURRENT_TIME_FUNC_NO,
+			(unsigned int)ntohl(header->tv.tv_sec),
+			(unsigned int)ntohl(header->tv.tv_usec),
+			(unsigned int)ntohl(PGR_Log_Header->replicate_id),
+			PGR_Response_Inf->response_mode);
+	}
+	/* execute query in the exceptional host */
+	/* it is not use replication */
+	if (is_need_wait_answer(header) == true)
+	{
+		status = PGRreturn_result(dest, PGR_WAIT_ANSWER);
+	}
+	else
+	{
+		status = PGRreturn_result(dest, PGR_NOWAIT_ANSWER);
+	}
+	if (status == STATUS_ERROR )
+	{
+		show_error("%s: %s[%d] should be down ",func,host_ptr->hostName,host_ptr->port);
+		PGRset_host_status(host_ptr,DATA_ERR);
+	}
+	else if (status == STATUS_ABORTED)
+	{
+		snprintf(PGR_Result,PGR_MESSAGE_BUFSIZE,"%d", PGR_NOTICE_ABORT_FUNC_NO);
+		status = PGRreturn_result(dest, PGR_NOWAIT_ANSWER);
+		status = STATUS_ABORTED;
+		pthread_exit((void *) status);
+	}
+	/* delete server table when query use template db */
+	if (PGR_Response_Inf->response_mode != PGR_RELIABLE_MODE)
+	{
+		delete_template(host_ptr,header);
+	}
+	pthread_exit((void *) 0);
+}
+
+static void *
+thread_send_cluster(void * arg)
+{
+	char * func = "thread_send_cluster()";
+	ThreadArgInf * thread_arg = NULL;
+	ReplicateHeader * header = (ReplicateHeader*)NULL;
+	char * query = NULL;
+	int dest = 0;
+	HostTbl * host_ptr = (HostTbl*)NULL;
+	int rtn = 0;
+	int status = STATUS_OK;
+
+	if ((PGR_Result == NULL) || (arg == NULL))
+	{
+		show_error("%s:PGR_Result is not initialize",func);
+		status = STATUS_ERROR;
+		pthread_exit((void *) status);
+	}
+	thread_arg = (ThreadArgInf *)arg;
+	header = thread_arg->header;
+	query = thread_arg->query;
+	dest = thread_arg->dest;
+	host_ptr = thread_arg->host_ptr;
+	/*
+	 * send replication query to each cluster server
+	 */
+	rtn = PGRreplicate_packet_send_each_server( host_ptr, false, header, query, dest);
+	if (rtn == STATUS_ABORTED)
+	{
+		snprintf(PGR_Result,PGR_MESSAGE_BUFSIZE,"%d", PGR_NOTICE_ABORT_FUNC_NO);
+		status = PGRreturn_result(dest, PGR_NOWAIT_ANSWER);
+		status = STATUS_ABORTED;
+		pthread_exit((void *) status);
+	}
+	/* delete server table when query use template db */
+	delete_template(host_ptr,header);
+
+	pthread_exit((void *) 0);
+}
+
+/*--------------------------------------------------
+ * SYMBOL
+ *     PGRreplicate_packet_send_each_server()
+ * NOTES
+ *     Send query to a cluster DB server and return result.
+ * ARGS 
+ *     HostTbl * ptr : cluster server info table (I)
+ *     bool return_response : flag for return result(I)
+ *     ReplicateHeader * header: header data (I)
+ *     char * query : query data (I)
+ *     int dest : socket of destination server(I)
+ * RETURN
+ *     OK : STATUS_OK
+ *     NG : STATUS_ERROR
+ *---------------------------------------------------
+ */
+int
+PGRreplicate_packet_send_each_server( HostTbl * ptr, bool return_response, ReplicateHeader * header, char * query,int dest)
+{
+	char * func = "PGRreplicate_packet_send_each_server()";
+	char * host;
+	int rtn;
+
+	host = ptr->hostName;
+	/*
+	 * send query to cluster DB
+	 */
+	if (PGR_Result == NULL)
+	{
+		show_error("%s:PGR_Result is not initialize",func);
+		return STATUS_ERROR;
+	}
+
+	rtn = PGRsend_replicate_packet_to_server( ptr, header,query,PGR_Result, dest);
+
+	return rtn;
+}
+
+/*--------------------------------------------------
+ * SYMBOL
+ *     PGRread_packet()
+ * NOTES
+ *     Read packet data and send the query to each cluster DB.
+ *     The packet data has header data and query data.
+ * ARGS 
+ *     int sock : socket (I)
+ *     ReplicateHeader *header : header data (O)
+ * RETURN
+ *     OK: pointer of read query
+ *     NG: NULL
+ *---------------------------------------------------
+ */
+char *
+PGRread_packet(int sock, ReplicateHeader *header)
+{
+	char * func = "PGRread_packet()";
+	int r =0;
+	int cnt = 0;
+	char * read_ptr = NULL;
+	int read_size = 0;
+	int header_size = 0;
+	char * query = NULL;
+
+	if (header == NULL)
+	{
+		return NULL;
+	}
+	memset(header,0,sizeof(ReplicateHeader));
+	read_ptr = (char*)header;
+	header_size = sizeof(ReplicateHeader);
+	cnt = 0;
+	for (;;){
+		/*
+		 * read header data
+		 */
+		r = recv(sock,read_ptr + read_size ,header_size - read_size, MSG_WAITALL);
+		/*
+		r = recv(sock,read_ptr + read_size ,header_size - read_size, 0);
+		*/
+		if (r < 0)
+		{
+			if (errno == EINTR)
+			{
+				usleep(PGR_RECV_WAIT_MSEC);
+			}
+#ifdef EPIPE
+			if (errno == EPIPE)
+			{
+				show_error("%s:recv failed: (%s)",func,strerror(errno));
+				return NULL;
+			}
+#endif /* EPIPE */
+#ifdef EHOSTUNREACH
+			if (errno == EHOSTUNREACH)
+			{
+				show_error("%s:recv failed: (%s)",func,strerror(errno));
+				return NULL;
+			}
+#endif /* EHOSTUNREACH */
+#ifdef ENOTSOCK
+			if (errno == ENOTSOCK)
+			{
+				show_error("%s:recv failed: (%s)",func,strerror(errno));
+				return NULL;
+			}
+#endif /* ENOTSOCK */
+			if (cnt < PGR_RECV_RETRY_CNT )
+			{
+				cnt ++;
+				usleep(PGR_RECV_WAIT_MSEC);
+				continue;
+			}
+			else
+			{
+				show_error("%s:recv failed: (%s)",func,strerror(errno));
+				return NULL;
+			}
+		}
+		if (r > 0)
+		{
+			read_size += r;
+			if ( read_size == header_size)
+			{
+				query = PGRread_query(sock,header);
+				return query;
+			}
+		}
+		/* if ((r == 0) && (read_size == 0)) */
+		if (r == 0)
+		{
+			return NULL;
+		}
+		if (cnt < PGR_RECV_RETRY_CNT )
+		{
+			cnt ++;
+			usleep(PGR_RECV_WAIT_MSEC);
+			continue;
+		}
+		else
+		{
+			return NULL;
+		}
+	}
+}
+
+char *
+PGRread_query(int sock, ReplicateHeader *header)
+{
+	char * func = "PGRread_query()";
+	int r =0;
+	int cnt = 0;
+	char * read_ptr;
+	int read_size = 0;
+	int query_size = 0;
+	char * query = NULL;
+
+	query_size = ntohl(header->query_size);
+	if (query_size < 0)
+	{
+		show_error("%s:receive size less than 0",func);
+		return NULL;
+	}
+	query = malloc(query_size+4);
+	if (query == NULL)
+	{
+		/*
+		 * buffer allocation failed
+		 */
+		show_error("%s:malloc failed: (%s)",func,strerror(errno));
+		return NULL;
+	}
+	memset(query,0,query_size+4);
+	if (query_size == 0)
+	{
+		return query;
+	}
+	read_size = 0;
+	cnt = 0;
+	read_ptr = (char *)query;
+	for (;;){
+		/*
+		 * read query data
+		 */
+
+		/*r = recv(sock,read_ptr + read_size ,query_size - read_size, MSG_WAITALL); */
+		r = recv(sock,read_ptr + read_size ,query_size - read_size, 0); 
+		if (r < 0)
+		{
+			if (errno == EINTR)
+			{
+				usleep(PGR_RECV_WAIT_MSEC);
+				continue;
+			}
+#ifdef EPIPE
+			if (errno == EPIPE)
+			{
+				free(query);
+				query = NULL;
+				return NULL;
+			}
+#endif /* EPIPE */
+#ifdef EHOSTUNREACH
+			if (errno == EHOSTUNREACH)
+			{
+				free(query);
+				query = NULL;
+				return NULL;
+			}
+#endif /* EHOSTUNREACH */
+#ifdef ENOTSOCK
+			if (errno == ENOTSOCK)
+			{
+				free(query);
+				query = NULL;
+				return NULL;
+			}
+#endif /* ENOTSOCK */
+			if (cnt < PGR_RECV_RETRY_CNT )
+			{
+				cnt ++;
+				usleep(PGR_RECV_WAIT_MSEC);
+				continue;
+			}
+			else
+			{
+				free(query);
+				query = NULL;
+				return NULL;
+			}
+		}
+		if (r > 0)
+		{
+			read_size += r;
+			if ( read_size == query_size)
+			{
+				return query;
+			}
+		}
+		if ((r == 0 ) && (read_size == 0))
+		{
+			free(query);
+			query = NULL;
+			return NULL;
+		}
+		if (cnt < PGR_RECV_RETRY_CNT )
+		{
+			cnt ++;
+			usleep(PGR_RECV_WAIT_MSEC);
+			continue;
+		}
+		else
+		{
+			free(query);
+			query = NULL;
+			return NULL;
+		}
+	}
+	free(query);
+	query = NULL;
+	return NULL;
+}
+
+static bool
+is_autocommit_off(char * query)
+{
+	int i;
+	char buf[PGR_MESSAGE_BUFSIZE];
+	char * p = NULL;
+
+	if (query == NULL)
+	{
+		return false;
+	}
+	memset(buf,0,sizeof(buf));
+	p = query;
+	i = 0;
+	while ( *p != '\0' )
+	{
+		buf[i++] = toupper(*p);
+		p++;
+		if (i >= (sizeof(buf) -2))
+			break;
+	}
+	p = strstr(buf,"AUTOCOMMIT");
+	if ( p == NULL)
+	{
+		return false;
+	}
+	p = strstr(buf,"OFF");
+	if ( p == NULL )
+	{
+		return false;
+	}
+	return true;
+}
+
+static bool
+is_autocommit_on(char * query)
+{
+	int i;
+	char buf[PGR_MESSAGE_BUFSIZE];
+	char * p = NULL;
+
+	if (query == NULL)
+	{
+		return false;
+	}
+	memset(buf,0,sizeof(buf));
+	p = query;
+	i = 0;
+	while ( *p != '\0' )
+	{
+		buf[i++] = toupper(*p);
+		p++;
+		if (i >= (sizeof(buf) -2))
+			break;
+	}
+	p = strstr(buf,"AUTOCOMMIT");
+	if ( p == NULL)
+	{
+		return false;
+	}
+	p = strstr(buf,"ON");
+	if ( p == NULL )
+	{
+		return false;
+	}
+	return true;
+}
+
+static unsigned int 
+get_host_ip_from_tbl(char * host)
+{
+	TransactionTbl * ptr = NULL;
+
+	if (Transaction_Tbl_Begin == (TransactionTbl *) NULL)
+	{
+		return 0;
+	}
+	ptr = Transaction_Tbl_Begin;
+	while (ptr != NULL)
+	{
+		if (!strncmp(ptr->host,host,sizeof(ptr->host)))
+		{
+			return ptr->hostIP;
+		}
+		ptr = (TransactionTbl*)ptr->next;
+	}
+	return 0;
+}
+
+static unsigned int 
+get_srcHost_ip_from_tbl(char * srcHost)
+{
+	TransactionTbl * ptr = NULL;
+
+	if (Transaction_Tbl_Begin == (TransactionTbl *) NULL)
+	{
+		return 0;
+	}
+	ptr = Transaction_Tbl_Begin;
+	while (ptr != NULL)
+	{
+		if (!strncmp(ptr->srcHost,srcHost,sizeof(ptr->srcHost)))
+		{
+			return ptr->srcHostIP;
+		}
+		ptr = (TransactionTbl*)ptr->next;
+	}
+	return 0;
+}
+
+unsigned int
+PGRget_next_query_id(void)
+{
+	if (PGR_Query_ID >= PGR_MAX_QUERY_ID)
+	{
+		PGR_Query_ID = 0;
+	}
+	PGR_Query_ID ++;
+	return PGR_Query_ID;
+}
+
+/*
+ * sync oid during cluster DB's 
+ */
+int
+PGRsync_oid(ReplicateHeader *header)
+{
+	HostTbl * host_ptr = (HostTbl*)NULL;
+	uint32_t max_oid = 0;
+	uint32_t oid = 0;
+
+	/* get current oid of all cluster db's */
+	host_ptr = Host_Tbl_Begin;
+	if (host_ptr == (HostTbl *)NULL)
+	{
+		return STATUS_ERROR;
+	}
+	while(host_ptr->useFlag != DATA_END)
+	{
+		/*
+		 * check the status of the cluster DB
+		 */
+		if (host_ptr->useFlag != DATA_USE)
+		{
+			host_ptr ++;
+			continue;
+		}
+		/*
+		 * skip loop during recover and the host name is master DB
+		 */
+		if (is_master_in_recovery(host_ptr->hostName, host_ptr->port) == true)
+		{
+			host_ptr ++;
+			continue;
+		}
+		oid = get_oid(host_ptr,header);
+		if (max_oid < oid )
+		{
+			max_oid = oid;
+		}
+		host_ptr ++;
+	}
+	if (max_oid <= 0)
+		return STATUS_ERROR;
+	
+	/* set oid in cluster db */
+	host_ptr = Host_Tbl_Begin;
+	while(host_ptr->useFlag != DATA_END)
+	{
+		/*
+		 * check the status of the cluster DB
+		 */
+		if (host_ptr->useFlag != DATA_USE)
+		{
+			host_ptr ++;
+			continue;
+		}
+		/*
+		 * skip loop during recover and the host name is master DB
+		 */
+		if (is_master_in_recovery(host_ptr->hostName, host_ptr->port) == true)
+		{
+			host_ptr ++;
+			continue;
+		}
+		set_oid(host_ptr,header,max_oid);
+		host_ptr ++;
+	}
+
+	return STATUS_OK;
+}
+
+static int 
+send_func(HostTbl * host_ptr,ReplicateHeader * header, char * func,char * result)
+{
+	char * f ="send_func()";
+	char	   *database = NULL;
+	char	   port[8];
+	char	   *userName = NULL;
+	char * host = NULL;
+	char * str = NULL;
+	TransactionTbl * transaction_tbl = (TransactionTbl *)NULL;
+	PGresult * res = (PGresult *)NULL;
+	PGconn * conn = (PGconn *)NULL;
+	int rtn = 0;
+	int current_cluster = 0;
+
+	if ((host_ptr == (HostTbl *)NULL)		||
+		(header == (ReplicateHeader *)NULL)	||
+		(func == NULL)						||
+		(result == NULL))
+	{
+		return STATUS_ERROR;
+	}
+	/*
+	 * set up the connection
+	 */
+	database = (char *)header->dbName;
+	snprintf(port,sizeof(port),"%d", host_ptr->port);
+	userName = (char *)header->userName;
+	host = host_ptr->hostName;
+	if (PGR_Response_Inf != NULL)
+	{
+		current_cluster = PGR_Response_Inf->current_cluster;
+	}
+
+	/*
+	 * get the transaction table data
+	 * it has the connection data with each cluster DB
+	 */
+	transaction_tbl = getTransactionTbl(host_ptr,header);
+	/*
+	 * if the transaction process is new one, 
+	 * create connection data and add the transaction table
+	 */
+	if (transaction_tbl == (TransactionTbl *)NULL)
+	{
+		transaction_tbl = setTransactionTbl(host_ptr, header);
+		if (transaction_tbl == (TransactionTbl *)NULL)
+		{
+			show_error("%s:setTransactionTbl failed",f);
+			if ( header->cmdSts != CMD_STS_NOTICE )
+			{
+				PGRset_host_status(host_ptr,DATA_ERR);
+			}
+			return STATUS_ERROR;
+		}
+		StartReplication[current_cluster] = true;
+	}
+	else
+	{
+		/*
+		 * re-use the connection data
+		 */
+		if ((transaction_tbl->conn != (PGconn *)NULL) &&
+			(transaction_tbl->conn->sock > 0))
+		{
+			StartReplication[current_cluster] = false;
+		}
+		else
+		{
+			PQfinish(transaction_tbl->conn);
+		 	transaction_tbl->conn = pgr_createConn(host,port,database,userName);
+			StartReplication[current_cluster] = true;
+		}
+	}
+	conn = transaction_tbl->conn;
+
+	if (conn == NULL)
+	{
+		show_error("%s:[%d@%s] may be down",f,host_ptr->port,host_ptr->hostName);
+		if ( header->cmdSts != CMD_STS_NOTICE )
+		{
+			PGRset_host_status(host_ptr,DATA_ERR);
+		}
+		return STATUS_ERROR;
+	}
+	res = PQexec(conn, func);
+	if (res == NULL)
+	{
+		StartReplication[current_cluster] = true;
+		return STATUS_ERROR;
+	}
+	str = PQcmdStatus(res);
+	if ((str == NULL) || (*str == '\0'))
+	{
+		rtn = STATUS_ERROR;
+	}
+	else
+	{
+		snprintf(result, PGR_MESSAGE_BUFSIZE, "%s",str);
+		rtn = STATUS_OK;
+	}
+	if (res != NULL)
+		PQclear(res);
+	return rtn;	
+}
+
+static uint32_t
+get_oid(HostTbl * host_ptr,ReplicateHeader * header)
+{
+	char * func = "get_oid()";
+	char sync_command[PGR_MESSAGE_BUFSIZE];
+	char result[PGR_MESSAGE_BUFSIZE];
+
+	memset(result,0,sizeof(result));
+	snprintf(sync_command,sizeof(sync_command),
+		"SELECT %s(%d)",
+		PGR_SYSTEM_COMMAND_FUNC, PGR_GET_OID_FUNC_NO);
+#ifdef PRINT_DEBUG
+	show_debug("%s:sync_command(%s)",func,sync_command);
+#endif			
+
+	if (send_func(host_ptr, header, sync_command, result) == STATUS_OK)
+	{
+		return (strtoul(result, NULL, 10));
+	}
+	return 0;
+}
+
+static int
+set_oid(HostTbl * host_ptr,ReplicateHeader * header, uint32_t oid)
+{
+	char * func = "set_oid()";
+	char sync_command[PGR_MESSAGE_BUFSIZE];
+	char result[PGR_MESSAGE_BUFSIZE];
+
+	memset(result,0,sizeof(result));
+	snprintf(sync_command,sizeof(sync_command),
+		"SELECT %s(%d,%u)",
+		PGR_SYSTEM_COMMAND_FUNC, 
+		PGR_SET_OID_FUNC_NO,
+		oid);
+#ifdef PRINT_DEBUG
+	show_debug("%s:sync_command(%s)",func,sync_command);
+#endif			
+	return ( send_func(host_ptr, header, sync_command, result) );
+}
+
+void
+PGRnotice_replication_server(char * hostName, unsigned short portNumber,unsigned short recoveryPortNumber, unsigned short lifecheckPortNumber, char * userName)
+{
+	char * func ="PGRnotice_replication_server()";
+	ReplicateHeader  header;
+	char query[PGR_MESSAGE_BUFSIZE];
+
+	if (((hostName == NULL) || (*hostName == 0)) ||
+		((userName == NULL) || (*userName == 0)) ||
+		((portNumber == 0) || (recoveryPortNumber == 0)))
+	{
+#ifdef PRINT_DEBUG
+		show_debug("%s: can not connect server[%s]",func,hostName);
+#endif			
+		return;
+	}
+	memset(&header,0,sizeof(ReplicateHeader));
+	memset(query,0,sizeof(query));
+	snprintf(query,sizeof(query)-1,"SELECT %s(%d,'%s',%d,%d,%d)",
+			PGR_SYSTEM_COMMAND_FUNC,
+			PGR_STARTUP_REPLICATION_SERVER_FUNC_NO,
+			hostName,
+			portNumber,
+			recoveryPortNumber,
+			lifecheckPortNumber);
+	header.cmdSys = CMD_SYS_CALL;
+	header.cmdSts = CMD_STS_NOTICE;
+	header.query_size = htonl(strlen(query));
+	header.query_id = htonl(PGRget_next_query_id());
+	strncpy(header.from_host,hostName,sizeof(header.from_host));
+	strncpy(header.userName,userName,sizeof(header.userName));
+	strcpy(header.dbName,"template1");
+	PGRreplicate_packet_send( &header, query, NOTICE_SYSTEM_CALL_TYPE );
+}
+
+static bool
+is_need_use_rlog(ReplicateHeader * header)
+{
+	bool rtn = false;
+
+	if ((Cascade_Inf->useFlag != DATA_USE) ||
+		(PGR_Use_Replication_Log != true)  ||
+		(header->rlog > 0))
+	{
+		return false;
+	}
+	if ((header->cmdSts == CMD_STS_QUERY ) &&
+		((header->cmdType == CMD_TYPE_INSERT) || 
+		 (header->cmdType == CMD_TYPE_UPDATE) || 
+		 (header->cmdType == CMD_TYPE_DELETE) || 
+		 (header->cmdType == CMD_TYPE_EXECUTE)))
+	{
+		rtn = true;	
+	}
+	else 
+	{
+		if ((header->cmdSts == CMD_STS_TRANSACTION ) &&
+			(header->cmdType == CMD_TYPE_COMMIT))
+		{
+			rtn = true;
+		}
+	}
+	return rtn;
+}
+
+/*
+ * set db_name & user_name
+ */
+static int
+set_pgconn_queue(ReplicateHeader * header)
+{
+	char * func = "set_pgconn_queue()";
+	MsgData * msg_data = NULL;
+	int size = 0;
+	int rtn = 0;
+
+	if ((PGconnMsgid < 0) || (header == NULL))
+	{
+		return STATUS_ERROR;
+	}
+	/*
+	 * set db_login data
+	 */
+	size = sizeof(ReplicateHeader) + sizeof(MsgData);
+	msg_data = (MsgData *) malloc(size+sizeof(long));
+	if (msg_data == NULL)
+	{
+		show_error("%s:malloc() failed. reason: %s", func, strerror(errno));
+		return STATUS_ERROR;
+	}
+	memset(msg_data,0,size+sizeof(long));
+	msg_data->mtype = 1;
+	memcpy(msg_data->mdata,header,sizeof(ReplicateHeader));
+
+	/*
+	 * send login data to queue
+	 */
+	rtn = msgsnd(PGconnMsgid, msg_data, sizeof(ReplicateHeader), IPC_NOWAIT);
+
+	/*
+	 * release memory
+	 */
+	free(msg_data);
+
+	return STATUS_OK;	
+}
+
+/*
+ * get db_name & user_name
+ */
+int
+PGRget_pgconn_queue(void)
+{
+	char * func ="PGRget_pgconn_queue()";
+	MsgData * msg_data = NULL;
+	ReplicateHeader * header = NULL;
+	HostTbl * host_ptr = (HostTbl*)NULL;
+	TransactionTbl * ptr = NULL;
+	int size = 0;
+
+	if ((PGconnMsgid <= 0) || (Host_Tbl_Begin == NULL))
+	{
+		return STATUS_ERROR;
+	}
+
+	size = sizeof(MsgData) + sizeof(ReplicateHeader) ;
+	msg_data = (MsgData*)malloc(size+sizeof(long));
+	if (msg_data == (MsgData*)NULL)
+	{
+		show_error("%s:malloc() failed. (%s)",func,strerror(errno));
+		return STATUS_ERROR;
+	}
+	memset(msg_data,0,size+sizeof(long));
+
+	while (msgrcv( PGconnMsgid , msg_data, sizeof(ReplicateHeader) , 0, IPC_NOWAIT) != -1 )
+	{
+		header = (ReplicateHeader *)(msg_data->mdata);
+		host_ptr = Host_Tbl_Begin;
+		/* create new db login */
+		while(host_ptr->useFlag != DATA_END)
+		{
+			/*
+			 * check the status of the cluster DB
+			 */
+			if ((host_ptr->useFlag != DATA_USE) &&
+				(host_ptr->useFlag != DATA_NEW))
+			{
+				host_ptr ++;
+				continue;
+			}
+			if (host_ptr->useFlag == DATA_NEW)
+			{
+				deletePGconnTbl(host_ptr,header);
+			}
+			ptr = getPGconnTbl(host_ptr,header);
+			if (ptr == NULL)
+			{
+				setPGconnTbl(host_ptr, header, DATA_USE);
+				PGRset_host_status(host_ptr,DATA_USE);
+			}
+			host_ptr++;
+		}
+	}
+	if (msg_data != NULL)
+	{
+		free(msg_data);
+	}
+	return STATUS_OK;
+}
+#endif /* USE_REPLICATION */
diff -ruN postgresql-7.4.13-old/src/pgcluster/pgrp/rlog.c postgresql-7.4.13/src/pgcluster/pgrp/rlog.c
--- postgresql-7.4.13-old/src/pgcluster/pgrp/rlog.c	1970-01-01 01:00:00.000000000 +0100
+++ postgresql-7.4.13/src/pgcluster/pgrp/rlog.c	2006-08-05 16:53:43.000000000 +0200
@@ -0,0 +1,1219 @@
+/*--------------------------------------------------------------------
+ * FILE:
+ *     rlog.c
+ *
+ * NOTE:
+ *     This file is composed of the functions to call with the source
+ *     at pgreplicate for replicate ahead log.
+ *
+ * Portions Copyright (c) 2004, Atsushi Mitani
+ *--------------------------------------------------------------------
+ */
+#ifdef USE_REPLICATION
+
+#include "postgres.h"
+#include "postgres_fe.h"
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/un.h>
+#include <unistd.h>
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#include <errno.h>
+#include <ctype.h>
+#include <time.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <sys/sem.h>
+#include <sys/msg.h>
+#include <signal.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#ifdef HAVE_NETINET_TCP_H
+#include <netinet/tcp.h>
+#endif
+#include <dirent.h>
+#include <arpa/inet.h>
+
+#ifdef HAVE_CRYPT_H
+#include <crypt.h>
+#endif
+
+#ifdef MULTIBYTE
+#include "mb/pg_wchar.h"
+#endif
+
+#include "libpq-fe.h"
+#include "libpq-int.h"
+#include "fe-auth.h"
+#include "access/xact.h"
+#include "replicate_com.h"
+#include "pgreplicate.h"
+
+int RLog_Recv_Sock = -1;
+/*--------------------------------------
+ * PROTOTYPE DECLARATION
+ *--------------------------------------
+ */
+int PGRwrite_rlog(ReplicateHeader * header, char * query);
+ReplicateHeader * PGRget_requested_query(ReplicateHeader * header);
+void PGRreconfirm_commit(int sock, ReplicateHeader * header);
+void PGRset_rlog(ReplicateHeader * header, char * query);
+void PGRunset_rlog(ReplicateHeader * header, char * query);
+int PGRresend_rlog_to_db(void);
+void PGRreconfirm_query(int sock, ReplicateHeader * header);
+pid_t  PGR_RLog_Main(void);
+int PGRcreate_send_rlog_socket(void);
+int PGRget_sync_data(ReplicateHeader *header);
+int PGRdelete_sync_data(ReplicateHeader *header);
+int PGRsend_rlog_packet(int sock,ReplicateHeader * header, const char * query_string);
+int PGRrecv_rlog_result(int sock,void * result, int size);
+int PGRsend_rlog_to_local(ReplicateHeader * header,char * query);
+int PGRget_rlog_header(ReplicateHeader * header);
+
+static int set_query_log(ReplicateHeader * header, char * query);
+static QueryLogType * get_query_log_by_header(ReplicateHeader * header);
+static QueryLogType * get_query_log(ReplicateHeader * header);
+static void delete_query_log(ReplicateHeader * header);
+static int set_commit_log(ReplicateHeader * header);
+static CommitLogInf * get_commit_log(ReplicateHeader * header);
+static void delete_commit_log(ReplicateHeader * header);
+static bool was_committed_transaction(ReplicateHeader * header);
+static int create_recv_rlog_socket(void);
+static int do_rlog(int fd);
+static int recv_message(int sock,char * buf, int len);
+static int send_message(int sock, char * msg, int len);
+static void exit_rlog(int sig);
+static int reconfirm_commit(ReplicateHeader * header);
+
+
+int
+PGRwrite_rlog(ReplicateHeader * header, char * query)
+{
+	char * func = "PGRwrite_rlog()";
+
+ 	if (header == NULL)
+	{
+		show_error("%s:header is null",func);
+		return STATUS_ERROR;
+	}
+	switch (header->cmdSts)
+	{
+		case CMD_STS_QUERY:
+#ifdef PRINT_DEBUG
+			show_debug("%s:set_query_log",func);
+#endif			
+			set_query_log(header,query);
+			break;
+		case CMD_STS_DELETE_QUERY:
+#ifdef PRINT_DEBUG
+			show_debug("%s:delete_query_log",func);
+#endif			
+			delete_query_log(header);
+			break;
+		case CMD_STS_TRANSACTION:
+			if (header->cmdType == CMD_TYPE_COMMIT)
+			{
+#ifdef PRINT_DEBUG
+				show_debug("%s:set_commit_log call",func);
+#endif			
+				set_commit_log(header);
+			}
+			break;
+		case CMD_STS_DELETE_TRANSACTION:
+			if (header->cmdType == CMD_TYPE_COMMIT)
+			{
+#ifdef PRINT_DEBUG
+				show_debug("%s:delete_commit_log call",func);
+#endif			
+				delete_commit_log(header);
+			}
+			break;
+	}
+	return STATUS_OK;
+}
+
+ReplicateHeader *
+PGRget_requested_query(ReplicateHeader * header)
+{
+	QueryLogType * query_log = NULL;
+
+	if (Query_Log_Top == NULL)
+	{
+		return NULL;
+	}
+	query_log = Query_Log_Top;
+	while(query_log != (QueryLogType *)NULL)
+	{
+		if ((query_log->header->request_id == header->request_id) &&
+			(query_log->header->pid == header->pid) &&
+			(query_log->header->port == header->port) &&
+			(!strncmp(query_log->header->from_host,header->from_host,sizeof(header->from_host))))
+		{
+			return query_log->header;
+		}
+		query_log = (QueryLogType *)(query_log->next);
+	}
+	return (ReplicateHeader *)NULL;
+}
+
+static int
+set_query_log(ReplicateHeader * header, char * query)
+{
+	char * func = "set_query_log()";
+	int size = 0;
+	QueryLogType * query_log = NULL;
+
+	if (Query_Log_Top == NULL)
+	{
+		Query_Log_Top = (QueryLogType *)malloc(sizeof(QueryLogType));
+		if (Query_Log_Top == (QueryLogType *)NULL)
+		{
+			show_error("%s:malloc failed: (%s)",func,strerror(errno));
+			return STATUS_ERROR;
+		}
+		Query_Log_Top->next = NULL;
+		Query_Log_Top->last = NULL;
+		Query_Log_End = Query_Log_Top;
+		Query_Log_End->next = NULL;
+		Query_Log_End->last = NULL;
+		query_log = Query_Log_Top;	
+	}
+	else
+	{
+		query_log = (QueryLogType *)malloc(sizeof(QueryLogType));
+		if (query_log == (QueryLogType *)NULL)
+		{
+			show_error("%s:malloc failed: (%s)",func,strerror(errno));
+			return STATUS_ERROR;
+		}
+		Query_Log_End->next = (char *)query_log;
+		query_log->last = (char *)Query_Log_End;
+		query_log->next = NULL;
+		Query_Log_End = query_log;	
+	}
+	query_log->header = (ReplicateHeader *)malloc(sizeof(ReplicateHeader));
+	if (query_log->header == (ReplicateHeader *)NULL)
+	{
+		show_error("%s:malloc failed: (%s)",func,strerror(errno));
+		return STATUS_ERROR;
+	}
+	size = ntohl(header->query_size);
+	query_log->query = (char *)malloc(size+4);
+	if (query_log->query == (char *)NULL)
+	{
+		show_error("%s:malloc failed: (%s)",func,strerror(errno));
+		return STATUS_ERROR;
+	}
+	memset(query_log->query,0,size+4);
+	memcpy(query_log->header,header,sizeof(ReplicateHeader));
+	query_log->header->rlog = FROM_R_LOG_TYPE ;
+	memcpy(query_log->query,query,size);
+
+	return STATUS_OK;
+}
+
+static QueryLogType *
+get_query_log_by_header(ReplicateHeader * header)
+{
+	QueryLogType * query_log = NULL;
+
+	if (Query_Log_Top == NULL)
+	{
+		return (QueryLogType *)NULL;
+	}
+	query_log = Query_Log_Top;
+	while(query_log != (QueryLogType *)NULL)
+	{
+		if ((query_log->header->request_id == header->request_id) &&
+			(query_log->header->pid == header->pid) &&
+			(query_log->header->port == header->port) &&
+			(!strncmp(query_log->header->from_host,header->from_host,sizeof(header->from_host))))
+		{
+			return query_log;
+		}
+		query_log = (QueryLogType *)(query_log->next);
+	}
+	return (QueryLogType *)NULL;
+}
+
+static QueryLogType *
+get_query_log(ReplicateHeader * header)
+{
+	QueryLogType * query_log = NULL;
+
+	if (Query_Log_Top == NULL)
+	{
+		return NULL;
+	}
+	query_log = Query_Log_Top;
+	while(query_log != (QueryLogType *)NULL)
+	{
+		if (query_log->header->replicate_id == header->replicate_id)
+		{
+			return query_log;
+		}
+		query_log = (QueryLogType *)(query_log->next);
+	}
+	return (QueryLogType*)NULL;
+}
+
+static void
+delete_query_log(ReplicateHeader * header)
+{
+	QueryLogType * query_log = NULL;
+	QueryLogType * last = NULL;
+	QueryLogType * next = NULL;
+
+	query_log = get_query_log(header);
+
+	if (query_log == NULL)
+	{
+		return ;
+	}
+	last = (QueryLogType *)query_log->last;
+	next = (QueryLogType *)query_log->next;
+
+	/* change link */
+	if (last != (QueryLogType *)NULL)
+	{
+		last->next = (char *)next;
+	}
+	else
+	{
+		Query_Log_Top = next;
+	}
+	if (next != (QueryLogType *)NULL)
+	{
+		next->last = (char *)last;
+	}
+	else
+	{
+		Query_Log_End = last;
+	}
+
+	/* delete contents */
+	if (query_log->header != NULL)
+	{
+		free(query_log->header);
+	}
+	if (query_log->query != NULL)
+	{
+		free(query_log->query);
+	}
+	free(query_log);
+}
+
+static int
+set_commit_log(ReplicateHeader * header)
+{
+
+	CommitLogInf * commit_log = NULL;
+	ReplicateHeader * c_header;
+
+	if (Commit_Log_Tbl == NULL)
+	{
+		return STATUS_ERROR;
+	}
+	commit_log = Commit_Log_Tbl + 1;
+	while (	commit_log->inf.useFlag != DATA_END )
+	{
+		if (commit_log->inf.useFlag != DATA_USE)
+		{
+			commit_log->inf.useFlag = DATA_USE;
+			c_header = &(commit_log->header);
+			memcpy(c_header,header,sizeof(ReplicateHeader));
+			Commit_Log_Tbl->inf.commit_log_num ++;
+			break;
+		}
+		commit_log ++;
+	}
+	return STATUS_OK;
+}
+
+static CommitLogInf *
+get_commit_log(ReplicateHeader * header)
+{
+	CommitLogInf * commit_log = NULL;
+	ReplicateHeader * c_header;
+	int cnt = 0;
+
+	if (Commit_Log_Tbl == NULL)
+	{
+		return (CommitLogInf *)NULL;
+	}
+	commit_log = Commit_Log_Tbl + 1;
+	while (	commit_log->inf.useFlag != DATA_END )
+	{
+		if (commit_log->inf.useFlag == DATA_USE)
+		{
+			cnt ++;
+			c_header = &(commit_log->header);
+			if (c_header == NULL)
+			{
+				commit_log ++;
+				continue;
+			}
+			if (c_header->replicate_id == header->replicate_id)
+			{
+				return commit_log;	
+			}
+		}
+		else
+		{
+		}
+		if (cnt >= Commit_Log_Tbl->inf.commit_log_num)
+		{
+			break;
+		}
+		commit_log ++;
+	}
+	return (CommitLogInf *)NULL;
+}
+
+static void
+delete_commit_log(ReplicateHeader * header)
+{
+	CommitLogInf * commit_log = NULL;
+
+	commit_log = get_commit_log(header);
+	if (commit_log != NULL)
+	{
+		memset(&(commit_log->header),0,sizeof(commit_log->header));
+		commit_log->inf.useFlag = DATA_INIT;
+		Commit_Log_Tbl->inf.commit_log_num --;
+	}
+}
+
+static bool
+was_committed_transaction(ReplicateHeader * header)
+{
+	CommitLogInf * commit_log = NULL;
+
+	commit_log = get_commit_log(header);
+	if (commit_log != NULL)
+	{
+		return true;
+	}
+	return false;
+}
+
+void 
+PGRreconfirm_commit(int sock, ReplicateHeader * header)
+{
+	int result = PGR_NOT_YET_COMMIT;
+
+	if (Replicateion_Log == NULL) 
+	{
+		return ;
+	}
+	if (Replicateion_Log->r_log_sock > 0)
+	{
+		close(Replicateion_Log->r_log_sock );
+		Replicateion_Log->r_log_sock = -1;
+	}
+	Replicateion_Log->r_log_sock = PGRcreate_send_rlog_socket();
+
+	header->query_size = 0;
+	PGRsend_rlog_packet(Replicateion_Log->r_log_sock,header,NULL);
+	PGRrecv_rlog_result(Replicateion_Log->r_log_sock,&result, sizeof(result));
+
+	close(Replicateion_Log->r_log_sock );
+	Replicateion_Log->r_log_sock = -1;
+		
+	snprintf(PGR_Result,PGR_MESSAGE_BUFSIZE,"%d,%d", PGR_TRANSACTION_CONFIRM_ANSWER_FUNC_NO,result);
+
+	PGRreturn_result(sock, PGR_NOWAIT_ANSWER);
+}
+
+static int 
+reconfirm_commit(ReplicateHeader * header)
+{
+	char * func = "reconfirm_commit()";
+	int result = PGR_NOT_YET_COMMIT;
+
+	/* check the transaction was committed */
+	if (was_committed_transaction(header) == true)
+	{
+		result = PGR_ALREADY_COMMITTED;
+#ifdef PRINT_DEBUG
+		show_debug("%s:PGR_ALREADY_COMMITTED",func);
+#endif			
+	}
+	else
+	{
+#ifdef PRINT_DEBUG
+		show_debug("%s:PGR_NOT_YET_COMMIT",func);
+#endif			
+	}
+	return result;
+}
+
+void
+PGRset_rlog(ReplicateHeader * header, char * query)
+{
+	char * func = "PGRset_rlog()";
+	int status = STATUS_OK;
+	bool send_flag = false;
+
+ 	if (PGR_Log_Header == NULL)
+	{
+		return;
+	}
+	switch (header->cmdSts)
+	{
+		case CMD_STS_QUERY:
+			send_flag = true;
+			break;
+		case CMD_STS_TRANSACTION:
+			if (header->cmdType == CMD_TYPE_COMMIT)
+			{
+				send_flag = true;
+				PGR_Log_Header->cmdType = header->cmdType;
+				PGR_Log_Header->query_size = htonl(strlen(query));
+			}
+			break;
+	}
+	if (send_flag != true)
+	{
+		show_error("%s:send_flag is false",func);
+		return;
+	}
+	PGR_Log_Header->cmdSys = CMD_SYS_LOG;
+	if (Cascade_Inf->useFlag == DATA_USE)
+	{
+		/* save log data in remote server */
+
+		status = PGRsend_lower_cascade(PGR_Log_Header, query);	
+		if (status != STATUS_OK)
+		{
+#ifdef PRINT_DEBUG
+			show_debug("%s:PGRsend_lower_cascade failed",func);
+#endif			
+			PGRwrite_rlog(PGR_Log_Header, query);
+		}
+	}
+	else
+	{
+		/* save log data in local server */
+		PGRwrite_rlog(PGR_Log_Header, query);
+	}
+}
+
+void
+PGRunset_rlog(ReplicateHeader * header, char * query)
+{
+	int status = STATUS_OK;
+	bool send_flag = false;
+
+ 	if (PGR_Log_Header == NULL)
+	{
+		return;
+	}
+	switch (header->cmdSts)
+	{
+		case CMD_STS_QUERY:
+			send_flag = true;
+			PGR_Log_Header->cmdSts = CMD_STS_DELETE_QUERY;
+			break;
+		case CMD_STS_TRANSACTION:
+			if (PGR_Log_Header->cmdType == CMD_TYPE_COMMIT)
+			{
+				PGR_Log_Header->cmdSts = CMD_STS_DELETE_TRANSACTION;
+				PGR_Log_Header->query_size = htonl(strlen(query));
+				send_flag = true;
+			}
+			break;
+	}
+	if (send_flag != true)
+	{
+		return;
+	}
+	PGR_Log_Header->cmdSys = CMD_SYS_LOG;
+	if (Cascade_Inf->useFlag == DATA_USE)
+	{
+		/* save log data in remote server */
+
+		status = PGRsend_lower_cascade(PGR_Log_Header, query);	
+		if (status != STATUS_OK)
+		{
+			PGRwrite_rlog(PGR_Log_Header, query);
+		}
+	}
+	else
+	{
+		/* save log data in local server */
+		 PGRwrite_rlog(PGR_Log_Header, query);
+	}
+}
+
+int
+PGRresend_rlog_to_db(void)
+{
+	QueryLogType * query_log = NULL;
+	QueryLogType * next = NULL;
+	int status = STATUS_OK;
+	int dest = 0;
+
+	query_log = Query_Log_Top;
+
+	while (query_log != NULL)
+	{
+		if (query_log->header->rlog != FROM_R_LOG_TYPE )
+		{
+			query_log = (QueryLogType *)query_log->next;
+			continue;
+		}
+		status = PGRreplicate_packet_send(query_log->header,query_log->query, dest);
+		if (status == STATUS_SKIP_REPLICATE )
+		{
+			Query_Log_Top = query_log;
+			query_log = (QueryLogType *)query_log->next;
+			if (query_log != NULL)
+			{
+				Query_Log_End = (QueryLogType *)query_log->next;
+			}
+			else
+			{
+				Query_Log_End = (QueryLogType *)NULL;
+			}
+			continue;
+		}
+		if (query_log->header != NULL)
+		{
+			free(query_log->header );
+		}
+		if (query_log->query != NULL)
+		{
+			free(query_log->query );
+		}
+		next = (QueryLogType *)query_log->next;
+		free(query_log);
+		query_log = next;
+		Query_Log_Top = query_log;
+		if (query_log != NULL)
+		{
+			Query_Log_End = (QueryLogType *)query_log->next;
+		}
+		else
+		{
+			Query_Log_End = (QueryLogType *)NULL;
+		}
+	}
+	return STATUS_OK;
+}
+	
+pid_t
+PGR_RLog_Main(void)
+{
+	char * func = "PGR_RLog_Main()";
+	int afd = -1;
+	int rtn;
+	struct sockaddr addr;
+	socklen_t addrlen;
+	pid_t pid = 0;
+	pid_t pgid = 0;
+
+	if (Replicateion_Log == NULL)
+	{
+		show_error("%s:Replicateion_Log is NULL",func);
+		return -1;
+	}
+	pgid = getpgid(0);
+	if ((pid = fork()) != 0 )
+	{
+		return pid;
+	}
+	signal(SIGTERM,exit_rlog);
+	signal(SIGINT,exit_rlog);
+	signal(SIGQUIT,exit_rlog);
+	signal(SIGPIPE,SIG_IGN);
+
+	setpgid(0,pgid);	
+	RLog_Recv_Sock = create_recv_rlog_socket();
+
+	if (RLog_Recv_Sock  < 0)
+	{
+		exit(0);
+	}
+	for (;;)
+	{
+		fd_set	  rmask;
+		struct timeval timeout;
+
+		timeout.tv_sec = PGR_RECV_TIMEOUT;
+		timeout.tv_usec = 0;
+
+		Idle_Flag = IDLE_MODE ;
+		if (Exit_Request)
+		{
+			exit_rlog(0);
+		}
+		/*
+		 * Wait for something to happen.
+		 */
+		FD_ZERO(&rmask);
+		FD_SET(RLog_Recv_Sock,&rmask);
+		rtn = select(RLog_Recv_Sock+1, &rmask, (fd_set *)NULL, (fd_set *)NULL, &timeout);
+		if (rtn && FD_ISSET(RLog_Recv_Sock, &rmask))
+		{
+			Idle_Flag = BUSY_MODE ;
+			addrlen = sizeof(addr);
+			afd = accept(RLog_Recv_Sock, &addr, &addrlen);
+			if (afd < 0)
+			{
+				continue;
+			}
+			else
+			{
+				do_rlog(afd);
+				close(afd);
+			}
+		}
+	}
+	exit(0);
+}
+
+static int 
+create_recv_rlog_socket(void)
+{
+	char * func = "create_recv_socket()";
+	struct sockaddr_un addr;
+	int fd;
+	int status;
+	int len;
+
+	/* set unix domain socket path */
+	fd = socket(AF_UNIX, SOCK_STREAM, 0);
+	if (fd == -1)
+	{
+		show_error("%s:Failed to create UNIX domain socket. reason: %s",func,  strerror(errno));
+		return -1;
+	}
+	memset((char *) &addr, 0, sizeof(addr));
+	((struct sockaddr *)&addr)->sa_family = AF_UNIX;
+	snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/.s.PGRLOG.%d",
+			PGR_Write_Path, 
+			Replicateion_Log->RLog_Port_Number);
+fprintf(stderr,"addr.sun_path[%s]\n",addr.sun_path);
+	if (Replicateion_Log->RLog_Sock_Path == NULL)
+	{
+		Replicateion_Log->RLog_Sock_Path = strdup(addr.sun_path);
+fprintf(stderr,"Replicateion_Log->RLog_Sock_Path[%s]\n",Replicateion_Log->RLog_Sock_Path);
+	}
+	len = sizeof(struct sockaddr_un);
+	status = bind(fd, (struct sockaddr *)&addr, len);
+	if (status == -1)
+	{
+		show_error("%s: bind() failed. reason: %s", func, strerror(errno));
+		return -1;
+	}
+
+	if (chmod(addr.sun_path, 0770) == -1)
+	{
+		show_error("%s: chmod() failed. reason: %s", func, strerror(errno));
+		return -1;
+	}
+
+	status = listen(fd, PGR_MAX_SOCKET_QUEUE);
+	if (status < 0)
+	{
+		show_error("%s: listen() failed. reason: %s", func, strerror(errno));
+		return -1;
+	}
+	return fd;
+}
+
+int 
+PGRcreate_send_rlog_socket(void)
+{
+	char * func = "create_recv_socket()";
+	struct sockaddr_un addr;
+	int fd;
+	int len;
+
+	/* set unix domain socket path */
+	fd = socket(AF_UNIX, SOCK_STREAM, 0);
+	if (fd == -1)
+	{
+		show_error("%s:Failed to create UNIX domain socket. reason: %s",func,  strerror(errno));
+		return -1;
+	}
+	memset((char *) &addr, 0, sizeof(addr));
+	((struct sockaddr *)&addr)->sa_family = AF_UNIX;
+	snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/.s.PGRLOG.%d",
+			PGR_Write_Path, 
+			Replicateion_Log->RLog_Port_Number);
+	if (Replicateion_Log->RLog_Sock_Path == NULL)
+	{
+		Replicateion_Log->RLog_Sock_Path = strdup(addr.sun_path);
+	}
+	len = sizeof(struct sockaddr_un);
+	if (connect(fd, (struct sockaddr *)&addr, len) < 0)
+	{
+		close(fd);
+		return -1;
+	}
+	return fd;
+}
+
+static int
+do_rlog(int fd)
+{
+	char * func = "do_rlog()";
+	QueryLogType * query_log = NULL;
+	ReplicateHeader  header;
+	char * query = NULL;
+	int status = STATUS_OK;
+
+	memset(&header,0,sizeof(header));
+	query = PGRread_packet(fd, &header);
+	if (header.cmdSys == 0)
+	{
+		return STATUS_ERROR;
+	}
+	switch (header.cmdSys)
+	{
+		case CMD_SYS_REPLICATE:
+			if (header.cmdSts != CMD_STS_DELETE_QUERY)
+			{
+				query_log = get_query_log_by_header(&header);
+				if (query_log != (QueryLogType*)NULL)
+				{
+					memcpy(&header,query_log->header,sizeof(ReplicateHeader));
+				}
+				send_message(fd,(char *)&header,sizeof(ReplicateHeader));
+				header.cmdSts = CMD_STS_DELETE_QUERY;
+				PGRwrite_rlog(&header, NULL);
+			}
+			else
+			{
+				status = PGRwrite_rlog((ReplicateHeader*)&header,(char *)NULL);
+				send_message(fd,(char *)&status,sizeof(status));
+			}
+			break;
+		case CMD_SYS_LOG:
+			status = PGRwrite_rlog((ReplicateHeader*)&header, query);
+			send_message(fd,(char *)&status,sizeof(status));
+			break;
+		case  CMD_SYS_CALL:
+			if (header.cmdSts == CMD_STS_TRANSACTION_ABORT)
+			{
+#ifdef PRINT_DEBUG
+				show_debug("%s: CMD_STS_TRANSACTION_ABORT",func);
+#endif
+				status = reconfirm_commit(&header);
+			}
+			else if (header.cmdSts == CMD_STS_QUERY_SUSPEND)
+			{
+#ifdef PRINT_DEBUG
+				show_debug("%s: CMD_STS_QUERY_SUSPEND",func);
+#endif
+				status = PGRresend_rlog_to_db();
+			}
+			send_message(fd,(char *)&status,sizeof(status));
+			break;
+	}
+	return STATUS_OK;
+}
+
+int
+PGRget_sync_data(ReplicateHeader *header)
+{
+	ReplicateHeader rlog_header;
+
+	if (header == NULL)
+	{
+		return STATUS_ERROR;
+	}
+
+	if (Replicateion_Log->r_log_sock > 0)
+	{
+		close(Replicateion_Log->r_log_sock );
+		Replicateion_Log->r_log_sock = -1;
+	}
+	Replicateion_Log->r_log_sock = PGRcreate_send_rlog_socket();
+
+	memset(&rlog_header,0,sizeof(ReplicateHeader));
+	send_message( Replicateion_Log->r_log_sock, (char *)header,sizeof(ReplicateHeader));
+	recv_message( Replicateion_Log->r_log_sock, (char *)&rlog_header,sizeof(ReplicateHeader));
+	if (rlog_header.cmdSts != 0)
+	{
+		memcpy(header,&rlog_header, sizeof(ReplicateHeader));
+		return STATUS_OK;
+	}
+	close(Replicateion_Log->r_log_sock );
+	Replicateion_Log->r_log_sock = -1;
+	return STATUS_ERROR;
+
+}
+
+int
+PGRdelete_sync_data(ReplicateHeader *header)
+{
+	int status;
+	char cmdSts;
+
+	cmdSts = header->cmdSts;
+	header->cmdSts = CMD_STS_DELETE_QUERY;
+	if (header == NULL)
+	{
+		return STATUS_ERROR;
+	}
+	if (Replicateion_Log->r_log_sock > 0)
+	{
+		close(Replicateion_Log->r_log_sock );
+		Replicateion_Log->r_log_sock = -1;
+	}
+	Replicateion_Log->r_log_sock = PGRcreate_send_rlog_socket();
+	send_message( Replicateion_Log->r_log_sock, (char *)header,sizeof(ReplicateHeader));
+	recv_message( Replicateion_Log->r_log_sock, (char *)&status,sizeof(status));
+	header->cmdSts = cmdSts;
+	close(Replicateion_Log->r_log_sock );
+	Replicateion_Log->r_log_sock = -1;
+	return status;
+
+}
+
+int
+PGRsend_rlog_packet(int sock,ReplicateHeader * header, const char * query_string)
+{
+	char * buf = NULL;
+	int buf_size = 0;
+	int header_size = 0;
+	int query_size = 0;
+	int rtn = 0;
+
+	/* check parameter */
+	if ((sock <= 0) || (header == NULL))
+	{
+		return STATUS_ERROR;
+	}
+	if (query_string != NULL)
+	{
+		query_size = ntohl(header->query_size);
+	}
+	header_size = sizeof(ReplicateHeader);
+	buf_size = header_size + query_size + 4;
+	buf = (char *)malloc(buf_size);
+	if (buf == (char *)NULL)
+	{
+		return STATUS_ERROR;
+	}
+	memset(buf,0,buf_size);
+	buf_size -= 4;
+	memcpy(buf,header,header_size);
+	if (query_size > 0)
+	{
+		memcpy((char *)(buf+header_size),query_string,query_size+1);
+	}
+	rtn = send_message(sock,buf,buf_size);
+	free(buf);
+	return rtn;
+}
+
+int
+PGRrecv_rlog_result(int sock,void * result, int size)
+{
+	fd_set      rmask;
+	struct timeval timeout;
+	int rtn;
+
+	if ((result == (void *)NULL) || (size <= 0))
+	{
+		return -1;
+	}
+
+	timeout.tv_sec = PGR_RECV_TIMEOUT;
+	timeout.tv_usec = 0;
+
+	/*
+	 * Wait for something to happen.
+	 */
+	rtn = 1;
+	while (rtn)
+	{
+		FD_ZERO(&rmask);
+		FD_SET(sock,&rmask);
+		rtn = select(sock+1, &rmask, (fd_set *)NULL, (fd_set *)NULL, &timeout);
+		if (rtn && FD_ISSET(sock, &rmask))
+		{
+			return (recv_message(sock, (char*)result, size));
+		}
+		else
+		{
+			if (errno != EINTR)
+			{
+				return -1;
+			}
+		}
+	}
+	return -1;
+}
+
+
+static int
+recv_message(int sock,char * buf, int len)
+{
+	int cnt = 0;
+	int r = 0;
+	char * read_ptr;
+	int read_size = 0;
+	cnt = 0;
+	read_ptr = buf;
+
+	for (;;)
+	{
+		r = recv(sock,read_ptr + read_size ,len - read_size, 0); 
+		if (r < 0)
+		{
+			if (errno == EINTR)
+			{
+				usleep(PGR_RECV_WAIT_MSEC);
+				continue;
+			}
+			if (cnt < PGR_RECV_RETRY_CNT )
+			{
+				cnt ++;
+				usleep(PGR_RECV_WAIT_MSEC);
+				continue;
+			}
+			else
+			{
+				if (read_size == 0)
+				{
+					return -1;
+				}
+			}
+		}
+		if (r > 0)
+		{
+			read_size += r;
+			if (read_size == len)
+			{
+				return read_size;
+			}
+		}
+		if ((r == 0) && (read_size == 0))
+		{
+			return -1;
+		}
+		if (cnt < PGR_RECV_RETRY_CNT )
+		{
+			cnt ++;
+			usleep(PGR_RECV_WAIT_MSEC);
+			continue;
+		}
+		else
+		{
+			return -1;
+		}
+	}
+}
+
+int
+PGRsend_rlog_to_local(ReplicateHeader * header,char * query)
+{
+	int status = STATUS_OK;
+
+	if (Replicateion_Log == NULL) 
+	{
+		return STATUS_ERROR;
+	}
+	if (Replicateion_Log->r_log_sock > 0)
+	{
+		close(Replicateion_Log->r_log_sock );
+		Replicateion_Log->r_log_sock = -1;
+	}
+	Replicateion_Log->r_log_sock = PGRcreate_send_rlog_socket();
+
+	status = PGRsend_rlog_packet(Replicateion_Log->r_log_sock,header,query);
+	if (status != STATUS_ERROR)
+	{
+		PGRrecv_rlog_result(Replicateion_Log->r_log_sock,&status, sizeof(status));
+	}
+
+	close(Replicateion_Log->r_log_sock );
+	Replicateion_Log->r_log_sock = -1;
+		
+	return status;
+}
+
+int
+PGRget_rlog_header(ReplicateHeader * header)
+{
+	int status = STATUS_OK;
+	ReplicateHeader rlog_header;
+
+	if ((Replicateion_Log == NULL) || 
+		(header == NULL))
+	{
+		return STATUS_ERROR;
+	}
+	if (Replicateion_Log->r_log_sock > 0)
+	{
+		close(Replicateion_Log->r_log_sock );
+		Replicateion_Log->r_log_sock = -1;
+	}
+	Replicateion_Log->r_log_sock = PGRcreate_send_rlog_socket();
+
+	memcpy(&rlog_header,header,sizeof(ReplicateHeader));
+	rlog_header.cmdSys = CMD_SYS_REPLICATE;
+	rlog_header.query_size = 0;
+	status =PGRsend_rlog_packet(Replicateion_Log->r_log_sock,&rlog_header,NULL);
+	if (status != STATUS_ERROR)
+	{
+		status = PGRrecv_rlog_result(Replicateion_Log->r_log_sock,&rlog_header, sizeof(ReplicateHeader));
+		if (status > 0)
+		{
+			memcpy(header,&rlog_header,sizeof(ReplicateHeader));
+			status = STATUS_OK;
+		}
+		else
+		{
+			status = STATUS_ERROR;
+		}
+	}
+
+	close(Replicateion_Log->r_log_sock );
+	Replicateion_Log->r_log_sock = -1;
+		
+	return status;
+}
+
+static int
+send_message(int sock, char * msg, int len)
+{
+	char * func = "send_message()";
+	fd_set	  wmask;
+	struct timeval timeout;
+	int rtn = 0;
+	char * send_ptr = NULL;
+	int send_size= 0;
+	int buf_size = 0;
+	int s = 0;
+	int cnt = 0;
+	int flag = 0;
+	
+	if ((msg == NULL) || (len <= 0) || (sock <= 0))
+	{
+		return STATUS_ERROR;
+	}
+	send_ptr = msg;
+	buf_size = len;
+
+	timeout.tv_sec = PGR_SEND_TIMEOUT;
+	timeout.tv_usec = 0;
+
+	/*
+	 * Wait for something to happen.
+	 */
+#ifdef MSG_DONTWAIT
+	flag |= MSG_DONTWAIT;
+#endif
+#ifdef MSG_NOSIGNAL
+	flag |= MSG_NOSIGNAL;
+#endif
+	FD_ZERO(&wmask);
+	FD_SET(sock,&wmask);
+	rtn = select(sock+1, (fd_set *)NULL, &wmask, (fd_set *)NULL, &timeout);
+	if (rtn && FD_ISSET(sock, &wmask))
+	{
+		for (;;)
+		{
+			s = send(sock,send_ptr + send_size,buf_size - send_size ,flag); 
+			if (s < 0){
+				show_error("%s:send error: %d(%s)",func,errno,strerror(errno));
+				if (errno == EINTR)
+				{
+					usleep(PGR_SEND_WAIT_MSEC);
+					continue;
+				}
+#ifdef EPIPE
+				if (errno == EPIPE)
+				{
+					memset(send_ptr, 0, len);
+					return STATUS_ABORTED;
+				}
+#endif /* EPIPE */
+#ifdef ENSOCK
+				if (errno == ENSOCK)
+				{
+					memset(send_ptr, 0, len);
+					return STATUS_ABORTED;
+				}
+#endif /* ENSOCK */
+#ifdef EHOSTUNREACH
+				if (errno == EHOSTUNREACH)
+				{
+					memset(send_ptr, 0, len);
+					return STATUS_ABORTED;
+				}
+#endif /* EHOSTUNREACH */
+				if (cnt < PGR_SEND_RETRY_CNT )
+				{
+					cnt ++;
+					usleep(PGR_SEND_WAIT_MSEC);
+					continue;
+				}
+				else
+				{
+					memset(send_ptr, 0, len);
+					return STATUS_ERROR;
+				}
+			}
+			if (s > 0)
+			{
+				send_size += s;
+				if (send_size == buf_size)
+				{
+					return STATUS_OK;
+				}
+			}
+			usleep(PGR_SEND_WAIT_MSEC);
+			if (flag != 0)
+			{
+				if (cnt < PGR_SEND_RETRY_CNT )
+				{
+					cnt ++;
+					usleep(PGR_SEND_WAIT_MSEC);
+					continue;
+				}
+				else
+				{
+					memset(send_ptr, 0, len);
+					return STATUS_ERROR;
+				}
+			}
+		}
+	}
+	return STATUS_ERROR;
+}
+
+static void
+exit_rlog(int sig)
+{
+	Exit_Request = true;
+	if (sig == SIGTERM)
+	{
+		if (Idle_Flag == BUSY_MODE)
+		{
+			return;
+		}
+	}
+	if (RLog_Recv_Sock >= 0)
+	{
+		close(RLog_Recv_Sock);
+		RLog_Recv_Sock = -1;
+	}
+	if (Replicateion_Log->RLog_Sock_Path != NULL)
+	{
+		unlink(Replicateion_Log->RLog_Sock_Path);
+		free(Replicateion_Log->RLog_Sock_Path);
+	}
+	exit(0);
+}
+#endif /* USE_REPLICATION */
diff -ruN postgresql-7.4.13-old/src/pgcluster/tool/Makefile postgresql-7.4.13/src/pgcluster/tool/Makefile
--- postgresql-7.4.13-old/src/pgcluster/tool/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ postgresql-7.4.13/src/pgcluster/tool/Makefile	2006-08-05 16:53:43.000000000 +0200
@@ -0,0 +1,32 @@
+#-------------------------------------------------------------------------
+#
+# Makefile for src/pgcluster/pgrp
+#
+#-------------------------------------------------------------------------
+
+subdir = src/pgcluster/tool
+top_builddir = ../../..
+include $(top_builddir)/src/Makefile.global
+
+OBJS= pgcbench.o
+
+# EXTRA_OBJS = $(top_builddir)/src/backend/libpq/replicate_com.o
+
+override CPPFLAGS := -I$(libpq_srcdir) $(CPPFLAGS) -DBINDIR=\"$(bindir)\"
+
+all: pgcbench
+
+pgcbench: $(OBJS) $(libpq_builddir)/libpq.a 
+	$(CC) $(CFLAGS) $(OBJS) $(EXTRA_OBJS) $(libpq) $(LDFLAGS) $(LIBS) -o $@
+
+install: all installdirs
+	$(INSTALL_PROGRAM) pgcbench$(X) $(DESTDIR)$(bindir)/pgcbench$(X)
+
+installdirs:
+	$(mkinstalldirs) $(DESTDIR)$(bindir)
+
+uninstall:
+	rm -f $(addprefix $(DESTDIR)$(bindir)/, pgcbench$(X))
+
+clean distclean maintainer-clean:
+	rm -f pgcbench$(X) $(OBJS) 
diff -ruN postgresql-7.4.13-old/src/pgcluster/tool/pgcbench.c postgresql-7.4.13/src/pgcluster/tool/pgcbench.c
--- postgresql-7.4.13-old/src/pgcluster/tool/pgcbench.c	1970-01-01 01:00:00.000000000 +0100
+++ postgresql-7.4.13/src/pgcluster/tool/pgcbench.c	2006-08-05 16:53:43.000000000 +0200
@@ -0,0 +1,1113 @@
+/*
+ * pgbench: a simple benchmark program for PGCluster
+ * This program was written based on pgbench by Tatsuo Ishii.
+ *
+ * Portions Copyright (c) 2003, Atsushi Mitani
+ * Portions Copyright (c) 2000-2002, Tatsuo Ishii
+ *
+ * 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.
+ */
+#include "postgres_fe.h"
+
+#include "libpq-fe.h"
+
+#include <errno.h>
+
+#ifdef WIN32
+#include "win32.h"
+#else
+#include <sys/time.h>
+#include <unistd.h>
+
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#endif
+
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+
+/* for getrlimit */
+#include <sys/resource.h>
+#endif   /* ! WIN32 */
+
+#include <sys/types.h>
+#include <sys/wait.h>
+
+/********************************************************************
+ * some configurable parameters */
+
+#define MAXCLIENTS 4096			/* max number of clients allowed */
+
+int			nclients = 1;		/* default number of simulated clients */
+int			nxacts = 10;		/* default number of transactions per
+								 * clients */
+
+/*
+ * scaling factor. for example, tps = 10 will make 1000000 tuples of
+ * accounts table.
+ */
+int			tps = 1;
+
+/*
+ * end of configurable parameters
+ *********************************************************************/
+
+#define nbranches	1
+#define ntellers	10
+#define naccounts	100000
+
+#define SELECT_ONLY	(1)
+#define	INSERT_ONLY	(2)
+#define	UPDATE_ONLY	(3)
+#define	WITH_TRANSACTION	(4)
+#define TPC_B_LIKE	(5)
+
+FILE	   *LOGFILE = NULL;
+
+bool		use_log = false;			/* log transaction latencies to a file */
+
+int			remains;			/* number of remaining clients */
+
+int			is_connect;			/* establish connection  for each
+								 * transaction */
+
+char	   *pghost = "";
+char	   *pgport = NULL;
+char	   *pgoptions = NULL;
+char	   *pgtty = NULL;
+char	   *login = NULL;
+char	   *pwd = NULL;
+char	   *dbName;
+
+typedef struct
+{
+	PGconn	   *con;			/* connection handle to DB */
+	int			id;				/* client No. */
+	int			state;			/* state No. */
+	int			cnt;			/* xacts count */
+	int			ecnt;			/* error count */
+	int         maxAct;
+	int			listen;			/* 0 indicates that an async query has
+								 * been sent */
+	int			aid;			/* account id for this transaction */
+	int			bid;			/* branch id for this transaction */
+	int			tid;			/* teller id for this transaction */
+	int			delta;
+	int			abalance;
+	struct timeval txn_begin;	/* used for measuring latencies */
+}	CState;
+
+static void
+usage()
+{
+	fprintf(stderr, "usage: pgcbench [-h hostname][-p port][-c nclients][-t ntransactions][-s scaling_factor][-I(insert only)][-U(update only)][-S(select only)][-u login][-P password][-d(debug)][dbname]\n");
+	fprintf(stderr, "(initialize mode): pgcbench -i [-h hostname][-p port][-s scaling_factor][-u login][-P password][-d(debug)][dbname]\n");
+}
+
+/* random number generator */
+static int
+getrand(int min, int max )
+{
+
+	return (min + (int) (max * 1.0 * rand() / (RAND_MAX + 1.0)));
+}
+
+/* set up a connection to the backend */
+static PGconn *
+doConnect()
+{
+	PGconn	   *con;
+	PGresult   *res;
+ 
+	con = PQsetdbLogin(pghost, pgport, pgoptions, pgtty, dbName,
+					   login, pwd);
+	if (con == NULL)
+	{
+		fprintf(stderr, "Connection to database '%s' failed.\n", dbName);
+		fprintf(stderr, "Memory allocatin problem?\n");
+		return (NULL);
+	}
+
+	if (PQstatus(con) == CONNECTION_BAD)
+	{
+		fprintf(stderr, "Connection to database '%s' failed.\n", dbName);
+
+		if (PQerrorMessage(con))
+			fprintf(stderr, "%s", PQerrorMessage(con));
+		else
+			fprintf(stderr, "No explanation from the backend\n");
+
+		return (NULL);
+	}
+
+	res = PQexec(con, "SET search_path = public");
+	if (PQresultStatus(res) != PGRES_COMMAND_OK)
+	{
+		fprintf(stderr, "%s", PQerrorMessage(con));
+		exit(1);
+	}
+	PQclear(res);
+	res = PQexec(con, "SET autocommit TO 'on'");
+	if (PQresultStatus(res) != PGRES_COMMAND_OK)
+	{
+		fprintf(stderr, "%s", PQerrorMessage(con));
+		exit(1);
+	}
+	PQclear(res);
+
+	return (con);
+}
+
+/* throw away response from backend */
+static void
+discard_response(CState * state)
+{
+	PGresult   *res;
+
+	do
+	{
+		res = PQgetResult(state->con);
+		if (res)
+			PQclear(res);
+	} while (res);
+}
+
+/* check to see if the SQL result was good */
+static int
+check(CState * st, PGresult *res, int good)
+{
+	if (res && PQresultStatus(res) != good)
+	{
+		fprintf(stderr, "aborted in state %d: %s",  st->state, PQerrorMessage(st->con));
+		PQfinish(st->con);
+		st->con = NULL;
+		return (-1);
+	}
+	return (0);					/* OK */
+}
+
+/* process a transaction */
+static void
+doMix(CState * st, int debug, int ttype)
+{
+	char		sql[256];
+	PGresult   *res;
+
+	if (st->listen)
+	{							/* are we receiver? */
+		if (debug)
+			fprintf(stderr, "client receiving\n");
+		if (!PQconsumeInput(st->con))
+		{						/* there's something wrong */
+			fprintf(stderr, "Client aborted in state %d. Probably the backend died while processing.\n", st->state);
+			PQfinish(st->con);
+			st->con = NULL;
+			return;
+		}
+		if (PQisBusy(st->con))
+			return;				/* don't have the whole result yet */
+
+		switch (st->state)
+		{
+			case 0:				/* response to "begin" */
+				res = PQgetResult(st->con);
+				if (ttype == WITH_TRANSACTION)
+				{
+					if (check(st, res, PGRES_COMMAND_OK))
+						return;
+				}
+				else
+				{
+					if (check(st, res, PGRES_TUPLES_OK))
+						return;
+				}
+				PQclear(res);
+				discard_response(st);
+				break;
+			case 1:				/* response to "update accounts..." */
+				res = PQgetResult(st->con);
+				if (check(st, res, PGRES_COMMAND_OK))
+					return;
+				PQclear(res);
+				discard_response(st);
+				break;
+			case 2:				/* response to "select abalance ..." */
+				res = PQgetResult(st->con);
+				if (check(st, res, PGRES_TUPLES_OK))
+					return;
+				PQclear(res);
+				discard_response(st);
+				break;
+			case 3:				/* response to "update tellers ..." */
+				res = PQgetResult(st->con);
+				if (check(st, res, PGRES_COMMAND_OK))
+					return;
+				PQclear(res);
+				discard_response(st);
+				break;
+			case 4:				/* response to "update branches ..." */
+				res = PQgetResult(st->con);
+				if (check(st, res, PGRES_COMMAND_OK))
+					return;
+				PQclear(res);
+				discard_response(st);
+				break;
+			case 5:				/* response to "insert into history ..." */
+				res = PQgetResult(st->con);
+				if (check(st, res, PGRES_COMMAND_OK))
+					return;
+				PQclear(res);
+				discard_response(st);
+				break;
+			case 6:				/* response to "end" */
+
+				/*
+				 * transaction finished: record the time it took in the
+				 * log
+				 */
+				if (use_log)
+				{
+					long long	diff;
+					struct timeval now;
+
+					gettimeofday(&now, 0);
+					diff = (now.tv_sec - st->txn_begin.tv_sec) * 1000000 +
+						(now.tv_usec - st->txn_begin.tv_usec);
+
+					fprintf(LOGFILE, "%d %d %lld\n", st->id, st->cnt, diff);
+				}
+
+				res = PQgetResult(st->con);
+				if (ttype == WITH_TRANSACTION)
+				{
+					if (check(st, res, PGRES_COMMAND_OK))
+						return;
+				}
+				else
+				{
+					if (check(st, res, PGRES_TUPLES_OK))
+						return;
+				}
+				PQclear(res);
+				discard_response(st);
+
+				if (is_connect)
+				{
+					PQfinish(st->con);
+					st->con = NULL;
+				}
+				if (++st->cnt >= st->maxAct)
+				{
+					remains--;			/* I've done */
+					if (st->con != NULL)
+					{
+						PQfinish(st->con);
+						st->con = NULL;
+					}
+					return;
+				}
+				break;
+		}
+
+		/* increment state counter */
+		st->state++;
+		if (st->state > 6)
+		{
+			st->state = 0;
+			remains--;			/* I've done */
+		}
+	}
+
+	if (st->con == NULL)
+	{
+		if ((st->con = doConnect()) == NULL)
+		{
+			fprintf(stderr, "Client aborted in establishing connection.\n");
+			remains--;			/* I've aborted */
+			PQfinish(st->con);
+			st->con = NULL;
+			return;
+		}
+	}
+
+	switch (st->state)
+	{
+		case 0:			/* about to start */
+			if (ttype == WITH_TRANSACTION)
+			{
+				strcpy(sql, "begin");
+			}
+			else
+			{
+				st->aid = getrand(1, naccounts * tps);
+				snprintf(sql, 256, "select abalance from accounts where aid = %d", st->aid);
+			}
+			st->aid = getrand(1, naccounts * tps);
+			st->bid = getrand(1, nbranches * tps);
+			st->tid = getrand(1, ntellers * tps);
+			st->delta = getrand(1, 1000);
+			if (use_log)
+				gettimeofday(&(st->txn_begin), 0);
+			break;
+		case 1:
+			snprintf(sql, 256, "update accounts set abalance = abalance + %d where aid = %d\n", st->delta, st->aid);
+			break;
+		case 2:
+			snprintf(sql, 256, "select abalance from accounts where aid = %d", st->aid);
+			break;
+		case 3:
+			if (ttype == 0)
+			{
+				snprintf(sql, 256, "update tellers set tbalance = tbalance + %d where tid = %d\n",
+						 st->delta, st->tid);
+				break;
+			}
+		case 4:
+			if (ttype == 0)
+			{
+				snprintf(sql, 256, "update branches set bbalance = bbalance + %d where bid = %d", st->delta, st->bid);
+				break;
+			}
+		case 5:
+			snprintf(sql, 256, "insert into history(tid,bid,aid,delta,mtime) values(%d,%d,%d,%d,'now')",
+					 st->tid, st->bid, st->aid, st->delta);
+			break;
+		case 6:
+			if (ttype == WITH_TRANSACTION)
+			{
+				strcpy(sql, "end");
+			}
+			else
+			{
+				st->aid = getrand(1, naccounts * tps);
+				snprintf(sql, 256, "select abalance from accounts where aid = %d", st->aid);
+			}
+			break;
+	}
+
+	if (debug)
+		fprintf(stderr, "client sending %s\n", sql);
+
+	if (PQsendQuery(st->con, sql) == 0)
+	{
+		if (debug)
+			fprintf(stderr, "PQsendQuery(%s)failed\n", sql);
+		st->ecnt++;
+	}
+	else
+	{
+		st->listen++;			/* flags that should be listened */
+	}
+}
+
+/* process a select only transaction */
+static void
+doOne(CState * st, int debug, int ttype )
+{
+	char		sql[256];
+	PGresult   *res;
+
+	if (st->listen)
+	{							/* are we receiver? */
+		if (debug)
+			fprintf(stderr, "client receiving\n");
+		if (!PQconsumeInput(st->con))
+		{						/* there's something wrong */
+			fprintf(stderr, "Client aborted in state %d. Probably the backend died while processing.\n", st->state);
+			remains--;			/* I've aborted */
+			PQfinish(st->con);
+			st->con = NULL;
+			return;
+		}
+		if (PQisBusy(st->con))
+			return;				/* don't have the whole result yet */
+
+		switch (st->state)
+		{
+			case 0:				/* response to "select abalance ..." */
+				res = PQgetResult(st->con);
+				if (ttype == SELECT_ONLY)
+				{
+					if (check(st, res, PGRES_TUPLES_OK))
+						return;
+				}
+				else
+				{
+					if (check(st, res, PGRES_COMMAND_OK))
+						return;
+				}
+				PQclear(res);
+				discard_response(st);
+
+				if (is_connect)
+				{
+					PQfinish(st->con);
+					st->con = NULL;
+				}
+
+				if (++st->cnt >= st->maxAct)
+				{
+					remains--;			/* I've done */
+					if (st->con != NULL)
+					{
+						PQfinish(st->con);
+						st->con = NULL;
+					}
+					return;
+				}
+				break;
+		}
+
+		/* increment state counter */
+		st->state++;
+		if (st->state > 0)
+		{
+			st->state = 0;
+			remains--;	/* I've done */
+		}
+	}
+
+	if (st->con == NULL)
+	{
+		if ((st->con = doConnect()) == NULL)
+		{
+			fprintf(stderr, "Client aborted in establishing connection.\n");
+			PQfinish(st->con);
+			st->con = NULL;
+			return;
+		}
+	}
+
+	switch (st->state)
+	{
+		case 0:
+			st->aid = getrand(1, naccounts * tps);
+			st->bid = getrand(1, nbranches * tps);
+			st->tid = getrand(1, ntellers * tps);
+			st->delta = getrand(1, 1000);
+			if ( ttype == SELECT_ONLY)
+			{
+				snprintf(sql, 256, "select abalance from accounts where aid = %d", st->aid);
+			}
+			if ( ttype == UPDATE_ONLY)
+			{
+				snprintf(sql, 256, "update accounts set abalance = abalance + %d where aid = %d\n", st->delta, st->aid);
+			}
+			if ( ttype == INSERT_ONLY)
+			{
+				snprintf(sql, 256, "insert into history(tid,bid,aid,delta,mtime) values(%d,%d,%d,%d,'now')",
+						 st->tid, st->bid, st->aid, st->delta);
+			}
+			break;
+	}
+
+	if (debug)
+		fprintf(stderr, "client sending %s\n", sql);
+
+	if (PQsendQuery(st->con, sql) == 0)
+	{
+		if (debug)
+			fprintf(stderr, "PQsendQuery(%s)failed\n", sql);
+		st->ecnt++;
+	}
+	else
+	{
+		st->listen++;			/* flags that should be listened */
+	}
+}
+
+/* discard connections */
+static void
+disconnect_all(CState * state)
+{
+	if (state->con)
+		PQfinish(state->con);
+}
+
+/* create tables and setup data */
+static void
+init(void)
+{
+	PGconn	   *con;
+	PGresult   *res;
+	static char *DDLs[] = {
+		"drop table branches",
+		"create table branches(bid int, primary key(bid),bbalance int,filler char(88))",
+		"drop table tellers",
+		"create table tellers(tid int, primary key(tid),bid int,tbalance int,filler char(84))",
+		"drop table accounts",
+		"create table accounts(aid int,primary key(aid),bid int,abalance int,filler char(84))",
+		"drop table history",
+	"create table history(tid int,bid int,aid int,delta int,mtime timestamp,filler char(22))"};
+	char		sql[256];
+
+	int			i;
+
+	if ((con = doConnect()) == NULL)
+		exit(1);
+
+	for (i = 0; i < (sizeof(DDLs) / sizeof(char *)); i++)
+	{
+		res = PQexec(con, DDLs[i]);
+		if (strncmp(DDLs[i], "drop", 4) && PQresultStatus(res) != PGRES_COMMAND_OK)
+		{
+			fprintf(stderr, "%s", PQerrorMessage(con));
+			exit(1);
+		}
+		PQclear(res);
+	}
+
+	res = PQexec(con, "begin");
+	if (PQresultStatus(res) != PGRES_COMMAND_OK)
+	{
+		fprintf(stderr, "%s", PQerrorMessage(con));
+		exit(1);
+	}
+	PQclear(res);
+
+	for (i = 0; i < nbranches * tps; i++)
+	{
+		snprintf(sql, 256, "insert into branches(bid,bbalance) values(%d,0)", i + 1);
+		res = PQexec(con, sql);
+		if (PQresultStatus(res) != PGRES_COMMAND_OK)
+		{
+			fprintf(stderr, "%s", PQerrorMessage(con));
+			exit(1);
+		}
+		PQclear(res);
+	}
+
+	for (i = 0; i < ntellers * tps; i++)
+	{
+		snprintf(sql, 256, "insert into tellers(tid,bid,tbalance) values (%d,%d,0)"
+				 ,i + 1, i / ntellers + 1);
+		res = PQexec(con, sql);
+		if (PQresultStatus(res) != PGRES_COMMAND_OK)
+		{
+			fprintf(stderr, "%s", PQerrorMessage(con));
+			exit(1);
+		}
+		PQclear(res);
+	}
+
+	res = PQexec(con, "end");
+	if (PQresultStatus(res) != PGRES_COMMAND_OK)
+	{
+		fprintf(stderr, "%s", PQerrorMessage(con));
+		exit(1);
+	}
+
+	/*
+	 * occupy accounts table with some data
+	 */
+	fprintf(stderr, "creating tables...\n");
+	for (i = 0; i < naccounts * tps; i++)
+	{
+		int			j = i + 1;
+
+		if (j % 10000 == 1)
+		{
+			res = PQexec(con, "copy accounts from stdin");
+			if (PQresultStatus(res) != PGRES_COPY_IN)
+			{
+				fprintf(stderr, "%s", PQerrorMessage(con));
+				exit(1);
+			}
+			PQclear(res);
+		}
+
+		snprintf(sql, 256, "%d\t%d\t%d\t\n", j, j / naccounts, 0);
+		if (PQputline(con, sql))
+		{
+			fprintf(stderr, "PQputline failed\n");
+			exit(1);
+		}
+
+		if (j % 10000 == 0)
+		{
+			/*
+			 * every 10000 tuples, we commit the copy command. this should
+			 * avoid generating too much WAL logs
+			 */
+			fprintf(stderr, "%d tuples done.\n", j);
+			if (PQputline(con, "\\.\n"))
+			{
+				fprintf(stderr, "very last PQputline failed\n");
+				exit(1);
+			}
+
+			if (PQendcopy(con))
+			{
+				fprintf(stderr, "PQendcopy failed\n");
+				exit(1);
+			}
+
+#ifdef NOT_USED
+
+			/*
+			 * do a checkpoint to purge the old WAL logs
+			 */
+			res = PQexec(con, "checkpoint");
+			if (PQresultStatus(res) != PGRES_COMMAND_OK)
+			{
+				fprintf(stderr, "%s", PQerrorMessage(con));
+				exit(1);
+			}
+			PQclear(res);
+#endif   /* NOT_USED */
+		}
+	}
+	/* vacuum */
+	fprintf(stderr, "vacuum...");
+	res = PQexec(con, "vacuum analyze");
+	if (PQresultStatus(res) != PGRES_COMMAND_OK)
+	{
+		fprintf(stderr, "%s", PQerrorMessage(con));
+		exit(1);
+	}
+	PQclear(res);
+	fprintf(stderr, "done.\n");
+
+	PQfinish(con);
+}
+
+/* print out results */
+static void
+printResults(
+			 int ttype, int normal_xacts,
+			 struct timeval * tv1, struct timeval * tv2,
+			 struct timeval * tv3)
+{
+	double		t1,
+				t2;
+	char	   *s;
+
+	t1 = (tv3->tv_sec - tv1->tv_sec) * 1000000.0 + (tv3->tv_usec - tv1->tv_usec);
+	t1 = t1 / 1000000.0 ;
+
+	t2 = (tv3->tv_sec - tv1->tv_sec) * 1000000.0 + (tv3->tv_usec - tv1->tv_usec);
+	t2 = normal_xacts * 1000000.0 / t2;
+
+#define SELECT_ONLY	(1)
+#define	INSERT_ONLY	(2)
+#define	UPDATE_ONLY	(3)
+#define	WITH_TRANSACTION	(4)
+	switch (ttype)
+	{
+		case 0:
+			s = "TPC-B (sort of)";
+			break;
+		case SELECT_ONLY :
+			s = "SELECT only";
+			break;
+		case INSERT_ONLY :
+			s = "INSERT only";
+			break;
+		case UPDATE_ONLY :
+			s = "UPDATE only";
+			break;
+		default:
+			s = "Mix query";
+			break;
+	}
+
+
+	printf("transaction type: %s\n", s);
+	printf("scaling factor: %d\n", tps);
+	printf("number of clients: %d\n", nclients);
+	printf("number of transactions actually processed: %d\n", normal_xacts );
+	printf("run time (sec) = %f \n", t1);
+	printf("tps = %f (including connections establishing)\n", t2);
+}
+
+static int
+doChild(int clientId, int min, int max, int debug, int ttype)
+{
+	CState state;		/* status of clients */
+
+	struct timeval tv1;			/* start up time */
+	fd_set		input_mask;
+	int			nsocks = 0;		/* return from select(2) */
+	int			sock = 0;
+
+	gettimeofday(&tv1, 0);
+	srand((uint) tv1.tv_usec + clientId );
+
+	memset((char *)&state,0,sizeof(CState));
+	/* make connections to the database */
+	state.id = clientId;
+	if ((state.con = doConnect()) == NULL)
+		exit(1);
+
+	state.maxAct = max - min + 1;
+	/* send start up queries in async manner */
+	switch (ttype)
+	{
+		case WITH_TRANSACTION :
+		case TPC_B_LIKE :
+			doMix(&state, debug, ttype);
+			break;
+		default :
+			doOne(&state, debug, ttype);
+			break;
+	}
+
+	remains = max;
+	for (;;)
+	{
+		if (remains < min)
+		{
+			break;
+		}
+
+		FD_ZERO(&input_mask);
+
+		if (state.con == NULL)
+		{
+			if ((state.con = doConnect()) == NULL)
+			{
+				exit(1);
+			}
+		}
+		sock = PQsocket(state.con);
+
+		if (sock < 0)
+		{
+			fprintf(stderr, "Client %d: PQsocket failed\n", clientId);
+			disconnect_all(&state);
+			exit(1);
+		}
+		FD_SET(sock, &input_mask);
+
+		if ((nsocks = select(sock + 1, &input_mask, (fd_set *) NULL,
+						  (fd_set *) NULL, (struct timeval *) NULL)) < 0)
+		{
+			if (errno == EINTR)
+				continue;
+			/* must be something wrong */
+			disconnect_all(&state);
+			fprintf(stderr, "select failed: %s\n", strerror(errno));
+			exit(1);
+		}
+		else if (nsocks == 0)
+		{						/* timeout */
+			fprintf(stderr, "select timeout\n");
+			fprintf(stderr, "client %d:state %d cnt %d ecnt %d listen %d\n",
+					clientId, state.state, state.cnt, state.ecnt, state.listen);
+			exit(0);
+		}
+
+		/* ok, backend returns reply */
+		if (state.con && FD_ISSET(PQsocket(state.con), &input_mask))
+		{
+			switch (ttype)
+			{
+				case WITH_TRANSACTION :
+				case TPC_B_LIKE :
+					doMix(&state, debug, ttype);
+					break;
+				default :
+					doOne(&state, debug, ttype);
+					break;
+			}
+		}
+	}
+	disconnect_all(&state);
+	return 1;
+}
+
+static int
+doClient(int debug, int ttype)
+{
+	pid_t pid;
+	int i;
+	int min,max;
+	int base,mo;
+
+	base = nxacts / nclients;
+	mo = nxacts % nclients;
+	min = max = 0;
+	for ( i = 0 ; i < nclients ; i ++)
+	{
+		min = max + 1;
+		max += base;
+		if (mo > 0)
+		{
+			max += 1;
+			mo --;
+		}
+		pid = fork();
+		if (pid == 0)
+		{
+			doChild(i, min, max, debug, ttype);
+			exit(0);
+		}
+	}
+	while ( wait(NULL) > 0)
+		;
+	return 1;
+}
+
+int
+main(int argc, char **argv)
+{
+	extern char *optarg;
+	extern int	optind;
+	int			c;
+	int			is_init_mode = 0;		/* initialize mode? */
+	int			is_no_vacuum = 0;		/* no vacuum at all before
+										 * testing? */
+	int			is_full_vacuum = 0;		/* do full vacuum before testing? */
+	int			debug = 0;		/* debug flag */
+	int			ttype = TPC_B_LIKE;		/* transaction type */
+
+	struct timeval tv1;			/* start up time */
+	struct timeval tv2;			/* after establishing all connections to
+								 * the backend */
+	struct timeval tv3;			/* end time */
+
+#ifndef __CYGWIN__
+	struct rlimit rlim;
+#endif
+
+	PGconn	   *con;
+	PGresult   *res;
+
+	while ((c = getopt(argc, argv, "ih:nvp:dc:t:s:u:P:CNSlTUI")) != -1)
+	{
+		switch (c)
+		{
+			case 'i':
+				is_init_mode++;
+				break;
+			case 'h':
+				pghost = optarg;
+				break;
+			case 'n':
+				is_no_vacuum++;
+				break;
+			case 'v':
+				is_full_vacuum++;
+				break;
+			case 'p':
+				pgport = optarg;
+				break;
+			case 'd':
+				debug++;
+				break;
+			case 'S':
+				ttype = SELECT_ONLY;
+				break;
+			case 'I':
+				ttype = INSERT_ONLY;
+				break;
+			case 'U':
+				ttype = UPDATE_ONLY;
+				break;
+			case 'T':
+				ttype = WITH_TRANSACTION;
+				break;
+			case 'c':
+				nclients = atoi(optarg);
+				if (nclients <= 0 || nclients > MAXCLIENTS)
+				{
+					fprintf(stderr, "invalid number of clients: %d\n", nclients);
+					exit(1);
+				}
+#ifndef __CYGWIN__
+#ifdef RLIMIT_NOFILE			/* most platform uses RLIMIT_NOFILE */
+				if (getrlimit(RLIMIT_NOFILE, &rlim) == -1)
+				{
+#else							/* but BSD doesn't ... */
+				if (getrlimit(RLIMIT_OFILE, &rlim) == -1)
+				{
+#endif   /* HAVE_RLIMIT_NOFILE */
+					fprintf(stderr, "getrlimit failed. reason: %s\n", strerror(errno));
+					exit(1);
+				}
+				if (rlim.rlim_cur <= (nclients + 2))
+				{
+					fprintf(stderr, "You need at least %d open files resource but you are only allowed to use %ld.\n", nclients + 2, (long) rlim.rlim_cur);
+					fprintf(stderr, "Use limit/ulimt to increase the limit before using pgbench.\n");
+					exit(1);
+				}
+#endif   /* #ifndef __CYGWIN__ */
+				break;
+			case 'C':
+				is_connect = 1;
+				break;
+			case 's':
+				tps = atoi(optarg);
+				if (tps <= 0)
+				{
+					fprintf(stderr, "invalid scaling factor: %d\n", tps);
+					exit(1);
+				}
+				break;
+			case 't':
+				nxacts = atoi(optarg);
+				if (nxacts <= 0)
+				{
+					fprintf(stderr, "invalid number of transactions: %d\n", nxacts);
+					exit(1);
+				}
+				break;
+			case 'u':
+				login = optarg;
+				break;
+			case 'P':
+				pwd = optarg;
+				break;
+			case 'l':
+				use_log = true;
+				break;
+			default:
+				usage();
+				exit(1);
+				break;
+		}
+	}
+
+	if (argc > optind)
+		dbName = argv[optind];
+	else
+	{
+		dbName = getenv("USER");
+		if (dbName == NULL)
+			dbName = "";
+	}
+
+	if (is_init_mode)
+	{
+		init();
+		exit(0);
+	}
+
+	if (use_log)
+	{
+		char		logpath[64];
+
+		snprintf(logpath, 64, "pgbench_log.%d", getpid());
+		LOGFILE = fopen(logpath, "w");
+
+		if (LOGFILE == NULL)
+		{
+			fprintf(stderr, "Couldn't open logfile \"%s\": %s", logpath, strerror(errno));
+			exit(1);
+		}
+	}
+
+	if (debug)
+	{
+		printf("pghost: %s pgport: %s nclients: %d nxacts: %d dbName: %s\n",
+			   pghost, pgport, nclients, nxacts, dbName);
+	}
+
+	/* opening connection... */
+	con = doConnect();
+	if (con == NULL)
+		exit(1);
+
+	if (PQstatus(con) == CONNECTION_BAD)
+	{
+		fprintf(stderr, "Connection to database '%s' failed.\n", dbName);
+		fprintf(stderr, "%s", PQerrorMessage(con));
+		exit(1);
+	}
+
+	/*
+	 * get the scaling factor that should be same as count(*) from
+	 * branches...
+	 */
+	res = PQexec(con, "select count(*) from branches");
+	if (PQresultStatus(res) != PGRES_TUPLES_OK)
+	{
+		fprintf(stderr, "%s", PQerrorMessage(con));
+		exit(1);
+	}
+	tps = atoi(PQgetvalue(res, 0, 0));
+	if (tps < 0)
+	{
+		fprintf(stderr, "count(*) from branches invalid (%d)\n", tps);
+		exit(1);
+	}
+	PQclear(res);
+
+	if (!is_no_vacuum)
+	{
+		fprintf(stderr, "starting vacuum...");
+		res = PQexec(con, "vacuum branches");
+		if (PQresultStatus(res) != PGRES_COMMAND_OK)
+		{
+			fprintf(stderr, "%s", PQerrorMessage(con));
+			exit(1);
+		}
+		PQclear(res);
+
+		res = PQexec(con, "vacuum tellers");
+		if (PQresultStatus(res) != PGRES_COMMAND_OK)
+		{
+			fprintf(stderr, "%s", PQerrorMessage(con));
+			exit(1);
+		}
+		PQclear(res);
+
+		res = PQexec(con, "delete from history");
+		if (PQresultStatus(res) != PGRES_COMMAND_OK)
+		{
+			fprintf(stderr, "%s", PQerrorMessage(con));
+			exit(1);
+		}
+		PQclear(res);
+		res = PQexec(con, "vacuum history");
+		if (PQresultStatus(res) != PGRES_COMMAND_OK)
+		{
+			fprintf(stderr, "%s", PQerrorMessage(con));
+			exit(1);
+		}
+		PQclear(res);
+
+		fprintf(stderr, "end.\n");
+
+		if (is_full_vacuum)
+		{
+			fprintf(stderr, "starting full vacuum...");
+			res = PQexec(con, "vacuum analyze accounts");
+			if (PQresultStatus(res) != PGRES_COMMAND_OK)
+			{
+				fprintf(stderr, "%s", PQerrorMessage(con));
+				exit(1);
+			}
+			PQclear(res);
+			fprintf(stderr, "end.\n");
+		}
+	}
+	PQfinish(con);
+	
+	/* set random seed */
+	gettimeofday(&tv1, 0);
+	srand((uint) tv1.tv_usec);
+	/* get start up time */
+	gettimeofday(&tv1, 0);
+	/* time after connections set up */
+	gettimeofday(&tv2, 0);
+
+	doClient(debug, ttype);
+
+	/* get end time */
+	gettimeofday(&tv3, 0);
+	printResults(ttype, nxacts, &tv1, &tv2, &tv3);
+	if (LOGFILE)
+		fclose(LOGFILE);
+	return 1;
+}
