Skip to Content.
Sympa Menu

sm-commit - Re: [SM-Commit] GIT changes to master grimoire by Arjan Bouter (3938db04ccd796caf6c0af01356e054cd355dc01)

sm-commit AT lists.ibiblio.org

Subject: Source Mage code commit list

List archive

Chronological Thread  
  • From: Andrew Stitt <afrayedknot AT thefrayedknot.armory.com>
  • To: sm-commit AT lists.ibiblio.org
  • Subject: Re: [SM-Commit] GIT changes to master grimoire by Arjan Bouter (3938db04ccd796caf6c0af01356e054cd355dc01)
  • Date: Fri, 10 Nov 2006 22:12:44 -0800

Does a patch this size really belong in the grimoire? Can't we just host
it on ibiblio?

On Thu, Nov 09, 2006 at 12:30:31PM -0600, Arjan Bouter wrote:
> GIT changes to master grimoire by Arjan Bouter <abouter AT sourcemage.org>:
>
> database/postgresql/HISTORY | 4
> database/postgresql/PREPARE | 1
> database/postgresql/PRE_BUILD | 9
> database/postgresql/pgcluster-1.5.0rc7-smgl-patch |30328
> ++++++++++++++++++++++
> 4 files changed, 30339 insertions(+), 3 deletions(-)
>
> New commits:
> commit 3938db04ccd796caf6c0af01356e054cd355dc01
> Author: Arjan Bouter <abouter AT sourcemage.org>
> Commit: Arjan Bouter <abouter AT sourcemage.org>
>
> postgresql: added pgcluster support
>
> diff --git a/database/postgresql/HISTORY b/database/postgresql/HISTORY
> index 0866731..a0b739b 100644
> --- a/database/postgresql/HISTORY
> +++ b/database/postgresql/HISTORY
> @@ -1,3 +1,7 @@
> +2006-11-09 Arjan Bouter <abouter AT sourcemage.org>
> + * PREPARE, PRE_BUILD: added
> + * pgcluster-1.5.0rc7-smgl.patch: added
> +
> 2006-10-14 Ladislav Hagara <hgr AT vabo.cz>
> * DETAILS: 8.1.5
> * FINAL: removed 8.0.3 related message
> diff --git a/database/postgresql/PREPARE b/database/postgresql/PREPARE
> new file mode 100755
> index 0000000..4dd13d2
> --- /dev/null
> +++ b/database/postgresql/PREPARE
> @@ -0,0 +1 @@
> +config_query PGSQL_CLUSTER 'Do you want to apply the PGCluster patch?' n
> diff --git a/database/postgresql/PRE_BUILD b/database/postgresql/PRE_BUILD
> index 940e3da..05c5e75 100755
> --- a/database/postgresql/PRE_BUILD
> +++ b/database/postgresql/PRE_BUILD
> @@ -1,3 +1,6 @@
> - create_account postgres &&
> - default_pre_build
> -
> +create_account postgres &&
> +default_pre_build &&
> +cd $SOURCE_DIRECTORY &&
> +if [ "$PGSQL_CLUSTER" = "y" ]; then
> + patch -p1 < $SCRIPT_DIRECTORY/pgcluster-1.5.0rc7-smgl-patch
> +fi
> diff --git a/database/postgresql/pgcluster-1.5.0rc7-smgl-patch
> b/database/postgresql/pgcluster-1.5.0rc7-smgl-patch
> new file mode 100644
> index 0000000..9a8f385
> --- /dev/null
> +++ b/database/postgresql/pgcluster-1.5.0rc7-smgl-patch
> @@ -0,0 +1,30328 @@
> +diff -aruN postgresql-8.1.2/GNUmakefile.in
> pgcluster-1.5.0rc7/GNUmakefile.in
> +--- postgresql-8.1.2/GNUmakefile.in 2005-05-01 08:15:51.000000000 +0200
> ++++ pgcluster-1.5.0rc7/GNUmakefile.in 2006-01-10 17:39:30.000000000
> +0100
> +@@ -57,13 +57,13 @@
> +
> + ##########################################################################
> +
> +-distdir := postgresql-$(VERSION)
> ++distdir := pgcluster-$(PGCLUSTER_VERSION)
> + dummy := =install=
> +-garbage := =* "#"* ."#"* *~* *.orig *.rej core postgresql-*
> ++garbage := =* "#"* ."#"* *~* *.orig *.rej core pgcluster-*
> +
> + dist: $(distdir).tar.gz
> + ifeq ($(split-dist), yes)
> +-dist: postgresql-base-$(VERSION).tar.gz postgresql-docs-$(VERSION).tar.gz
> postgresql-opt-$(VERSION).tar.gz postgresql-test-$(VERSION).tar.gz
> ++dist: pgcluster-base-$(PGCLUSTER_VERSION).tar.gz
> pgcluster-docs-$(PGCLUSTER_VERSION).tar.gz
> pgcluster-opt-$(PGCLUSTER_VERSION).tar.gz
> pgcluster-test-$(PGCLUSTER_VERSION).tar.gz
> + endif
> + dist:
> + -rm -rf $(distdir)
> +@@ -75,19 +75,19 @@
> + src/tools src/tutorial \
> + $(addprefix src/pl/, plperl plpython tcl)
> +
> +-docs_files := doc/postgres.tar.gz doc/src doc/TODO.detail
> ++docs_files := doc/pgcluster.tar.gz doc/src doc/TODO.detail
> +
> +-postgresql-base-$(VERSION).tar: distdir
> ++pgcluster-base-$(PGCLUSTER_VERSION).tar: distdir
> + $(TAR) -c $(addprefix --exclude $(distdir)/, $(docs_files)
> $(opt_files) src/test) \
> + -f $@ $(distdir)
> +
> +-postgresql-docs-$(VERSION).tar: distdir
> ++pgcluster-docs-$(PGCLUSTER_VERSION).tar: distdir
> + $(TAR) cf $@ $(addprefix $(distdir)/, $(docs_files))
> +
> +-postgresql-opt-$(VERSION).tar: distdir
> ++pgcluster-opt-$(PGCLUSTER_VERSION).tar: distdir
> + $(TAR) cf $@ $(addprefix $(distdir)/, $(opt_files))
> +
> +-postgresql-test-$(VERSION).tar: distdir
> ++pgcluster-test-$(PGCLUSTER_VERSION).tar: distdir
> + $(TAR) cf $@ $(distdir)/src/test
> +
> + distdir:
> +diff -aruN postgresql-8.1.2/INSTALL_PGCLUSTER
> pgcluster-1.5.0rc7/INSTALL_PGCLUSTER
> +--- postgresql-8.1.2/INSTALL_PGCLUSTER 1970-01-01 01:00:00.000000000
> +0100
> ++++ pgcluster-1.5.0rc7/INSTALL_PGCLUSTER 2006-02-09 17:55:54.000000000
> +0100
> +@@ -0,0 +1,286 @@
> ++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/share' in default)
> ++----------------------------------------------------------------
> ++$cd /usr/local/pgsql/share
> ++$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/share' in default)
> ++----------------------------------------------------------------
> ++$cd /usr/local/pgsql/share
> ++$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>
> ++#-------------------------------------------------------------
> ++# A setup of a replication server
> ++#
> ++# o Replicate_Port : connection for replication
> ++# o Recovery_Port : connection for recovery
> ++# 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 : use replication log
> ++# [yes/no]. default : no
> ++# o RLOG_Port : connection for replication log
> ++#-------------------------------------------------------------
> ++<Replication_Port> 8001 </Replication_Port>
> ++<Recovery_Port> 8101 </Recovery_Port>
> ++<Response_Mode> normal </Response_Mode>
> ++<Use_Replication_Log> no </Use_Replication_Log>
> ++<RLOG_Port> 8301 </RLOG_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/share
> ++----------------------------------------------------------------
> ++
> ++B. Stop load balance server
> ++----------------------------------------------------------------
> ++$ /usr/local/pgsql/bin/pglb -D /usr/local/pgsql/share 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 -aruN postgresql-8.1.2/README_PGCLUSTER
> pgcluster-1.5.0rc7/README_PGCLUSTER
> +--- postgresql-8.1.2/README_PGCLUSTER 1970-01-01 01:00:00.000000000
> +0100
> ++++ pgcluster-1.5.0rc7/README_PGCLUSTER 2006-01-10 17:39:32.000000000
> +0100
> +@@ -0,0 +1,47 @@
> ++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/catalog/pg_depend.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/recovery.c
> ++ src/backend/libpq/relicate.c
> ++ src/backend/libpq/relicate_com.c
> ++ src/backend/libpq/cluster.conf.sample
> ++ 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 -aruN postgresql-8.1.2/configure pgcluster-1.5.0rc7/configure
> +--- postgresql-8.1.2/configure 2006-01-05 05:02:18.000000000 +0100
> ++++ pgcluster-1.5.0rc7/configure 2006-02-09 17:47:19.000000000 +0100
> +@@ -275,6 +275,8 @@
> + PACKAGE_STRING='PostgreSQL 8.1.2'
> + PACKAGE_BUGREPORT='pgsql-bugs AT postgresql.org'
> +
> ++PGCLUSTER_VERSION='1.5.0rc7'
> ++
> + ac_unique_file="src/backend/access/common/heaptuple.c"
> + ac_default_prefix=/usr/local/pgsql
> + # Factoring default headers for most tests.
> +@@ -314,7 +316,7 @@
> + # include <unistd.h>
> + #endif"
> +
> +-ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME
> PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix
> program_transform_name bindir sbindir libexecdir datadir sysconfdir
> sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir
> build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS
> configure_args build build_cpu build_vendor build_os host host_cpu
> host_vendor host_os PORTNAME docdir enable_nls WANTED_LANGUAGES
> default_port enable_shared enable_rpath enable_debug CC CFLAGS LDFLAGS
> CPPFLAGS ac_ct_CC EXEEXT OBJEXT CPP GCC TAS autodepend INCLUDES
> enable_thread_safety with_tcl with_perl with_python with_krb5 krb_srvtab
> with_pam with_bonjour with_openssl with_zlib EGREP ELF_SYS LDFLAGS_SL AWK
> FLEX FLEXFLAGS LN_S LD with_gnu_ld ld_R_works RANLIB ac_ct_RANLIB LORDER
> TAR STRIP ac_ct_STRIP STRIP_STATIC_LIB STRIP_SHARED_LIB YACC YFLAGS PERL
> perl_archlibexp perl_privlibexp perl_useshrplib perl_embed_ldflags PYTHON
> python_vers
> ion python_configdir python_includespec python_libdir python_libspec
> python_additional_libs HAVE_IPV6 LIBOBJS acx_pthread_config PTHREAD_CC
> PTHREAD_LIBS PTHREAD_CFLAGS HAVE_POSIX_SIGNALS MSGFMT MSGMERGE XGETTEXT
> localedir TCLSH TCL_CONFIG_SH TCL_INCLUDE_SPEC TCL_LIB_FILE TCL_LIBS
> TCL_LIB_SPEC TCL_SHARED_BUILD TCL_SHLIB_LD_LIBS NSGMLS JADE have_docbook
> DOCBOOKSTYLE COLLATEINDEX SGMLSPL vpath_build LTLIBOBJS'
> ++ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME
> PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix
> program_transform_name bindir sbindir libexecdir datadir sysconfdir
> sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir
> build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS
> configure_args build build_cpu build_vendor build_os host host_cpu
> host_vendor host_os PORTNAME docdir enable_nls WANTED_LANGUAGES
> default_port enable_shared enable_rpath enable_debug CC CFLAGS LDFLAGS
> CPPFLAGS ac_ct_CC EXEEXT OBJEXT CPP GCC TAS autodepend INCLUDES
> enable_thread_safety with_tcl with_perl with_python with_krb5 krb_srvtab
> with_pam with_bonjour with_openssl with_zlib EGREP ELF_SYS LDFLAGS_SL AWK
> FLEX FLEXFLAGS LN_S LD with_gnu_ld ld_R_works RANLIB ac_ct_RANLIB LORDER
> TAR STRIP ac_ct_STRIP STRIP_STATIC_LIB STRIP_SHARED_LIB YACC YFLAGS PERL
> perl_archlibexp perl_privlibexp perl_useshrplib perl_embed_ldflags PYTHON
> python_vers
> ion python_configdir python_includespec python_libdir python_libspec
> python_additional_libs HAVE_IPV6 LIBOBJS acx_pthread_config PTHREAD_CC
> PTHREAD_LIBS PTHREAD_CFLAGS HAVE_POSIX_SIGNALS MSGFMT MSGMERGE XGETTEXT
> localedir TCLSH TCL_CONFIG_SH TCL_INCLUDE_SPEC TCL_LIB_FILE TCL_LIBS
> TCL_LIB_SPEC TCL_SHARED_BUILD TCL_SHLIB_LD_LIBS NSGMLS JADE have_docbook
> DOCBOOKSTYLE COLLATEINDEX SGMLSPL vpath_build LTLIBOBJS PGCLUSTER_VERSION'
> + ac_subst_files=''
> +
> + # Initialize some variables set by options.
> +@@ -1238,6 +1240,10 @@
> + #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
> + _ACEOF
> +
> ++cat >>confdefs.h <<_ACEOF
> ++#define PGCLUSTER_VERSION "$PGCLUSTER_VERSION"
> ++_ACEOF
> ++
> +
> + # Let the site file select an alternate cache file if it wants to.
> + # Prefer explicitly selected file to automatically selected ones.
> +@@ -1361,6 +1367,8 @@
> +
> +
> +
> ++
> ++
> + ac_aux_dir=
> + for ac_dir in config $srcdir/config; do
> + if test -f $ac_dir/install-sh; then
> +@@ -23204,6 +23212,7 @@
> + s,@host_os@,$host_os,;t t
> + s,@PORTNAME@,$PORTNAME,;t t
> + s,@docdir@,$docdir,;t t
> ++s,@PGCLUSTER_VERSION@,$PGCLUSTER_VERSION,;t t
> + s,@enable_nls@,$enable_nls,;t t
> + s,@WANTED_LANGUAGES@,$WANTED_LANGUAGES,;t t
> + s,@default_port@,$default_port,;t t
> +diff -aruN postgresql-8.1.2/configure.in pgcluster-1.5.0rc7/configure.in
> +--- postgresql-8.1.2/configure.in 2006-01-05 05:02:23.000000000 +0100
> ++++ pgcluster-1.5.0rc7/configure.in 2006-01-10 17:39:30.000000000 +0100
> +@@ -27,6 +27,7 @@
> + AC_SUBST(configure_args, [$ac_configure_args])
> +
> + AC_DEFINE_UNQUOTED(PG_VERSION, "$PACKAGE_VERSION", [PostgreSQL version])
> ++AC_DEFINE_UNQUOTED(PGCLUSTER_VERSION, "$PGCLUSTER_VERSION", [PGCluster
> version])
> +
> + AC_CANONICAL_HOST
> +
> +diff -aruN postgresql-8.1.2/pgcluster.sh.tmpl
> pgcluster-1.5.0rc7/pgcluster.sh.tmpl
> +--- postgresql-8.1.2/pgcluster.sh.tmpl 1970-01-01 01:00:00.000000000
> +0100
> ++++ pgcluster-1.5.0rc7/pgcluster.sh.tmpl 2006-01-10 17:39:30.000000000
> +0100
> +@@ -0,0 +1,56 @@
> ++#!/bin/sh
> ++#
> ++# $FreeBSD: ports/databases/pgcluster/files/pgcluster.sh.tmpl,v 1.1
> 2004/01/26 09:02:45 kuriyama Exp $
> ++#
> ++# PROVIDE: pgcluster
> ++# REQUIRE: DAEMON
> ++# BEFORE: pgreplicate
> ++# KEYWORD: FreeBSD
> ++#
> ++# Add the following line to /etc/rc.conf to enable pgcluster:
> ++#
> ++# pgcluster_enable="YES"
> ++# # optional
> ++# pgcluster_data="/home/pgsql/data"
> ++# pgcluster_flags="-w -s"
> ++#
> ++
> ++pgcluster_enable="NO"
> ++pgcluster_data="%%PREFIX%%/pgsql/data"
> ++pgcluster_flags="-w -s"
> ++
> ++. %%RC_SUBR%%
> ++
> ++load_rc_config pgcluster
> ++
> ++name=pgcluster
> ++command=%%PREFIX%%/bin/pg_ctl
> ++pgcluster_user=pgsql
> ++extra_commands="initdb recover"
> ++initdb_cmd="pgcluster_initdb"
> ++recover_cmd="pgcluster_recover"
> ++start_cmd="pgcluster_start"
> ++stop_cmd="pgcluster_stop"
> ++
> ++pgcluster_flags="${pgcluster_flags} -D ${pgcluster_data}"
> ++pidfile="${pgcluster_data}/postmaster.pid"
> ++
> ++pgcluster_start()
> ++{
> ++ su -m ${pgcluster_user} -c "exec ${command} start ${pgcluster_flags}
> -o '-i'"
> ++}
> ++pgcluster_stop()
> ++{
> ++ su -m ${pgcluster_user} -c "exec ${command} stop ${pgcluster_flags}
> -m i"
> ++}
> ++pgcluster_recover()
> ++{
> ++ su -m ${pgcluster_user} -c "exec ${command} start ${pgcluster_flags}
> -o '-i -R'"
> ++}
> ++pgcluster_initdb()
> ++{
> ++ su -m ${pgcluster_user} -c "exec %%PREFIX%%/bin/initdb -D
> ${pgcluster_data}"
> ++}
> ++
> ++load_rc_config $name
> ++run_rc_command "$1"
> +diff -aruN postgresql-8.1.2/src/Makefile pgcluster-1.5.0rc7/src/Makefile
> +--- postgresql-8.1.2/src/Makefile 2005-01-13 19:23:21.000000000 +0100
> ++++ pgcluster-1.5.0rc7/src/Makefile 2006-01-10 17:39:48.000000000 +0100
> +@@ -16,14 +16,15 @@
> + all install installdirs uninstall dep depend distprep:
> + $(MAKE) -C port $@
> + $(MAKE) -C timezone $@
> ++ $(MAKE) -C interfaces $@
> + $(MAKE) -C backend $@
> + $(MAKE) -C backend/utils/mb/conversion_procs $@
> + $(MAKE) -C include $@
> +- $(MAKE) -C interfaces $@
> + $(MAKE) -C bin $@
> + $(MAKE) -C pl $@
> + $(MAKE) -C makefiles $@
> + $(MAKE) -C utils $@
> ++ $(MAKE) -C pgcluster $@
> +
> + install: install-local
> +
> +@@ -44,6 +45,7 @@
> + rm -f $(addprefix $(DESTDIR)$(pgxsdir)/$(subdir), Makefile.global
> Makefile.port Makefile.shlib nls-global.mk)
> +
> + clean:
> ++ $(MAKE) -C pgcluster $@
> + $(MAKE) -C port $@
> + $(MAKE) -C timezone $@
> + $(MAKE) -C backend $@
> +@@ -58,6 +60,7 @@
> + $(MAKE) -C tools/thread $@
> +
> + distclean maintainer-clean:
> ++ -$(MAKE) -C pgcluster $@
> + -$(MAKE) -C port $@
> + -$(MAKE) -C timezone $@
> + -$(MAKE) -C backend $@
> +diff -aruN postgresql-8.1.2/src/Makefile.global.in
> pgcluster-1.5.0rc7/src/Makefile.global.in
> +--- postgresql-8.1.2/src/Makefile.global.in 2005-09-27 19:39:32.000000000
> +0200
> ++++ pgcluster-1.5.0rc7/src/Makefile.global.in 2006-01-10
> 17:39:48.000000000 +0100
> +@@ -31,6 +31,9 @@
> + # PostgreSQL version number
> + VERSION = @PACKAGE_VERSION@
> +
> ++# PGCluster version number
> ++PGCLUSTER_VERSION = @PGCLUSTER_VERSION@
> ++
> + # Support for VPATH builds
> + vpath_build = @vpath_build@
> + abs_top_srcdir = @abs_top_srcdir@
> +@@ -204,6 +207,7 @@
> + GCC = @GCC@
> + CFLAGS = @CFLAGS@
> +
> ++CFLAGS += -DUSE_REPLICATION -DPRINT_DEBUG
> + # Kind-of compilers
> +
> + YACC = @YACC@
> +diff -aruN postgresql-8.1.2/src/backend/Makefile
> pgcluster-1.5.0rc7/src/backend/Makefile
> +--- postgresql-8.1.2/src/backend/Makefile 2005-10-27 22:45:29.000000000
> +0200
> ++++ pgcluster-1.5.0rc7/src/backend/Makefile 2006-01-10 17:39:39.000000000
> +0100
> +@@ -40,7 +40,7 @@
> + ifneq ($(PORTNAME), win32)
> + ifneq ($(PORTNAME), aix)
> +
> +-postgres: $(OBJS)
> ++postgres: $(OBJS) $(libpq_srcdir)/libpq.a
> + $(CC) $(CFLAGS) $(LDFLAGS) $(export_dynamic) $^ $(LIBS) -o $@
> +
> + endif
> +@@ -169,6 +169,7 @@
> + $(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)/access/transam/recovery.conf.sample
> $(DESTDIR)$(datadir)/recovery.conf.sample
> ++ $(INSTALL_DATA) $(srcdir)/libpq/cluster.conf.sample
> $(DESTDIR)$(datadir)/cluster.conf.sample
> +
> + install-bin: postgres $(POSTGRES_IMP) installdirs
> + $(INSTALL_PROGRAM) postgres$(X) $(DESTDIR)$(bindir)/postgres$(X)
> +@@ -222,7 +223,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 -aruN postgresql-8.1.2/src/backend/access/transam/xact.c
> pgcluster-1.5.0rc7/src/backend/access/transam/xact.c
> +--- postgresql-8.1.2/src/backend/access/transam/xact.c 2005-11-22
> 19:23:05.000000000 +0100
> ++++ pgcluster-1.5.0rc7/src/backend/access/transam/xact.c 2006-01-10
> 17:39:38.000000000 +0100
> +@@ -46,6 +46,9 @@
> + #include "utils/resowner.h"
> + #include "pgstat.h"
> +
> ++#ifdef USE_REPLICATION
> ++#include "replicate.h"
> ++#endif /* USE_REPLICATION */
> +
> + /*
> + * User-tweakable parameters
> +@@ -4280,3 +4283,11 @@
> + else
> + strcat(buf, "UNKNOWN");
> + }
> ++
> ++#ifdef USE_REPLICATION
> ++void
> ++PGR_Reload_Start_Time(void)
> ++{
> ++ xactStartTimestamp = GetCurrentTimestamp();
> ++}
> ++#endif /* USE_REPLICATION */
> +diff -aruN postgresql-8.1.2/src/backend/catalog/catalog.c
> pgcluster-1.5.0rc7/src/backend/catalog/catalog.c
> +--- postgresql-8.1.2/src/backend/catalog/catalog.c 2005-10-15
> 04:49:12.000000000 +0200
> ++++ pgcluster-1.5.0rc7/src/backend/catalog/catalog.c 2006-01-10
> 17:39:39.000000000 +0100
> +@@ -29,6 +29,9 @@
> + #include "utils/fmgroids.h"
> + #include "utils/relcache.h"
> +
> ++#ifdef USE_REPLICATION
> ++#include "replicate.h"
> ++#endif /* USE_REPLICATION */
> +
> + #define OIDCHARS 10 /* max chars printed by %u */
> +
> +@@ -293,7 +296,7 @@
> + Oid
> + GetNewOidWithIndex(Relation relation, Relation indexrel)
> + {
> +- Oid newOid;
> ++ Oid newOid = 0;
> + IndexScanDesc scan;
> + ScanKeyData key;
> + bool collides;
> +@@ -301,8 +304,18 @@
> + /* Generate new OIDs until we find one not in the table */
> + do
> + {
> ++#ifdef USE_REPLICATION
> ++ if (PGR_Is_Sync_OID == true)
> ++ {
> ++ newOid = PGRGetNewObjectId(newOid);
> ++ }
> ++ else
> ++ {
> ++ newOid = GetNewObjectId();
> ++ }
> ++#else
> + newOid = GetNewObjectId();
> +-
> ++#endif /* USE_REPLICATION */
> + ScanKeyInit(&key,
> + (AttrNumber) 1,
> + BTEqualStrategyNumber, F_OIDEQ,
> +@@ -386,3 +399,4 @@
> +
> + return rnode.relNode;
> + }
> ++
> +diff -aruN postgresql-8.1.2/src/backend/commands/analyze.c
> pgcluster-1.5.0rc7/src/backend/commands/analyze.c
> +--- postgresql-8.1.2/src/backend/commands/analyze.c 2005-11-22
> 19:23:06.000000000 +0100
> ++++ pgcluster-1.5.0rc7/src/backend/commands/analyze.c 2006-01-10
> 17:39:34.000000000 +0100
> +@@ -39,6 +39,9 @@
> + #include "utils/syscache.h"
> + #include "utils/tuplesort.h"
> +
> ++#ifdef USE_REPLICATION
> ++#include "replicate.h"
> ++#endif /* USE_REPLICATION */
> +
> + /* Data structure for Algorithm S from Knuth 3.4.2 */
> + typedef struct
> +@@ -936,7 +939,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 -aruN postgresql-8.1.2/src/backend/commands/copy.c
> pgcluster-1.5.0rc7/src/backend/commands/copy.c
> +--- postgresql-8.1.2/src/backend/commands/copy.c 2005-12-28
> 06:38:26.000000000 +0100
> ++++ pgcluster-1.5.0rc7/src/backend/commands/copy.c 2006-01-10
> 17:39:34.000000000 +0100
> +@@ -48,6 +48,9 @@
> + #include "utils/relcache.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')
> +@@ -421,6 +424,9 @@
> + CopyGetData(CopyState cstate, void *databuf, int minread, int maxread)
> + {
> + int bytesread = 0;
> ++#ifdef USE_REPLICATION
> ++ char * ptr = (char *)databuf;
> ++#endif
> +
> + switch (cstate->copy_dest)
> + {
> +@@ -511,6 +517,9 @@
> + }
> + break;
> + }
> ++#ifdef USE_REPLICATION
> ++ PGR_Set_Copy_Data(PGRCopyData,ptr,bytesread,0);
> ++#endif /* USE_REPLICATION */
> +
> + return bytesread;
> + }
> +@@ -1921,6 +1930,13 @@
> + }
> + }
> +
> ++#ifdef USE_REPLICATION
> ++ if (done)
> ++ {
> ++ PGR_Set_Copy_Data(PGRCopyData,(char *)NULL,0,1);
> ++ }
> ++#endif /* USE_REPLICATION */
> ++
> + /* Done, clean up */
> + error_context_stack = errcontext.previous;
> +
> +@@ -2025,6 +2041,11 @@
> + break;
> + }
> + }
> ++#ifdef USE_REPLICATION
> ++ /*
> ++
> PGR_Set_Copy_Data(PGRCopyData,cstate->line_buf.data,cstate->line_buf.len,0);
> ++ */
> ++#endif
> +
> + /* Done reading the line. Convert it to server encoding. */
> + if (cstate->need_transcoding)
> +diff -aruN postgresql-8.1.2/src/backend/commands/sequence.c
> pgcluster-1.5.0rc7/src/backend/commands/sequence.c
> +--- postgresql-8.1.2/src/backend/commands/sequence.c 2005-11-22
> 19:23:07.000000000 +0100
> ++++ pgcluster-1.5.0rc7/src/backend/commands/sequence.c 2006-01-10
> 17:39:34.000000000 +0100
> +@@ -26,6 +26,9 @@
> + #include "utils/resowner.h"
> + #include "utils/syscache.h"
> +
> ++#ifdef USE_REPLICATION
> ++#include "replicate.h"
> ++#endif /* USE_REPLICATION */
> +
> + /*
> + * We don't want to log each fetching of a value from a sequence,
> +@@ -385,6 +388,9 @@
> + RangeVar *sequence;
> + Oid relid;
> +
> ++#ifdef USE_REPLICATION
> ++ Xlog_Check_Replicate(CMD_UTILITY);
> ++#endif /* USE_REPLICATION */
> + sequence = makeRangeVarFromNameList(textToQualifiedNameList(seqin));
> + relid = RangeVarGetRelid(sequence, false);
> +
> +@@ -610,6 +616,10 @@
> + SeqTable elm;
> + Relation seqrel;
> +
> ++#ifdef USE_REPLICATION
> ++ Xlog_Check_Replicate(CMD_UTILITY);
> ++#endif /* USE_REPLICATION */
> ++
> + /* open and AccessShareLock sequence */
> + init_sequence(relid, &elm, &seqrel);
> +
> +diff -aruN postgresql-8.1.2/src/backend/executor/functions.c
> pgcluster-1.5.0rc7/src/backend/executor/functions.c
> +--- postgresql-8.1.2/src/backend/executor/functions.c 2005-11-22
> 19:23:08.000000000 +0100
> ++++ pgcluster-1.5.0rc7/src/backend/executor/functions.c 2006-01-10
> 17:39:38.000000000 +0100
> +@@ -32,6 +32,9 @@
> + #include "utils/syscache.h"
> + #include "utils/typcache.h"
> +
> ++#ifdef USE_REPLICATION
> ++#include "replicate.h"
> ++#endif /* USE_REPLICATION */
> +
> + /*
> + * We have an execution_state record for each query in a function. Each
> +@@ -462,6 +465,13 @@
> + Datum value;
> + MemoryContext oldcontext;
> +
> ++#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 -aruN postgresql-8.1.2/src/backend/libpq/Makefile
> pgcluster-1.5.0rc7/src/backend/libpq/Makefile
> +--- postgresql-8.1.2/src/backend/libpq/Makefile 2003-11-29
> 20:51:49.000000000 +0100
> ++++ pgcluster-1.5.0rc7/src/backend/libpq/Makefile 2006-01-10
> 17:39:39.000000000 +0100
> +@@ -15,7 +15,8 @@
> + # 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 \
> ++ replicate.o replicate_com.o recovery.o
> +
> +
> + all: SUBSYS.o
> +diff -aruN postgresql-8.1.2/src/backend/libpq/be-fsstubs.c
> pgcluster-1.5.0rc7/src/backend/libpq/be-fsstubs.c
> +--- postgresql-8.1.2/src/backend/libpq/be-fsstubs.c 2005-11-22
> 19:23:09.000000000 +0100
> ++++ pgcluster-1.5.0rc7/src/backend/libpq/be-fsstubs.c 2006-01-10
> 17:39:39.000000000 +0100
> +@@ -48,6 +48,9 @@
> + #include "storage/large_object.h"
> + #include "utils/memutils.h"
> +
> ++#ifdef USE_REPLICATION
> ++#include "replicate.h"
> ++#endif /* USE_REPLICATION */
> +
> + /*#define FSDB 1*/
> + #define BUFSIZE 8192
> +@@ -93,6 +96,19 @@
> + int fd;
> + MemoryContext currentContext;
> +
> ++#ifdef USE_REPLICATION
> ++ if ((PGR_Stand_Alone != NULL) &&
> ++ (PGR_lo_open(lobjId,mode) != STATUS_OK))
> ++ {
> ++ if ((mode & INV_WRITE) &&
> ++ (PGR_Is_Stand_Alone() == true) &&
> ++ (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
> +@@ -132,6 +148,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
> +@@ -201,6 +220,18 @@
> + errmsg("large object descriptor %d was not opened
> for writing",
> + fd)));
> +
> ++#ifdef USE_REPLICATION
> ++ if ((PGR_Stand_Alone != NULL) &&
> ++ (PGR_lo_write(fd, buf, len) != STATUS_OK))
> ++ {
> ++ if ((PGR_Is_Stand_Alone() == true) &&
> ++ (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);
> +
> +@@ -229,6 +260,10 @@
> + PG_RETURN_INT32(-1);
> + }
> +
> ++#ifdef USE_REPLICATION
> ++ PGR_lo_lseek(fd, offset, whence);
> ++#endif /* USE_REPLICATION */
> ++
> + Assert(fscxt != NULL);
> + currentContext = MemoryContextSwitchTo(fscxt);
> +
> +@@ -250,6 +285,18 @@
> +
> + currentContext = MemoryContextSwitchTo(fscxt);
> +
> ++#ifdef USE_REPLICATION
> ++ if ((PGR_Stand_Alone != NULL) &&
> ++ (PGR_lo_create(InvalidOid) != STATUS_OK))
> ++ {
> ++ if ((PGR_Is_Stand_Alone() == true) &&
> ++ (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 */
> + lobjId = inv_create(InvalidOid);
> +
> + MemoryContextSwitchTo(currentContext);
> +@@ -263,6 +310,18 @@
> + Oid lobjId = PG_GETARG_OID(0);
> + MemoryContext currentContext;
> +
> ++#ifdef USE_REPLICATION
> ++ if ((PGR_Stand_Alone != NULL) &&
> ++ (PGR_lo_create(lobjId) != STATUS_OK))
> ++ {
> ++ if ((PGR_Is_Stand_Alone() == true) &&
> ++ (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 */
> + /* do we actually need fscxt for this? */
> + CreateFSContext();
> +
> +@@ -300,6 +359,18 @@
> + {
> + Oid lobjId = PG_GETARG_OID(0);
> +
> ++#ifdef USE_REPLICATION
> ++ if ((PGR_Stand_Alone != NULL) &&
> ++ (PGR_lo_unlink(lobjId) != STATUS_OK))
> ++ {
> ++ if ((PGR_Is_Stand_Alone() == true) &&
> ++ (PGR_Stand_Alone->permit == PERMIT_READ_ONLY) )
> ++ {
> ++ elog(WARNING, "This query is not permitted when all
> replication servers fell down ");
> ++ return -1;
> ++ }
> ++ }
> ++#endif /* USE_REPLICATION */
> + /*
> + * If there are any open LO FDs referencing that ID, close 'em.
> + */
> +@@ -391,6 +462,7 @@
> + errhint("Anyone can use the client-side
> lo_import() provided by libpq.")));
> + #endif
> +
> ++
> + /*
> + * We don't actually need to switch into fscxt, but create it anyway
> to
> + * ensure that AtEOXact_LargeObject knows there is state to clean up
> +@@ -405,6 +477,20 @@
> + nbytes = MAXPGPATH - 1;
> + memcpy(fnamebuf, VARDATA(filename), nbytes);
> + fnamebuf[nbytes] = '\0';
> ++
> ++#ifdef USE_REPLICATION
> ++ if ((PGR_Stand_Alone != NULL) &&
> ++ (PGR_lo_import((char*)fnamebuf) != STATUS_OK))
> ++ {
> ++ if ((PGR_Is_Stand_Alone() == true) &&
> ++ (PGR_Stand_Alone->permit == PERMIT_READ_ONLY) )
> ++ {
> ++ elog(WARNING, "This query is not permitted when all
> replication servers fell down ");
> ++ return -1;
> ++ }
> ++ }
> ++#endif
> ++
> + fd = PathNameOpenFile(fnamebuf, O_RDONLY | PG_BINARY, 0666);
> + if (fd < 0)
> + ereport(ERROR,
> +diff -aruN postgresql-8.1.2/src/backend/libpq/cluster.conf.sample
> pgcluster-1.5.0rc7/src/backend/libpq/cluster.conf.sample
> +--- postgresql-8.1.2/src/backend/libpq/cluster.conf.sample 1970-01-01
> 01:00:00.000000000 +0100
> ++++ pgcluster-1.5.0rc7/src/backend/libpq/cluster.conf.sample 2006-01-10
> 17:39:39.000000000 +0100
> +@@ -0,0 +1,57 @@
> ++#============================================================
> ++# 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>
> ++</Replicate_Server_Info>
> ++#<Replicate_Server_Info>
> ++# <Host_Name> replicate2.postgres.jp </Host_Name>
> ++# <Port> 8002 </Port>
> ++# <Recovery_Port> 8102 </Recovery_Port>
> ++#</Replicate_Server_Info>
> ++#<Replicate_Server_Info>
> ++# <Host_Name> replicate3.postgres.jp </Host_Name>
> ++# <Port> 8003 </Port>
> ++# <Recovery_Port> 8103 </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 Rsync_Compress : use compression option for rsync
> ++# [yes/no]. default : yes
> ++# 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>
> ++<Rsync_Compress> yes </Rsync_Compress>
> ++<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>
> +diff -aruN postgresql-8.1.2/src/backend/libpq/recovery.c
> pgcluster-1.5.0rc7/src/backend/libpq/recovery.c
> +--- postgresql-8.1.2/src/backend/libpq/recovery.c 1970-01-01
> 01:00:00.000000000 +0100
> ++++ pgcluster-1.5.0rc7/src/backend/libpq/recovery.c 2006-02-08
> 22:17:50.000000000 +0100
> +@@ -0,0 +1,1196 @@
> ++/*--------------------------------------------------------------------
> ++ * 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 <pwd.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 "postmaster/postmaster.h"
> ++
> ++#include "../interfaces/libpq/libpq-fe.h"
> ++#include "../interfaces/libpq/libpq-int.h"
> ++#include "../interfaces/libpq/fe-auth.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
> ++
> ++#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, int stage);
> ++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);
> ++static int sync_table_space(char * hostName, uint16_t portNum, char *
> userName, int stage);
> ++static PGresult * get_table_space_location(char * hostName, uint16_t
> portNum, char * userName);
> ++static int rsync_table_space(char * hostName, char * location, int stage);
> ++
> ++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;
> ++
> ++ 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 || errno == EAGAIN) {
> ++ continue;
> ++ } else {
> ++ elog(DEBUG1, "read_packet():recv failed");
> ++ return -1;
> ++ }
> ++ } else if (r == 0) {
> ++ elog(DEBUG1, "read_packet():unexpected EOF");
> ++ return -1;
> ++ } else /*if (r > 0)*/ {
> ++ read_size += r;
> ++ if (read_size == packet_size) {
> ++ show_recovery_packet(packet);
> ++ return read_size;
> ++ }
> ++ }
> ++ }
> ++ 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.
> ++ */
> ++ rtn = 1;
> ++ while (rtn)
> ++ {
> ++ for (;;)
> ++ {
> ++ timeout.tv_sec = PGR_SEND_TIMEOUT;
> ++ timeout.tv_usec = 0;
> ++
> ++ FD_ZERO(&wmask);
> ++ FD_SET(sock,&wmask);
> ++ rtn = select(sock+1, (fd_set *)NULL, &wmask, (fd_set
> *)NULL, &timeout);
> ++
> ++ if (rtn < 0)
> ++ {
> ++ if (errno == EINTR || errno == EAGAIN)
> ++ {
> ++ continue;
> ++ }
> ++ else
> ++ {
> ++ rtn = 0;
> ++ break;
> ++ }
> ++ }
> ++ else if (rtn && FD_ISSET(sock, &wmask))
> ++ {
> ++ send_ptr = (char *)packet;
> ++ buf_size = sizeof(RecoveryPacket);
> ++
> ++ s = send(sock,send_ptr + send_size,buf_size -
> send_size ,0);
> ++ if (s < 0) {
> ++ if (errno == EINTR || errno ==
> EAGAIN) {
> ++ continue;
> ++ }
> ++ elog(DEBUG1,
> "send_recovery_packet():send error");
> ++
> ++ /* EPIPE || ENCONNREFUSED || ENSOCK
> || EHOSTUNREACH */
> ++ return STATUS_ERROR;
> ++ } else if (s == 0) {
> ++ elog(DEBUG1,
> "send_recovery_packet():unexpected EOF");
> ++ return STATUS_ERROR;
> ++ } else /*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;
> ++
> ++ count = 0;
> ++ while ((status =
> PGR_Create_Acception(fd,&sock,"",RecoveryPortNumber)) != 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 if (r_size < 0)
> ++ {
> ++ loop_end=true;
> ++ break;
> ++ }
> ++ }
> ++ 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_TARGET_ONLY:
> ++ memset(&packet,0,sizeof(packet));
> ++ set_recovery_packet(&packet,
> RECOVERY_ERROR_ANS );
> ++ status = send_packet(&sock,&packet);
> ++ PGR_Set_Cluster_Status(STATUS_REPLICATE);
> ++ 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);
> ++ /**
> ++ * kill broken cluster db.
> ++ * FIXME: missing MyProcPid here. It must be
> postmaster's pid.
> ++ * but here's a bug MyProcPid doesn't
> initialized properly , so MyProcPid = postmaster's pid.
>
> ++ * To fix this, define variable to set
> posmaster's pid.
> ++ */
> ++ kill(MyProcPid,SIGQUIT);
> ++ loop_end = true;
> ++ break;
> ++ case RECOVERY_ERROR_ANS:
> ++ /* TODO: recovery failed. close this postmaster */
> ++ loop_end = true;
> ++ break;
> ++ case RECOVERY_FINISH:
> ++ PGR_Set_Cluster_Status(STATUS_REPLICATE);
> ++ loop_end = true;
> ++ break;
> ++ default:
> ++ 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 ((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(SIGINT, authdie);
> ++ pqsignal(SIGQUIT, authdie);
> ++ pqsignal(SIGALRM, authdie);
> ++ PG_SETMASK(&UnBlockSig);
> ++
> ++ status = STATUS_ERROR;
> ++ status = PGR_Create_Socket_Bind(&fd, "", RecoveryPortNumber);
> ++
> ++ 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, i = 0;
> ++
> ++ args[i++] = "rsync";
> ++ args[i++] = "-a";
> ++ args[i++] = "-r";
> ++ if (RsyncCompress)
> ++ args[i++] = "-z";
> ++ args[i++] = "--delete";
> ++ args[i++] = "-e";
> ++ args[i++] = RsyncOption;
> ++ args[i++] = src;
> ++ args[i++] = dest;
> ++ args[i++] = NULL;
> ++
> ++ pid = fork();
> ++ if (pid == 0)
> ++ {
> ++ status = execv(RsyncPath,args);
> ++ }
> ++ else
> ++ {
> ++ for (;;)
> ++ {
> ++ int result;
> ++ result = wait(&status);
> ++ if (result < 0)
> ++ {
> ++ if (errno == EINTR)
> ++ continue;
> ++ return STATUS_ERROR;
> ++ }
> ++
> ++ if (WIFEXITED(status) == 0 || WEXITSTATUS(status) !=
> 0)
> ++ return STATUS_ERROR;
> ++ else
> ++ break;
> ++ }
> ++ }
> ++ 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 status;
> ++ 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);
> ++ status = rename(org_dir,bkp_dir);
> ++ if (status < 0)
> ++ {
> ++ return STATUS_ERROR;
> ++ }
> ++ return STATUS_OK;
> ++}
> ++
> ++static int
> ++restore_dir(char * dir_name)
> ++{
> ++ int status;
> ++ 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);
> ++ status = rename(bkp_dir,org_dir);
> ++ if (status < 0)
> ++ {
> ++ remove_dir(org_dir);
> ++ status = rename(bkp_dir,org_dir);
> ++ if (status < 0)
> ++ {
> ++ return STATUS_ERROR;
> ++ }
> ++ }
> ++ return STATUS_OK;
> ++}
> ++
> ++static int
> ++rsync_global_dir(char * src, char * dest, int stage)
> ++{
> ++ int status;
> ++ char control_file[256];
> ++ char org_dir[256];
> ++ char src_dir[256];
> ++ struct stat fstat;
> ++ int cnt;
> ++
> ++ sprintf(org_dir,"%s/global",dest);
> ++ sprintf(control_file,"%s/global/pg_control",dest);
> ++ if (stage == PGR_1ST_RECOVERY)
> ++ {
> ++ 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);
> ++ }
> ++ if (stage == PGR_2ND_RECOVERY)
> ++ {
> ++ 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, stage) != 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");
> ++
> ++ /* 1st recovery step of "pg_xlog" directory */
> ++ fprintf(stderr,"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];
> ++ bool need_sync_table_space = false;
> ++
> ++ 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
> (!memcmp(Local_Host_Name,packet.hostName,strlen(packet.hostName)))
> ++ {
> ++ strcpy(src,packet.pg_data);
> ++ need_sync_table_space = false;
> ++ }
> ++ else
> ++ {
> ++
> sprintf(src,"%s:%s",packet.hostName,packet.pg_data);
> ++ need_sync_table_space = true;
> ++ }
> ++ 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;
> ++ }
> ++ if (need_sync_table_space == true)
> ++ {
> ++ fprintf(stderr,"1st sync_table_space ");
> ++ status = sync_table_space(packet.hostName,
> ntohs(packet.port), packet.userName, PGR_1ST_RECOVERY);
> ++ if (status != STATUS_OK)
> ++ {
> ++ if (Debug_pretty_print)
> ++ {
> ++ elog(DEBUG1,"1st sync table
> space error");
> ++ }
> ++ rtn = RECOVERY_LOOP_FAIL;
> ++ fprintf(stderr,"NG\n");
> ++ break;
> ++ }
> ++ fprintf(stderr,"OK\n");
> ++ }
> ++ /*
> ++ * 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
> (!memcmp(Local_Host_Name,packet.hostName,strlen(packet.hostName)))
> ++ {
> ++ strcpy(src,packet.pg_data);
> ++ need_sync_table_space = false;
> ++ }
> ++ else
> ++ {
> ++
> sprintf(src,"%s:%s",packet.hostName,packet.pg_data);
> ++ need_sync_table_space = true;
> ++ }
> ++ 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;
> ++ }
> ++ if (need_sync_table_space == true)
> ++ {
> ++ fprintf(stderr,"2nd sync_table_space ");
> ++ status = sync_table_space(packet.hostName,
> ntohs(packet.port), packet.userName, PGR_2ND_RECOVERY);
> ++ if (status != STATUS_OK)
> ++ {
> ++ if (Debug_pretty_print)
> ++ {
> ++ elog(DEBUG1,"2nd sync table
> space error");
> ++ }
> ++ rtn = RECOVERY_LOOP_FAIL;
> ++ fprintf(stderr,"NG\n");
> ++ break;
> ++ }
> ++ fprintf(stderr,"OK\n");
> ++ }
> ++ rtn = RECOVERY_LOOP_END;
> ++ break;
> ++ case RECOVERY_ERROR_OCCUPIED:
> ++ case RECOVERY_ERROR_CONNECTION:
> ++ default:
> ++ 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;
> ++
> ++Retry_Start_Recovery:
> ++ 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");
> ++ }
> ++ goto Retry_Start_Recovery;
> ++ }
> ++
> ++ 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;
> ++ }
> ++ else if (status == RECOVERY_LOOP_END)
> ++ {
> ++ close(fd);
> ++ break;
> ++ }
> ++ else 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;
> ++ }
> ++ else
> ++ {
> ++ 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)
> ++{
> ++ struct passwd * pw = NULL;
> ++
> ++ if (packet == NULL)
> ++ {
> ++ return;
> ++ }
> ++ PGRset_recovery_packet_no(packet, packet_no );
> ++ packet->max_connect = htons(MaxBackends);
> ++ packet->port = htons(PostPortNumber);
> ++ packet->recoveryPort = htons(RecoveryPortNumber);
> ++ gethostname(packet->hostName,sizeof(packet->hostName));
> ++ memcpy(packet->pg_data,DataDir,sizeof(packet->pg_data));
> ++ memset(packet->userName,0,sizeof(packet->userName));
> ++ if ((pw = getpwuid(geteuid())) != NULL)
> ++ {
> ++
> strncpy(packet->userName,pw->pw_name,sizeof(packet->userName));
> ++ }
> ++ else
> ++ {
> ++ cuserid(packet->userName);
> ++ }
> ++}
> ++
> ++static int
> ++sync_table_space(char * hostName, uint16_t portNum, char * userName, int
> stage)
> ++{
> ++ PGresult * res = (PGresult *)NULL;
> ++ int i = 0;
> ++ int row_num = 0;
> ++ char * location = NULL;
> ++ int rtn = STATUS_OK;
> ++
> ++ res = get_table_space_location(hostName, portNum, userName);
> ++ if (res == (PGresult *)NULL)
> ++ {
> ++ return STATUS_ERROR;
> ++ }
> ++ row_num = PQntuples(res);
> ++ for ( i = 0 ; i < row_num ; i ++)
> ++ {
> ++ location = PQgetvalue(res,i,0);
> ++ if (strlen(location) > 0 )
> ++ {
> ++ rtn = rsync_table_space(hostName, location, stage);
> ++ fprintf(stderr,".");
> ++ }
> ++ }
> ++ if (res != (PGresult *)NULL)
> ++ {
> ++ PQclear(res);
> ++ }
> ++
> ++ return STATUS_OK;
> ++}
> ++
> ++static PGresult *
> ++get_table_space_location(char * hostName, uint16_t portNum, char *
> userName)
> ++{
> ++ PGresult * res = (PGresult *)NULL;
> ++ int cnt = 0;
> ++ PGconn * conn = (PGconn *)NULL;
> ++ char port[8];
> ++ char *database = "template1";
> ++ char * query = "select spclocation from pg_tablespace";
> ++
> ++ if ( (hostName == NULL) ||
> ++ (portNum <= 0) ||
> ++ (userName == NULL))
> ++ {
> ++ return (PGresult *)NULL;
> ++ }
> ++ snprintf(port,sizeof(port),"%d", portNum);
> ++
> ++ /* create connection to master */
> ++ conn = PQsetdbLogin(hostName, port, NULL, NULL, database, userName,
> NULL);
> ++ if (conn == NULL)
> ++ {
> ++ return (PGresult *)NULL;
> ++ }
> ++ /* check to see that the backend Connection was successfully made */
> ++ cnt = 0;
> ++ while (PQstatus(conn) == CONNECTION_BAD)
> ++ {
> ++ if (conn != NULL)
> ++ {
> ++ PQfinish(conn);
> ++ }
> ++ if (cnt > MAX_RETRY_TIMES )
> ++ {
> ++ return (PGresult *)NULL;
> ++ }
> ++ conn = PQsetdbLogin(hostName, port, NULL, NULL, database,
> userName, NULL);
> ++ cnt ++;
> ++ }
> ++ res = PQexec(conn , query);
> ++ if ((res == NULL) ||
> ++ (PQresultStatus(res) != PGRES_TUPLES_OK))
> ++ {
> ++ PQclear(res);
> ++ res = (PGresult *)NULL;
> ++ }
> ++ if (conn != NULL)
> ++ {
> ++ PQfinish(conn);
> ++ }
> ++
> ++ return res;
> ++}
> ++
> ++static int
> ++rsync_table_space(char * hostName, char * location, int stage)
> ++{
> ++ int status = STATUS_OK;
> ++ char src_dir[256];
> ++ char dest_dir[256];
> ++ struct stat fstat;
> ++ int cnt = 0;
> ++ char * term = NULL;
> ++
> ++ sprintf(src_dir,"%s:%s",hostName,location);
> ++ strncpy(dest_dir,location,sizeof(dest_dir));
> ++ term = strrchr(dest_dir,'/');
> ++ if (term != NULL)
> ++ {
> ++ *term = '\0';
> ++ }
> ++
> ++ if (stage == PGR_1ST_RECOVERY)
> ++ {
> ++ status = bkup_dir(location);
> ++ }
> ++ status = rsync_pg_data(src_dir, dest_dir);
> ++ if (status != STATUS_OK )
> ++ {
> ++ restore_dir(location);
> ++ return STATUS_ERROR;
> ++ }
> ++ /* check pg_control file */
> ++ cnt = 0;
> ++ while (stat(location,&fstat) < 0)
> ++ {
> ++ if (cnt > MAX_RETRY_TIMES )
> ++ {
> ++ restore_dir(location);
> ++ return STATUS_ERROR;
> ++ }
> ++ cnt ++;
> ++ sleep(1);
> ++ }
> ++ if (stage == PGR_2ND_RECOVERY)
> ++ {
> ++ clear_bkup_dir(location);
> ++ }
> ++ return STATUS_OK;
> ++}
> ++#endif /* USE_REPLICATION */
> +diff -aruN postgresql-8.1.2/src/backend/libpq/replicate.c
> pgcluster-1.5.0rc7/src/backend/libpq/replicate.c
> +--- postgresql-8.1.2/src/backend/libpq/replicate.c 1970-01-01
> 01:00:00.000000000 +0100
> ++++ pgcluster-1.5.0rc7/src/backend/libpq/replicate.c 2006-02-09
> 11:51:50.000000000 +0100
> +@@ -0,0 +1,3552 @@
> ++/*--------------------------------------------------------------------
> ++ * 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'.
> ++ *
> ++ * Portions Copyright (c) 2003-2006, Atsushi Mitani
> ++ *--------------------------------------------------------------------
> ++ */
> ++
> ++/*--------------------------------------
> ++ * 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 <strings.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/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 "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 "storage/proc.h"
> ++#include "postmaster/postmaster.h"
> ++
> ++#include "replicate.h"
> ++
> ++/* the source of this value is 'access/transam/varsup.c' */
> ++#define VAR_OID_PREFETCH (8192)
> ++
> ++PGR_ReplicationLog_Info ReplicationLog_Info;
> ++
> ++/*--------------------------------------
> ++ * PROTOTYPE DECLARATION
> ++ *--------------------------------------
> ++ */
> ++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 int send_replicate_packet(int sock,ReplicateHeader * header, char
> * query_string);
> ++static int get_replicate_server_socket ( ReplicateServerInfo * sp , int
> socket_type );
> ++static bool is_copy_from(char * query);
> ++//static int is_session_authorization(char * query);
> ++static int get_words( char words[MAX_WORDS][MAX_WORD_LETTERS] ,char *
> string,int length,int upper);
> ++static int get_table_name(char * table_name, char * query, int position );
> ++static bool is_not_replication_query(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,char * query);
> ++static bool is_select_into_query(char cmdType,char * query);
> ++static int send_response_to_replication_server(const char * notice);
> ++static bool do_not_replication_command(const char * commandTag);
> ++static bool is_create_temp_table(char * query);
> ++static int add_replication_server(char * hostname,char * port, char *
> recovery_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 char * get_hostName(char * str);
> ++static void set_response_mode(char * mode);
> ++static void PGR_Set_Current_Replication_Query_ID(char *id);
> ++#ifdef CONTROL_LOCK_CONFLICT
> ++static int wait_lock_answer(void);
> ++static int read_trigger(char * result, int buf_size);
> ++#endif /* CONTROL_LOCK_CONFLICT */
> ++
> ++
> ++static unsigned int get_next_request_id(void);
> ++static bool is_this_query_replicated(char * id);
> ++static int set_replication_id(char * id);
> ++static int return_current_oid(void);
> ++static int sync_oid(char * oid);
> ++
> ++extern ssize_t secure_read(Port *, void *, size_t);
> ++
> ++bool autocommit = true;
> ++/*--------------------------------------------------------------------
> ++ * SYMBOL
> ++ * PGR_Init_Replicate_Server_Data()
> ++ * NOTES
> ++ * Read Configuration file and create ReplicateServerData table
> ++ * ARGS
> ++ * void
> ++ * RETURN
> ++ * OK: STATUS_OK
> ++ * NG: STATUS_ERROR
> ++ *--------------------------------------------------------------------
> ++ */
> ++int
> ++PGR_Init_Replicate_Server_Data(void)
> ++{
> ++ int table_size,str_size;
> ++ ReplicateServerInfo *sp;
> ++ PGR_Not_Replicate_Type * nrp;
> ++ ConfDataType * conf;
> ++ int rec_no,cnt;
> ++ unsigned int ip;
> ++ char HostName[128];
> ++
> ++
> ++ if (ConfData_Top == (ConfDataType *)NULL)
> ++ {
> ++ return STATUS_ERROR;
> ++ }
> ++
> ++ /* allocate replication server information table */
> ++ table_size = sizeof(ReplicateServerInfo) * MAX_SERVER_NUM;
> ++ ReplicateServerShmid = shmget(IPC_PRIVATE,table_size,IPC_CREAT |
> IPC_EXCL | 0600);
> ++ if (ReplicateServerShmid < 0)
> ++ {
> ++ return STATUS_ERROR;
> ++ }
> ++ ReplicateServerData = (ReplicateServerInfo
> *)shmat(ReplicateServerShmid,0,0);
> ++ if (ReplicateServerData == (ReplicateServerInfo *)-1)
> ++ {
> ++ return STATUS_ERROR;
> ++ }
> ++ memset(ReplicateServerData,0,table_size);
> ++ sp = ReplicateServerData;
> ++
> ++ /* allocate cluster db information table */
> ++ ClusterDBShmid = shmget(IPC_PRIVATE,sizeof(ClusterDBInfo),IPC_CREAT |
> IPC_EXCL | 0600);
> ++ if (ClusterDBShmid < 0)
> ++ {
> ++ return STATUS_ERROR;
> ++ }
> ++ ClusterDBData = (ClusterDBInfo *)shmat(ClusterDBShmid,0,0);
> ++ if (ClusterDBData == (ClusterDBInfo *)-1)
> ++ {
> ++ return STATUS_ERROR;
> ++ }
> ++ memset(ClusterDBData,0,sizeof(ClusterDBInfo));
> ++ PGR_Set_Cluster_Status(STATUS_REPLICATE);
> ++
> ++ /* allocate partial replicate table */
> ++ table_size = sizeof(PGR_Not_Replicate_Type) * MAX_SERVER_NUM;
> ++ PGR_Not_Replicate = malloc(table_size);
> ++ if (PGR_Not_Replicate == (PGR_Not_Replicate_Type*)NULL)
> ++ {
> ++ return STATUS_ERROR;
> ++ }
> ++ memset(PGR_Not_Replicate, 0, table_size);
> ++ nrp = PGR_Not_Replicate;
> ++ cnt = 0;
> ++ conf = 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))
> ++ {
> ++ (sp + rec_no)->portNumber = atoi(conf->value);
> ++ (sp + rec_no)->sock = -1;
> ++ if ((sp + rec_no)->useFlag != DATA_USE)
> ++ {
> ++
> PGR_Set_Replication_Server_Status((sp+rec_no), DATA_INIT);
> ++ }
> ++ 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,RECOVERY_PORT_TAG))
> ++ {
> ++ (sp + rec_no)->recoveryPortNumber =
> atoi(conf->value);
> ++ if ((sp + rec_no)->useFlag != DATA_USE)
> ++ {
> ++
> PGR_Set_Replication_Server_Status((sp+rec_no), DATA_INIT);
> ++ }
> ++ 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 (PGR_Not_Replicate_Rec_Num < rec_no +1)
> ++ {
> ++ 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;
> ++ }
> ++ }
> ++ if (!strcmp(conf->key,RECOVERY_PORT_TAG))
> ++ {
> ++ RecoveryPortNumber = atoi(conf->value);
> ++ }
> ++ if (!strcmp(conf->key,RSYNC_PATH_TAG))
> ++ {
> ++ str_size = strlen(conf->value) ;
> ++ RsyncPath = malloc(str_size + 1);
> ++ if (RsyncPath == NULL)
> ++ {
> ++ return STATUS_ERROR;
> ++ }
> ++ memset(RsyncPath,0,str_size + 1);
> ++ strncpy(RsyncPath,conf->value,str_size);
> ++ }
> ++ if (!strcmp(conf->key,RSYNC_OPTION_TAG))
> ++ {
> ++ str_size = strlen(conf->value) ;
> ++ RsyncOption = malloc(str_size + 1);
> ++ if (RsyncOption == NULL)
> ++ {
> ++ return STATUS_ERROR;
> ++ }
> ++ memset(RsyncOption,0,str_size + 1);
> ++ strncpy(RsyncOption,conf->value,str_size);
> ++ }
> ++ if (!strcmp(conf->key,RSYNC_COMPRESS_TAG))
> ++ {
> ++ if (!strcmp(conf->value, "yes"))
> ++ RsyncCompress = true;
> ++ else if (!strcmp(conf->value, "no"))
> ++ RsyncCompress = false;
> ++ }
> ++ if (!strcmp(conf->key,STAND_ALONE_TAG))
> ++ {
> ++ PGR_Stand_Alone =
> (PGR_Stand_Alone_Type*)malloc(sizeof(PGR_Stand_Alone_Type));
> ++ if (PGR_Stand_Alone == (PGR_Stand_Alone_Type *)NULL)
> ++ {
> ++ return STATUS_ERROR;
> ++ }
> ++ PGR_Stand_Alone->is_stand_alone = false;
> ++ if (!strcmp(conf->value,READ_WRITE_IF_STAND_ALONE))
> ++ {
> ++ PGR_Stand_Alone->permit = PERMIT_READ_WRITE;
> ++ }
> ++ else
> ++ {
> ++ PGR_Stand_Alone->permit = PERMIT_READ_ONLY;
> ++ }
> ++ }
> ++ conf = (ConfDataType *)conf->next;
> ++ }
> ++ TransactionSock = -1;
> ++ ReplicateCurrentTime = (ReplicateNow *)malloc(sizeof(ReplicateNow));
> ++ if (ReplicateCurrentTime == (ReplicateNow *)NULL)
> ++ {
> ++ return STATUS_ERROR;
> ++ }
> ++ memset(ReplicateCurrentTime,0,sizeof(ReplicateNow));
> ++
> ++ PGRCopyData = (CopyData *)malloc(sizeof(CopyData));
> ++ if (PGRCopyData == (CopyData *)NULL)
> ++ {
> ++ return STATUS_ERROR;
> ++ }
> ++ memset(PGRCopyData,0,sizeof(CopyData));
> ++
> ++ if (PGR_Not_Replicate_Rec_Num == 0)
> ++ {
> ++ free(PGR_Not_Replicate);
> ++ PGR_Not_Replicate = NULL;
> ++ }
> ++ else
> ++ {
> ++ qsort((char
> *)PGR_Not_Replicate,PGR_Not_Replicate_Rec_Num,sizeof(PGR_Not_Replicate_Type),
> (int (*)(const void*,const void*))Comp_Not_Replicate);
> ++ }
> ++
> ++ PGRSelfHostName = malloc(HOSTNAME_MAX_LENGTH);
> ++ if (PGRSelfHostName == NULL)
> ++ {
> ++ return STATUS_ERROR;
> ++ }
> ++ memset(PGRSelfHostName,0,HOSTNAME_MAX_LENGTH);
> ++ if (gethostname(HostName,HOSTNAME_MAX_LENGTH) < 0)
> ++ {
> ++ return STATUS_ERROR;
> ++ }
> ++ ip=PGRget_ip_by_name(HostName);
> ++
> ++ sprintf(PGRSelfHostName,
> ++ "%d.%d.%d.%d",
> ++ (ip ) & 0xff ,
> ++ (ip >> 8) & 0xff ,
> ++ (ip >> 16) & 0xff ,
> ++ (ip >> 24) & 0xff );
> ++
> ++ return STATUS_OK;
> ++}
> ++
> ++/*--------------------------------------------------------------------
> ++ * SYMBOL
> ++ * PGR_Set_Replicate_Server_Socket()
> ++ * NOTES
> ++ * Create new socket and set ReplicateServerData table
> ++ * ARGS
> ++ * void
> ++ * RETURN
> ++ * OK: STATUS_OK
> ++ * NG: STATUS_ERROR
> ++ *--------------------------------------------------------------------
> ++ */
> ++int
> ++PGR_Set_Replicate_Server_Socket(void)
> ++{
> ++ ReplicateServerInfo * sp;
> ++ if (ReplicateServerData == NULL)
> ++ {
> ++ return STATUS_ERROR;
> ++ }
> ++ sp = 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 (TransactionSock != -1)
> ++ {
> ++ return TransactionSock;
> ++ }
> ++
> ++
> while(PGR_Create_Socket_Connect(&TransactionSock,tmp->hostName,tmp->portNumber)
> != STATUS_OK)
> ++ {
> ++ close(TransactionSock);
> ++ TransactionSock = -1;
> ++ PGR_Set_Replication_Server_Status(tmp, DATA_ERR);
> ++ usleep(20);
> ++ tmp = PGR_get_replicate_server_info();
> ++ if (tmp == (ReplicateServerInfo *)NULL)
> ++ {
> ++ return -1;
> ++ }
> ++ PGR_Set_Replication_Server_Status(tmp, DATA_USE);
> ++ usleep(10);
> ++ }
> ++ return 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 (TransactionSock != -1)
> ++ {
> ++ PGR_Close_Sock(&(TransactionSock));
> ++ TransactionSock = -1;
> ++ }
> ++ switch (socket_type)
> ++ {
> ++ case PGR_TRANSACTION_SOCKET:
> ++ if (TransactionSock != -1)
> ++ {
> ++ PGR_Close_Sock(&(TransactionSock));
> ++ }
> ++ TransactionSock = -1;
> ++ sp->sock = -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;
> ++ int cnt = 0;
> ++
> ++ if ((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 = 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)
> ++ {
> ++ cnt ++;
> ++ 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;
> ++ }
> ++ if (cnt > MAX_RETRY_TIMES )
> ++ {
> ++ sp++;
> ++ cnt = 0;
> ++ }
> ++ else
> ++ {
> ++ continue;
> ++ }
> ++ }
> ++ return NULL;
> ++}
> ++
> ++static int
> ++get_table_name(char * table_name, 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 = 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(char * query_string, int query_len, char cmdType)
> ++{
> ++ PGR_Not_Replicate_Type key;
> ++ PGR_Not_Replicate_Type * ptr = NULL;
> ++
> ++ if (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)-1);
> ++ 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*)PGR_Not_Replicate,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(char * query_string, int query_len, char
> cmdSts ,char cmdType)
> ++{
> ++ int sock = -1;
> ++ 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 check_flag =0;
> ++
> ++
> ++ /*
> ++ * check query string
> ++ */
> ++ if ((query_string == NULL) ||
> ++ (query_len < 0))
> ++ {
> ++ return NULL;
> ++ }
> ++ /* check not replication query */
> ++ if (is_not_replication_query(query_string, query_len, cmdType) ==
> true)
> ++ {
> ++ 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;
> ++ }
> ++
> ++ serverName = sp->hostName;
> ++ portNumber = (int)sp->portNumber;
> ++ memset(&header,0,sizeof(ReplicateHeader));
> ++
> ++ 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)-1);
> ++ strncpy(header.userName , (char
> *)(MyProcPort->user_name),sizeof(header.userName)-1);
> ++ header.request_id = htonl(get_next_request_id());
> ++ header.rlog = 0;
> ++
> ++ if (PGRSelfHostName != NULL)
> ++ {
> ++ strncpy(header.from_host, PGRSelfHostName,
> HOSTNAME_MAX_LENGTH);
> ++ }
> ++
> ++ base = sp;
> ++ PGR_Sock_To_Replication_Server = sock;
> ++
> ++retry_send_prereplicate_packet:
> ++
> ++ memset(result,0,PGR_MESSAGE_BUFSIZE + 4);
> ++ cnt = 0;
> ++ header.cmdSys=CMD_SYS_PREREPLICATE;
> ++
> ++ while (send_replicate_packet(sock,&header,query_string) != STATUS_OK)
> ++ {
> ++ cnt++;
> ++ 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");
> ++ 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;
> ++
> ++ }
> ++ if(cmdSts==CMD_STS_TRANSACTION )
> ++ {
> ++ if (cmdType!=CMD_TYPE_BEGIN
> ++ && cmdType!=CMD_TYPE_ROLLBACK)
> ++ {
>
> ++ elog(ERROR,"replicate server down
> during replicating transaction. aborted.");
> ++ free(result);
> ++ return NULL;
> ++ }
> ++ }
> ++ PGR_Sock_To_Replication_Server = sock;
> ++ cnt = 0;
> ++ }
> ++ }
> ++
> ++ memset(result,0,PGR_MESSAGE_BUFSIZE);
> ++ if (recv_replicate_result(sock,result,0) < 0)
> ++ {
> ++
> ++ sock = get_new_replication_socket( base, sp,
> socket_type);
> ++ if (sock < 0)
> ++ {
> ++ if (Debug_pretty_print)
> ++ elog(DEBUG1,"all
> replication servers may be down");
> ++ 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;
> ++ }
> ++ PGR_Sock_To_Replication_Server = sock;
> ++ /* replication server should be down */
> ++
> ++ if(cmdSts==CMD_STS_TRANSACTION
> ++ && (cmdType!=CMD_TYPE_BEGIN &&
> cmdType!=CMD_TYPE_ROLLBACK))
> ++ {
> ++ elog(ERROR,"replicate server down
> during replicating transaction. aborted.");
> ++ free(result);
> ++ return NULL;
> ++ }
> ++
> ++ goto retry_send_prereplicate_packet;
> ++ }
> ++
> ++
> ++ argc = set_command_args(argv,result);
> ++ func_no=atoi(argv[0]);
> ++ if(func_no==0) {
> ++ /* this server is not primary replicate server*/
> ++ sock=-1;
> ++ goto retry_send_prereplicate_packet;
> ++ }
> ++retry_send_replicate_packet:
> ++
> ++ memset(result,0,PGR_MESSAGE_BUFSIZE + 4);
> ++ cnt = 0;
> ++ header.cmdSys = CMD_SYS_REPLICATE;
> ++ 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");
> ++ 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;
> ++
> ++ }
> ++ PGR_Sock_To_Replication_Server = sock;
> ++ header.rlog = CONNECTION_SUSPENDED_TYPE;
> ++ cnt = 0;
> ++ }
> ++ cnt ++;
> ++ }
> ++
> ++ memset(result,0,PGR_MESSAGE_BUFSIZE);
> ++ 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");
> ++ 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;
> ++ }
> ++ PGR_Sock_To_Replication_Server = sock;
> ++ header.rlog = CONNECTION_SUSPENDED_TYPE;
> ++
> ++ goto retry_send_replicate_packet;
> ++ }
> ++
> ++ argc = set_command_args(argv,result);
> ++ if (argc >= 1)
> ++ {
> ++ func_no = atoi(argv[0]);
> ++ if (func_no == PGR_SET_CURRENT_TIME_FUNC_NO)
> ++ {
> ++ PGR_Set_Current_Time(argv[1],argv[2]);
> ++ set_replication_id(argv[3]);
> ++ set_response_mode(argv[4]);
> ++ PGR_Set_Current_Replication_Query_ID(argv[5]);
> ++ }
> ++ 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_SET_CURRENT_REPLICATION_QUERY_ID_NO)
> ++ {
> ++ PGR_Set_Current_Replication_Query_ID(argv[1]);
> ++ }
> ++ 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;
> ++}
> ++
> ++uint32_t
> ++PGRget_replication_id(void)
> ++{
> ++ return (ReplicationLog_Info.PGR_Replicate_ID);
> ++}
> ++
> ++static int
> ++set_replication_id(char * id)
> ++{
> ++ uint32_t rid=0;
> ++ uint32_t saved_id;
> ++ if (id == NULL)
> ++ {
> ++ return STATUS_ERROR;
> ++ }
> ++
> ++ rid=(uint32_t)atol(id);
> ++ if(rid==0)
> ++ return STATUS_OK;
> ++
> ++ needToUpdateReplicateIdOnNextQueryIsDone=true;
> ++ saved_id=ReplicationLog_Info.PGR_Replicate_ID;
> ++
> ++ ReplicationLog_Info.PGR_Replicate_ID =rid;
> ++
> ++
> ++ /*set replicate id in this process */
> ++
> ++
> ++ if (CurrentReplicateServer == NULL)
> ++ {
> ++ PGR_get_replicate_server_info();
> ++ }
> ++ if (CurrentReplicateServer != NULL)
> ++ {
> ++ /* set replicate id in this system */
> ++ saved_id=CurrentReplicateServer->replicate_id;
> ++ elog(DEBUG1, "replication id set from %d to
> %d", saved_id, rid);
> ++
> ++ CurrentReplicateServer->replicate_id =
> (uint32_t)(atol(id));
> ++ }
> ++
> ++ return STATUS_OK;
> ++}
> ++
> ++
> ++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;
> ++ int32_t diff=0;
> ++ ReplicateServerInfo * replicate_server_info = NULL;
> ++
> ++ if (id == NULL)
> ++ {
> ++ return false;
> ++ }
> ++ replicate_id = (uint32_t)atol(id);
> ++ elog(DEBUG1, "check for replication id , input=%u", replicate_id);
> ++
> ++ if (CurrentReplicateServer == NULL)
> ++ {
> ++ PGR_get_replicate_server_info();
> ++ }
> ++
> ++ if (CurrentReplicateServer != NULL)
> ++ {
> ++ replicate_server_info = CurrentReplicateServer;
> ++ }
> ++ else if (LastReplicateServer != NULL)
> ++ {
> ++ replicate_server_info = LastReplicateServer;
> ++ }
> ++ if (replicate_server_info != NULL)
> ++ {
> ++
> ++ saved_id=replicate_server_info->replicate_id;
> ++ saved_id = saved_id < ReplicationLog_Info.PGR_Replicate_ID
> ++ ? ReplicationLog_Info.PGR_Replicate_ID
> ++ : saved_id;
> ++
> ++ elog(DEBUG1, "check for replication id , now=%u", saved_id);
> ++ /* check replicate_id < saved_id logically
> ++ *
> ++ * see also:
> ++ * backend/transam/transam.c#TransactionIdPrecedes
> ++ */
> ++ diff = (int32) ( replicate_id - saved_id );
> ++ return (diff < 0);
> ++ }
> ++ elog(DEBUG1, "check for replication id check failed. no replication
> server");
> ++ return false;
> ++}
> ++
> ++
> ++static int
> ++get_new_replication_socket( ReplicateServerInfo * base,
> ReplicateServerInfo * sp, int socket_type)
> ++{
> ++ int sock = -1;
> ++
> ++ 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");
> ++ 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;
> ++ }
> ++
> ++ /*
> ++ * Wait for something to happen.
> ++ */
> ++ for (;;)
> ++ {
> ++ if (user_timeout == 0)
> ++ timeout.tv_sec = PGR_RECV_TIMEOUT * 3;
> ++ else
> ++ timeout.tv_sec = user_timeout;
> ++
> ++ timeout.tv_usec = 0;
> ++
> ++ FD_ZERO(&rmask);
> ++ FD_SET(sock,&rmask);
> ++ rtn = select(sock+1, &rmask, (fd_set *)NULL, (fd_set *)NULL,
> &timeout);
> ++ if (rtn < 0)
> ++ {
> ++ if (errno != EINTR)
> ++ return -1;
> ++ }
> ++
> ++ else if ((rtn > 0) && (FD_ISSET(sock, &rmask)))
> ++ {
> ++ return (recv_message(sock, result,0));
> ++ }
> ++ }
> ++ 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 || errno == EAGAIN) {
> ++ continue;
> ++ } else {
> ++ elog(DEBUG1, "recv_message():recv failed");
> ++ return -1;
> ++ }
> ++ } else if (r == 0) {
> ++ elog(DEBUG1, "recv_message():unexpected EOF");
> ++ return -1;
> ++ } else /*if (r > 0)*/ {
> ++ read_size += r;
> ++ if (read_size == PGR_MESSAGE_BUFSIZE)
> ++ {
> ++ return read_size;
> ++ }
> ++ }
> ++ }
> ++ return -1;
> ++}
> ++
> ++static int
> ++send_replicate_packet(int sock,ReplicateHeader * header, char *
> query_string)
> ++{
> ++ int s = 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 = malloc(buf_size);
> ++ if (buf == 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;
> ++
> ++ /*
> ++ * Wait for something to happen.
> ++ */
> ++ rtn = 1;
> ++ for (;;)
> ++ {
> ++ timeout.tv_sec = PGR_SEND_TIMEOUT;
> ++ timeout.tv_usec = 0;
> ++
> ++ FD_ZERO(&wmask);
> ++ FD_SET(sock,&wmask);
> ++ rtn = select(sock+1, (fd_set *)NULL, &wmask, (fd_set *)NULL,
> &timeout);
> ++ if (rtn < 0)
> ++ {
> ++ if (errno == EINTR)
> ++ continue;
> ++ else
> ++ {
> ++ elog(DEBUG1,
> "send_replicate_packet():select() failed");
> ++ return STATUS_ERROR;
> ++ }
> ++ }
> ++ else if (rtn && FD_ISSET(sock, &wmask))
> ++ {
> ++
> ++
> ++ s = send(sock,send_ptr + send_size,buf_size -
> send_size ,0);
> ++ if (s < 0){
> ++ if (errno == EINTR || errno == EAGAIN)
> ++ {
> ++ continue;
> ++ }
> ++ elog(DEBUG1, "send_replicate_packet():send
> error");
> ++
> ++ /* EPIPE || ENCONNREFUSED || ENSOCK ||
> EHOSTUNREACH */
> ++ return STATUS_ERROR;
> ++ } else if (s == 0) {
> ++ free(buf);
> ++ buf = NULL;
> ++ elog(DEBUG1,
> "send_replicate_packet():unexpected EOF");
> ++ return STATUS_ERROR;
> ++ } else /*if (s > 0)*/ {
> ++ send_size += s;
> ++ if (send_size == buf_size)
> ++ {
> ++ free(buf);
> ++ buf = NULL;
> ++ return STATUS_OK;
> ++ }
> ++ }
> ++ }
> ++ }
> ++ if (buf != NULL)
> ++ {
> ++ free(buf);
> ++ buf = NULL;
> ++ }
> ++ return STATUS_ERROR;
> ++}
> ++
> ++bool
> ++PGR_Is_Replicated_Command(char * query)
> ++{
> ++
> ++ return (PGR_Is_System_Command(query));
> ++}
> ++
> ++int
> ++Xlog_Check_Replicate(int operation)
> ++{
> ++ if ((PGR_Get_Cluster_Status() == STATUS_RECOVERY) &&
> ++ (Transaction_Mode == 0 ) )
> ++ {
> ++ 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 (PGR_Stand_Alone == NULL)
> ++ {
> ++ return STATUS_OK;
> ++ }
> ++ if (Query_String != NULL)
> ++ {
> ++ if (PGR_Is_Stand_Alone() == true)
> ++ {
> ++ if (PGR_Stand_Alone->permit == PERMIT_READ_ONLY)
> ++ {
> ++ Query_String = NULL;
> ++ return STATUS_ERROR;
> ++ }
> ++ }
> ++ PGR_Need_Notice = true;
> ++ PGR_Check_Lock.check_lock_conflict = true;
> ++ result =
> PGR_Send_Replicate_Command(Query_String,strlen(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;
> ++ }
> ++ Query_String = NULL;
> ++ }
> ++ return status;
> ++}
> ++
> ++void
> ++PGR_delete_shm(void)
> ++{
> ++
> ++ if (ReplicateServerData != NULL)
> ++ {
> ++ shmdt(ReplicateServerData);
> ++ ReplicateServerData = NULL;
> ++ shmctl(ReplicateServerShmid,IPC_RMID,(struct shmid_ds *)NULL);
> ++ }
> ++ if (ClusterDBData != NULL)
> ++ {
> ++ shmdt(ClusterDBData);
> ++ ClusterDBData = NULL;
> ++ shmctl(ClusterDBShmid,IPC_RMID,(struct shmid_ds *)NULL);
> ++ }
> ++
> ++ if (TransactionSock != -1)
> ++ {
> ++ close(TransactionSock);
> ++ }
> ++
> ++ if (RsyncPath != NULL)
> ++ {
> ++ free(RsyncPath);
> ++ RsyncPath = NULL;
> ++ }
> ++ if (RsyncOption != NULL)
> ++ {
> ++ free(RsyncOption);
> ++ RsyncOption = NULL;
> ++ }
> ++
> ++ if (ReplicateCurrentTime != NULL)
> ++ {
> ++ free(ReplicateCurrentTime);
> ++ ReplicateCurrentTime = NULL;
> ++ }
> ++
> ++ if (PGRCopyData != NULL)
> ++ {
> ++ free (PGRCopyData);
> ++ PGRCopyData = NULL;
> ++ }
> ++
> ++ if (PGR_Stand_Alone != NULL)
> ++ {
> ++ free(PGR_Stand_Alone);
> ++ PGR_Stand_Alone = NULL;
> ++ }
> ++
> ++ if (PGR_Not_Replicate != NULL)
> ++ {
> ++ free(PGR_Not_Replicate);
> ++ PGR_Not_Replicate = NULL;
> ++ }
> ++ if (PGRSelfHostName != NULL)
> ++ {
> ++ free(PGRSelfHostName);
> ++ PGRSelfHostName = NULL;
> ++ }
> ++}
> ++
> ++ReplicateServerInfo *
> ++PGR_get_replicate_server_info(void)
> ++{
> ++
> ++ ReplicateServerInfo * sp;
> ++
> ++ if (ReplicateServerData == NULL)
> ++ {
> ++ return (ReplicateServerInfo *)NULL;
> ++ }
> ++ sp = ReplicateServerData;
> ++ while (sp->useFlag != DATA_END)
> ++ {
> ++ if (sp->useFlag == DATA_USE )
> ++ {
> ++ if (CurrentReplicateServer != NULL)
> ++ {
> ++ LastReplicateServer = CurrentReplicateServer;
> ++ CurrentReplicateServer->replicate_id =
> LastReplicateServer->replicate_id;
> ++ }
> ++ CurrentReplicateServer = sp;
> ++ return sp;
> ++ }
> ++ sp++;
> ++ }
> ++ sp = ReplicateServerData;
> ++ while (sp->useFlag != DATA_END)
> ++ {
> ++ if (sp->useFlag != DATA_ERR )
> ++ {
> ++ if (CurrentReplicateServer != NULL)
> ++ {
> ++ LastReplicateServer = CurrentReplicateServer;
> ++ CurrentReplicateServer->replicate_id =
> LastReplicateServer-> replicate_id;
> ++ }
> ++ CurrentReplicateServer = sp;
> ++ PGR_Set_Replication_Server_Status(sp, DATA_USE);
> ++ return sp;
> ++ }
> ++ sp++;
> ++ }
> ++ PGR_Stand_Alone->is_stand_alone = true;
> ++ if (CurrentReplicateServer != NULL)
> ++ {
> ++ LastReplicateServer = CurrentReplicateServer;
> ++ CurrentReplicateServer->replicate_id = LastReplicateServer->
> replicate_id;
> ++ }
> ++ 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];
> ++
> ++ if (copy == NULL)
> ++ {
> ++ return STATUS_ERROR;
> ++ }
> ++
> ++ cmdSts = CMD_STS_COPY;
> ++
> ++ if (Transaction_Mode)
> ++ {
> ++ cmdSts = CMD_STS_TRANSACTION ;
> ++ }
> ++ if (Session_Authorization_Mode)
> ++ {
> ++ cmdSts = CMD_STS_SET_SESSION_AUTHORIZATION ;
> ++ }
> ++ cmdType = CMD_TYPE_COPY_DATA;
> ++
> ++ copy->copy_data[copy->cnt] = '\0';
> ++ if (end)
> ++ {
> ++ memset(term,0,sizeof(term));
> ++ term[0]='\\';
> ++ term[1]='.';
> ++ term[2]='\n';
> ++ cmdType = CMD_TYPE_COPY_DATA_END;
> ++ p = NULL;
> ++ if (copy->cnt > 0)
> ++ {
> ++ copy->copy_data[copy->cnt] = '\0';
> ++ p = strstr(copy->copy_data,term);
> ++ if (p == NULL)
> ++ {
> ++ p = &(copy->copy_data[copy->cnt-1]);
> ++ copy->cnt--;
> ++ }
> ++ else
> ++ {
> ++ p = NULL;
> ++ }
> ++ }
> ++ if (p != NULL)
> ++ {
> ++ strncpy(p,term,sizeof(term));
> ++ copy->cnt += 4;
> ++ }
> ++ }
> ++
> ++ result = PGR_Send_Replicate_Command(copy->copy_data, copy->cnt,
> cmdSts, cmdType);
> ++
> ++ 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)
> ++{
> ++ CopyData save;
> ++ int save_len = 0;
> ++ int read_index = 0;
> ++ int send_size = 0;
> ++ int buf_size = 0;
> ++ int rest_len = 0;
> ++ int rest_buf_size = 0;
> ++ int status = STATUS_OK;
> ++ char * ep = NULL;
> ++ char term[4];
> ++
> ++ #define BUFF_OFFSET (8)
> ++
> ++ if ((PGR_Copy_Data_Need_Replicate == false) ||
> ++ (copy == NULL))
> ++ {
> ++ return (CopyData *)NULL;
> ++ }
> ++ memset(term,0,sizeof(term));
> ++ term[0]='\n';
> ++ term[1]='\\';
> ++ term[2]='.';
> ++ buf_size = COPYBUFSIZ - BUFF_OFFSET;
> ++ read_index = 0;
> ++ rest_len = len;
> ++ rest_buf_size = buf_size - copy->cnt;
> ++ while ((rest_len > 0) && (rest_buf_size > 0))
> ++ {
> ++ if (rest_buf_size < rest_len)
> ++ {
> ++ send_size = rest_buf_size;
> ++ rest_len -= send_size;
> ++ }
> ++ else
> ++ {
> ++ send_size = rest_len;
> ++ rest_len = 0;
> ++ }
> ++ memcpy(&(copy->copy_data[copy->cnt]) ,str + read_index
> ,send_size);
> ++ copy->cnt += send_size;
> ++ read_index += send_size;
> ++ rest_buf_size = buf_size - copy->cnt;
> ++ if (strstr(copy->copy_data,term) != NULL)
> ++ {
> ++ break;
> ++ }
> ++ if (rest_buf_size <= 0)
> ++ {
> ++ ep = strrchr(copy->copy_data,'\n');
> ++ if (ep != NULL)
> ++ {
> ++ *ep = '\0';
> ++ save_len = copy->cnt -
> strlen(copy->copy_data) -1;
> ++ copy->cnt -= save_len ;
> ++ memset(&save,0,sizeof(CopyData));
> ++ memcpy(save.copy_data,(ep+1),save_len+1);
> ++ save.cnt = save_len;
> ++ *ep = '\n';
> ++ *(ep+1) = '\0';
> ++ status = PGR_Send_Copy(copy,0);
> ++ memset(copy,0,sizeof(CopyData));
> ++ if (save_len > 0)
> ++ {
> ++ memcpy(copy,&save,sizeof(CopyData));
> ++ }
> ++ rest_buf_size = buf_size - copy->cnt;
> ++
> ++ }
> ++ else
> ++ {
> ++ /* one record is bigger than COPYBUFSIZ */
> ++ /* buffer would be over flow*/
> ++ status = PGR_Send_Copy(copy,0);
> ++ memset(copy,0,sizeof(CopyData));
> ++ rest_buf_size = buf_size - copy->cnt;
> ++ }
> ++ }
> ++ }
> ++ if (end)
> ++ {
> ++ status = PGR_Send_Copy(copy,end);
> ++ memset(copy,0,sizeof(CopyData));
> ++ }
> ++ if (status != STATUS_OK)
> ++ {
> ++ return (CopyData *)NULL;
> ++ }
> ++ return copy;
> ++}
> ++
> ++int
> ++PGR_replication(char * query_string, CommandDest dest, Node *parsetree,
> const char * commandTag)
> ++{
> ++ char *result = NULL;
> ++ char cmdSts = CMD_STS_OTHER;
> ++ char cmdType = CMD_TYPE_OTHER;
> ++ int query_len = 0;
> ++
> ++ if ((query_string == NULL) ||
> ++ (commandTag == NULL))
> ++ {
> ++ return STATUS_ERROR;
> ++ }
> ++
> ++ Query_String = NULL;
> ++ query_len = strlen(query_string);
> ++
> ++ /* save query data for retry */
> ++ PGR_Retry_Query.query_string = query_string;
> ++ PGR_Retry_Query.query_len = query_len;
> ++ PGR_Retry_Query.cmdSts = cmdSts;
> ++ PGR_Retry_Query.cmdType = cmdType;
> ++ 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 ;
> ++
> ++ /* only "replication_server" statement-name is replicated for SHOW. */
> ++ /* see CreateCommandTag() @ backend/tcop/postgres.c */
> ++ /*
> ++ else if (!strcmp(commandTag,"SHOW"))
> ++ {
> ++ }
> ++ */
> ++
> ++ else if (!strcmp(commandTag,"COPY"))
> ++ {
> ++ cmdType = CMD_TYPE_COPY ;
> ++ if (is_copy_from(query_string))
> ++ {
> ++ PGR_Copy_Data_Need_Replicate = true;
> ++ }
> ++ else
> ++ {
> ++ PGR_Copy_Data_Need_Replicate = false;
> ++ return STATUS_NOT_REPLICATE;
> ++ }
> ++ }
> ++ else if (!strcmp(commandTag,"SET"))
> ++ {
> ++ /* set pgr_force_loadbalance to on */
> ++ if (strstr(query_string,SYS_QUERY_1) != NULL)
> ++ {
> ++ return STATUS_NOT_REPLICATE;
> ++ }
> ++ cmdType = CMD_TYPE_SET;
> ++ }
> ++ else if (!strcmp(commandTag,"CREATE TABLE"))
> ++ {
> ++ if (is_create_temp_table(query_string))
> ++ {
> ++ Create_Temp_Table_Mode = true;
> ++ }
> ++ }
> ++ if (Create_Temp_Table_Mode)
> ++ {
> ++ cmdSts = CMD_STS_TEMP_TABLE ;
> ++ }
> ++ if (Transaction_Mode > 0)
> ++ {
> ++ cmdSts = CMD_STS_TRANSACTION ;
> ++ }
> ++ else if ((cmdType == CMD_TYPE_COMMIT ) ||
> ++ (cmdType == CMD_TYPE_ROLLBACK ))
> ++ {
> ++ cmdSts = CMD_STS_TRANSACTION ;
> ++ if (ReplicateCurrentTime != NULL)
> ++ {
> ++ ReplicateCurrentTime->useFlag = DATA_INIT;
> ++ ReplicateCurrentTime->use_seed = 0;
> ++ }
> ++ }
> ++ if (Session_Authorization_Mode)
> ++ {
> ++ cmdSts = CMD_STS_SET_SESSION_AUTHORIZATION ;
> ++ if (cmdType == CMD_TYPE_SESSION_AUTHORIZATION_END)
> ++ {
> ++ Session_Authorization_Mode = false;
> ++ }
> ++ }
> ++ if ((cmdSts == CMD_STS_TRANSACTION ) ||
> ++ (cmdSts == CMD_STS_SET_SESSION_AUTHORIZATION ) ||
> ++ (cmdSts == CMD_STS_TEMP_TABLE ))
> ++ {
> ++ /* check partitional replication table */
> ++ if (is_not_replication_query(query_string, query_len,
> cmdType)== true )
> ++ {
> ++ PGR_Copy_Data_Need_Replicate = false;
> ++ return STATUS_NOT_REPLICATE;
> ++ }
> ++ 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);
> ++ PGR_Retry_Query.cmdSts = cmdSts;
> ++ 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)
> ++ {
> ++ Query_String = NULL;
> ++ /* check partitional replication table */
> ++ if (is_not_replication_query(query_string, query_len,
> cmdType)== true )
> ++ {
> ++ PGR_Copy_Data_Need_Replicate = false;
> ++ return STATUS_NOT_REPLICATE;
> ++ }
> ++ 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;
> ++ }
> ++ /*
> ++ PGR_Send_Message_To_Frontend(result);
> ++ */
> ++ 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))
> ++ {
> ++ Query_String = NULL;
> ++ PGR_Need_Notice = true;
> ++ 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
> ++ {
> ++ Query_String = query_string;
> ++ /*PGR_Sock_To_Replication_Server = -1;*/
> ++ }
> ++ return STATUS_CONTINUE_SELECT;
> ++ }
> ++ }
> ++ return STATUS_CONTINUE;
> ++}
> ++
> ++
> ++bool
> ++PGR_Is_System_Command(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)
> ++{
> ++ int cnt;
> ++ int portNumber;
> ++ int recoveryPortNumber;
> ++ ReplicateServerInfo * sp;
> ++
> ++ if ((hostname == NULL) ||
> ++ (port == NULL ) ||
> ++ (recovery_port == NULL ))
> ++ {
> ++ return STATUS_ERROR;
> ++ }
> ++ if (ReplicateServerData == NULL)
> ++ {
> ++ return STATUS_ERROR;
> ++ }
> ++ portNumber = atoi(port);
> ++ recoveryPortNumber = atoi(recovery_port);
> ++ cnt = 0;
> ++ sp = ReplicateServerData;
> ++ while (sp->useFlag != DATA_END){
> ++ if((!strncmp(sp->hostName,hostname,sizeof(sp->hostName))) &&
> ++ (sp->portNumber == portNumber) &&
> ++ (sp->recoveryPortNumber == recoveryPortNumber))
> ++ {
> ++ 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 = recoveryPortNumber;
> ++ 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;
> ++ int portNumber;
> ++ int recoveryPortNumber;
> ++ ReplicateServerInfo * sp;
> ++
> ++ if ((hostname == NULL) ||
> ++ (port == NULL ) ||
> ++ (recovery_port == NULL ))
> ++ {
> ++ return STATUS_ERROR;
> ++ }
> ++ if (ReplicateServerData == NULL)
> ++ {
> ++ return STATUS_ERROR;
> ++ }
> ++ portNumber = atoi(port);
> ++ recoveryPortNumber = atoi(recovery_port);
> ++ cnt = 0;
> ++ sp = ReplicateServerData;
> ++ while (sp->useFlag != DATA_END){
> ++ if((!strcmp(sp->hostName,hostname)) &&
> ++ (sp->portNumber == portNumber) &&
> ++ (sp->recoveryPortNumber == recoveryPortNumber))
> ++ {
> ++ 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)
> ++{
> ++ int rtn = 0;
> ++ struct timeval local_tp;
> ++ struct timezone local_tpz;
> ++ struct timeval tv;
> ++
> ++ if ((sec == NULL) ||
> ++ (usec == NULL))
> ++ {
> ++ return STATUS_ERROR;
> ++ }
> ++ rtn = gettimeofday(&local_tp, &local_tpz);
> ++ tv.tv_sec = atol(sec);
> ++ tv.tv_usec = atol(usec);
> ++ ReplicateCurrentTime->offset_sec = local_tp.tv_sec - tv.tv_sec;
> ++ ReplicateCurrentTime->offset_usec = local_tp.tv_usec - tv.tv_usec;
> ++ ReplicateCurrentTime->tp.tv_sec = tv.tv_sec;
> ++ ReplicateCurrentTime->tp.tv_usec = tv.tv_usec;
> ++ ReplicateCurrentTime->useFlag = DATA_USE;
> ++ ReplicateCurrentTime->use_seed = 0;
> ++
> ++ return STATUS_OK;
> ++}
> ++
> ++static void
> ++PGR_Set_Current_Replication_Query_ID(char *id) {
> ++ MyProc->replicationId=atol(id);
> ++ return;
> ++}
> ++
> ++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 (CurrentReplicateServer == NULL)
> ++ {
> ++ PGR_get_replicate_server_info();
> ++ if (CurrentReplicateServer == NULL)
> ++ {
> ++ return;
> ++ }
> ++ }
> ++ if (CurrentReplicateServer->response_mode != response_mode)
> ++ {
> ++ 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 ((command == NULL) || (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 (atol(argv[1]) == 0)
> ++ {
> ++ CreateCheckPoint(false,true);
> ++ }
> ++ else
> ++ {
> ++ /*
> ++ if ((atoi(argv[3]) > 0) &&
> ++ (is_this_query_replicated(argv[3]) == true))
> ++ {
> ++ return STATUS_SKIP_QUERY;
> ++ }
> ++ */
> ++ PGR_Set_Current_Time(argv[1],argv[2]);
> ++ set_replication_id(argv[3]);
> ++ set_response_mode(argv[4]);
> ++ PGR_Set_Current_Replication_Query_ID(argv[5]);
> ++
> ++ }
> ++ 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]);
> ++ 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;
> ++ case PGR_SET_CURRENT_REPLICATION_QUERY_ID_NO:
> ++ PGR_Set_Current_Replication_Query_ID(argv[1]);
> ++ 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;
> ++ /* set noticed session abort */
> ++ case PGR_NOTICE_ABORT_FUNC_NO:
> ++ PGR_Noticed_Abort = 1;
> ++ break;
> ++ }
> ++ return STATUS_OK;
> ++}
> ++
> ++int
> ++PGR_GetTimeOfDay(struct timeval *tp, struct timezone *tpz)
> ++{
> ++
> ++ int rtn;
> ++
> ++ rtn = gettimeofday(tp, tpz);
> ++ if (ReplicateCurrentTime == NULL)
> ++ {
> ++ return rtn;
> ++ }
> ++ if (ReplicateCurrentTime->useFlag == DATA_USE)
> ++ {
> ++ if (ReplicateCurrentTime->use_seed != 0)
> ++ {
> ++ tp->tv_sec -= ReplicateCurrentTime->offset_sec;
> ++ if (tp->tv_usec < ReplicateCurrentTime->offset_usec)
> ++ {
> ++ tp->tv_usec += (1000000 -
> ReplicateCurrentTime->offset_usec);
> ++ tp->tv_sec -= 1;
> ++ }
> ++ else
> ++ {
> ++ tp->tv_usec -=
> ReplicateCurrentTime->offset_usec;
> ++ }
> ++ }
> ++ else
> ++ {
> ++ tp->tv_sec = ReplicateCurrentTime->tp.tv_sec;
> ++ tp->tv_usec = ReplicateCurrentTime->tp.tv_usec;
> ++ }
> ++ rtn = 0;
> ++ }
> ++ return rtn;
> ++}
> ++
> ++long
> ++PGR_Random(void)
> ++{
> ++ double rtn;
> ++ if (ReplicateCurrentTime != NULL)
> ++ {
> ++ if ( ReplicateCurrentTime->use_seed == 0)
> ++ {
> ++ srand( ReplicateCurrentTime->tp.tv_usec );
> ++ }
> ++ }
> ++ rtn = random();
> ++ return rtn;
> ++}
> ++
> ++char *
> ++PGR_scan_terminate( char * str)
> ++{
> ++ char * p;
> ++ int sflag = 0;
> ++ int dflag = 0;
> ++ int lflag = 0;
> ++ int i = 0;
> ++ char tag[256];
> ++
> ++ if (str == NULL)
> ++ return NULL;
> ++ p = str;
> ++ memset(tag,0,sizeof(tag));
> ++ 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 '$':
> ++ i = 0;
> ++ p++;
> ++ while (( *p != '\n') && (*p != '\0'))
> ++ {
> ++ if (isalnum(*p) == 0)
> ++ {
> ++ if (*p == '$')
> ++ {
> ++ lflag ^= 1;
> ++ }
> ++ break;
> ++ }
> ++ else
> ++ {
> ++ if (i >= sizeof(tag))
> ++ break;
> ++ if (lflag == 0)
> ++ {
> ++ tag[i] = *p;
> ++ }
> ++ else
> ++ {
> ++ if (tag[i] != *p)
> ++ {
> ++ break;
> ++ }
> ++ }
> ++ i++;
> ++ }
> ++ p++;
> ++ }
> ++ break;
> ++ case '\\':
> ++ p +=2;
> ++ continue;
> ++ break;
> ++ case ';':
> ++ if ((!sflag) && (!dflag) && (!lflag))
> ++ return p;
> ++ break;
> ++ }
> ++ p++;
> ++ }
> ++ return NULL;
> ++}
> ++
> ++static bool
> ++is_copy_from(char * query)
> ++{
> ++ char * p;
> ++ int i;
> ++ char buf[12];
> ++ int c_flag = 0;
> ++ if (query == NULL)
> ++ return false;
> ++ p = 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(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
> ++get_words( char words[MAX_WORDS][MAX_WORD_LETTERS] ,char * string,int
> length,int upper)
> ++{
> ++ int i,wc,lc;
> ++ char * p = NULL;
> ++ char * buf = NULL;
> ++
> ++ if (string == NULL)
> ++ return STATUS_ERROR;
> ++ buf = malloc(length);
> ++ if (buf == NULL)
> ++ return STATUS_ERROR;
> ++
> ++ memset(buf,0,length);
> ++ p = 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 = strcasecmp(nrp1->table_name,nrp2->table_name);
> ++ if (rtn == 0)
> ++ {
> ++ rtn = strcasecmp(nrp1->db_name,nrp2->db_name);
> ++ }
> ++ return rtn;
> ++}
> ++
> ++bool
> ++PGR_Is_Stand_Alone(void)
> ++{
> ++ ReplicateServerInfo * sp = NULL;
> ++
> ++ if (PGR_Stand_Alone == NULL)
> ++ return true;
> ++ if (PGR_Stand_Alone->is_stand_alone == true)
> ++ {
> ++ sp = PGR_get_replicate_server_info();
> ++ if (sp == NULL)
> ++ {
> ++ return true;
> ++ }
> ++ }
> ++ return false;
> ++}
> ++
> ++void
> ++PGR_Send_Message_To_Frontend(const char * msg)
> ++{
> ++ StringInfoData msgbuf;
> ++
> ++ pq_beginmessage(&msgbuf, 'N');
> ++
> ++ if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 3)
> ++ {
> ++ /* New style with separate fields */
> ++ char tbuf[12];
> ++ int ssval;
> ++ int i;
> ++
> ++ pq_sendbyte(&msgbuf, PG_DIAG_SEVERITY);
> ++ pq_sendstring(&msgbuf, "NOTICE" );
> ++
> ++ /* unpack MAKE_SQLSTATE code */
> ++ ssval = ERRCODE_WARNING ;
> ++ for (i = 0; i < 5; i++)
> ++ {
> ++ tbuf[i] = PGUNSIXBIT(ssval);
> ++ ssval >>= 6;
> ++ }
> ++ tbuf[i] = '\0';
> ++
> ++ pq_sendbyte(&msgbuf, PG_DIAG_SQLSTATE);
> ++ pq_sendstring(&msgbuf, tbuf);
> ++
> ++ /* M field is required per protocol, so always send something
> */
> ++ pq_sendbyte(&msgbuf, PG_DIAG_MESSAGE_PRIMARY);
> ++ if (msg)
> ++ pq_sendstring(&msgbuf, msg);
> ++ else
> ++ pq_sendstring(&msgbuf, _("missing error text"));
> ++
> ++ pq_sendbyte(&msgbuf, '\0'); /* terminator */
> ++ }
> ++ else
> ++ {
> ++ /* Old style --- gin up a backwards-compatible message */
> ++ StringInfoData buf;
> ++
> ++ initStringInfo(&buf);
> ++
> ++ appendStringInfo(&buf, "%s: ", "NOTICE");
> ++
> ++ if (msg)
> ++ appendStringInfoString(&buf, msg);
> ++ else
> ++ appendStringInfoString(&buf, _("missing error text"));
> ++
> ++ appendStringInfoChar(&buf, '\n');
> ++
> ++ pq_sendstring(&msgbuf, buf.data);
> ++
> ++ pfree(buf.data);
> ++ }
> ++
> ++ pq_endmessage(&msgbuf);
> ++
> ++ /*
> ++ * This flush is normally not necessary, since postgres.c will flush
> out
> ++ * waiting data when control returns to the main loop. But it seems
> best
> ++ * to leave it here, so that the client has some clue what happened
> if the
> ++ * backend dies before getting back to the main loop ... error/notice
> ++ * messages should not be a performance-critical path anyway, so an
> extra
> ++ * flush won't hurt much ...
> ++ */
> ++ pq_flush();
> ++}
> ++
> ++static bool
> ++is_serial_control_query(char cmdType,char * query)
> ++{
> ++ char * buf = NULL;
> ++ int len = 0;
> ++ int i = 0;
> ++ char * p = NULL;
> ++
> ++ if ((cmdType != CMD_TYPE_SELECT ) ||
> ++ ( query == NULL))
> ++ {
> ++ return false;
> ++ }
> ++
> ++ p = query;
> ++ len = strlen(query) +1;
> ++ buf = malloc(len);
> ++ if (buf == 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,char * query)
> ++{
> ++ char * buf = NULL;
> ++ int len = 0;
> ++ int i = 0;
> ++ char * p = NULL;
> ++
> ++ if ((cmdType != CMD_TYPE_SELECT ) ||
> ++ ( query == NULL))
> ++ {
> ++ return false;
> ++ }
> ++
> ++ p = query;
> ++ len = strlen(query) +1;
> ++ buf = malloc(len);
> ++ if (buf == 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;
> ++ }
> ++ if (strstr(buf,"CREATE") != 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 (PGR_Lock_Noticed)
> ++ {
> ++ return STATUS_OK;
> ++ }
> ++ if ((notice == NULL) ||
> ++ (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(PGR_Sock_To_Replication_Server,&header,(char
> *)notice);
> ++ return status;
> ++}
> ++
> ++void
> ++PGR_Notice_Transaction_Query_Done(void)
> ++{
> ++ send_response_to_replication_server(PGR_QUERY_DONE_NOTICE_CMD);
> ++}
> ++
> ++void
> ++PGR_Notice_Transaction_Query_Aborted(void)
> ++{
> ++ send_response_to_replication_server(PGR_QUERY_ABORTED_NOTICE_CMD);
> ++}
> ++
> ++int
> ++PGR_Notice_Conflict(void)
> ++{
> ++ const char * msg = NULL ;
> ++ int rtn = STATUS_OK;
> ++
> ++ msg = PGR_LOCK_CONFLICT_NOTICE_CMD ;
> ++ if (PGR_Check_Lock.deadlock == true)
> ++ {
> ++ msg = PGR_DEADLOCK_DETECT_NOTICE_CMD ;
> ++ }
> ++ if (PGR_Check_Lock.dest == TO_FRONTEND)
> ++ {
> ++ ReadyForQuery(DestRemote);
> ++ EndCommand(msg,DestRemote);
> ++#ifdef CONTROL_LOCK_CONFLICT
> ++ rtn = wait_lock_answer();
> ++#endif /* CONTROL_LOCK_CONFLICT */
> ++ }
> ++ else
> ++ {
> ++ send_response_to_replication_server(msg);
> ++#ifdef CONTROL_LOCK_CONFLICT
> ++ rtn = PGR_Recv_Trigger (PGR_RECV_TIMEOUT);
> ++#endif /* CONTROL_LOCK_CONFLICT */
> ++ }
> ++ 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;
> ++ }
> ++ 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 /* CONTROL_LOCK_CONFLICT */
> ++
> ++int
> ++PGR_Recv_Trigger (int user_timeout)
> ++{
> ++ char result[PGR_MESSAGE_BUFSIZE];
> ++ int rtn = 0;
> ++ int func_no = 0;
> ++
> ++
> ++ if (PGR_Lock_Noticed)
> ++ {
> ++ return STATUS_OK;
> ++ }
> ++ if (PGR_Sock_To_Replication_Server < 0)
> ++ return STATUS_ERROR;
> ++ memset(result,0,sizeof(result));
> ++ rtn =
> recv_replicate_result(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(CurrentReplicateServer, DATA_ERR);
> ++ }
> ++ return STATUS_ERROR;
> ++ }
> ++ return STATUS_OK;
> ++}
> ++
> ++int
> ++PGR_Set_Transaction_Mode(int mode,const char * commandTag)
> ++{
> ++ if (commandTag == NULL)
> ++ {
> ++ return mode;
> ++ }
> ++ if ((!strcmp(commandTag,"BEGIN")) ||
> ++ (!strcmp(commandTag,"START TRANSACTION")) )
> ++ {
> ++ return (++mode);
> ++ }
> ++ if (mode > 0)
> ++ {
> ++ if ((!strncmp(commandTag,"COMMIT",strlen("COMMIT"))) ||
> ++ (!strncmp(commandTag,"ROLLBACK",strlen("ROLLBACK"))))
> ++ {
> ++ return (--mode);
> ++ }
> ++ }
> ++ /*
> ++ if (autocommit == false)
> ++ {
> ++ return mode;
> ++ }
> ++ */
> ++ return mode;
> ++}
> ++
> ++
> ++
> ++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,"EXPLAIN")))
> ++ {
> ++ return true;
> ++ }
> ++ else
> ++ {
> ++ 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(char * query)
> ++{
> ++ char skip_2[256];
> ++
> ++ if ((query == NULL) ||
> ++ (MyProcPort == NULL))
> ++ {
> ++ return -1;
> ++ }
> ++ snprintf(skip_2,sizeof(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 = -1;
> ++ 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 (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;
> ++ }
> ++ result = malloc(PGR_MESSAGE_BUFSIZE);
> ++ if (result == NULL)
> ++ {
> ++ return false;
> ++ }
> ++ memset(result,0,PGR_MESSAGE_BUFSIZE);
> ++
> ++ 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(ReplicateCurrentTime->tp.tv_sec);
> ++ header.tv.tv_usec = htonl(ReplicateCurrentTime->tp.tv_usec);
> ++ header.query_size = htonl(0);
> ++ strncpy(header.dbName ,(char
> *)(MyProcPort->database_name),sizeof(header.dbName)-1);
> ++ strncpy(header.userName , (char
> *)(MyProcPort->user_name),sizeof(header.userName)-1);
> ++ if (PGRSelfHostName != NULL)
> ++ {
> ++ strncpy(header.from_host, PGRSelfHostName,
> HOSTNAME_MAX_LENGTH);
> ++ }
> ++ header.replicate_id = htonl(ReplicationLog_Info.PGR_Replicate_ID);
> ++ header.request_id = 0;
> ++
> ++ base = sp;
> ++ PGR_Sock_To_Replication_Server = sock;
> ++
> ++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");
> ++ PGR_Stand_Alone->is_stand_alone = true;
> ++ free(result);
> ++ result = NULL;
> ++ return false;
> ++ }
> ++ 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");
> ++ PGR_Stand_Alone->is_stand_alone = true;
> ++ free(result);
> ++ result = NULL;
> ++ return false;
> ++ }
> ++ 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;
> ++}
> ++
> ++int
> ++PGRsend_system_command(char cmdSts, char cmdType)
> ++{
> ++ ReplicateServerInfo * sp = NULL;
> ++ int sock = -1;
> ++ int socket_type = 0;
> ++ char * result = NULL;
> ++ char * serverName = NULL;
> ++ int portNumber=0;
> ++ ReplicateHeader header;
> ++ int cnt = 0;
> ++ ReplicateServerInfo * base = NULL;
> ++
> ++ sp = PGR_get_replicate_server_info();
> ++ if (sp == NULL)
> ++ {
> ++ if (Debug_pretty_print)
> ++ elog(DEBUG1,"PGR_get_replicate_server_info get
> error");
> ++ return STATUS_ERROR;
> ++ }
> ++ sock = get_replicate_server_socket( sp , PGR_QUERY_SOCKET);
> ++ if (sock < 0)
> ++ {
> ++ if (Debug_pretty_print)
> ++ elog(DEBUG1,"get_replicate_server_socket fail");
> ++ return STATUS_ERROR;
> ++ }
> ++ result = malloc(PGR_MESSAGE_BUFSIZE);
> ++ if (result == NULL)
> ++ {
> ++ return STATUS_ERROR;
> ++ }
> ++ memset(result,0,PGR_MESSAGE_BUFSIZE);
> ++
> ++ serverName = sp->hostName;
> ++ portNumber = (int)sp->portNumber;
> ++ header.cmdSys = CMD_SYS_CALL;
> ++ header.cmdSts = cmdSts;
> ++ header.cmdType = cmdType;
> ++ header.port = htons(PostPortNumber);
> ++ header.pid = htons(getpid());
> ++ header.tv.tv_sec = htonl(ReplicateCurrentTime->tp.tv_sec);
> ++ header.tv.tv_usec = htonl(ReplicateCurrentTime->tp.tv_usec);
> ++ header.query_size = htonl(0);
> ++ strncpy(header.dbName ,(char
> *)(MyProcPort->database_name),sizeof(header.dbName)-1);
> ++ strncpy(header.userName , (char
> *)(MyProcPort->user_name),sizeof(header.userName)-1);
> ++ if (PGRSelfHostName != NULL)
> ++ {
> ++ strncpy(header.from_host, PGRSelfHostName,
> HOSTNAME_MAX_LENGTH);
> ++ }
> ++ header.replicate_id = htonl(ReplicationLog_Info.PGR_Replicate_ID);
> ++ header.request_id = 0;
> ++
> ++ base = sp;
> ++ PGR_Sock_To_Replication_Server = sock;
> ++ 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");
> ++ PGR_Stand_Alone->is_stand_alone = true;
> ++ free(result);
> ++ result = NULL;
> ++ return STATUS_ERROR;
> ++ }
> ++ PGR_Sock_To_Replication_Server = sock;
> ++ cnt = 0;
> ++ }
> ++ cnt ++;
> ++ }
> ++ free(result);
> ++ result = NULL;
> ++ return STATUS_OK;
> ++}
> ++
> ++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;
> ++}
> ++
> ++char *
> ++PGR_Remove_Comment(char * str)
> ++{
> ++ char * p = NULL;
> ++ p = 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 (PGR_Retry_Query.useFlag == DATA_USE)
> ++ {
> ++ PGR_Send_Replicate_Command(PGR_Retry_Query.query_string,
> ++ PGR_Retry_Query.query_len,
> ++ PGR_Retry_Query.cmdSts,
> ++ PGR_Retry_Query.cmdType);
> ++ }
> ++}
> ++
> ++void
> ++PGR_Notice_DeadLock(void)
> ++{
> ++ ReplicateHeader header;
> ++
> ++ 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(PGR_Sock_To_Replication_Server,&header,(char
> *)NULL);
> ++}
> ++
> ++void
> ++PGR_Set_Cluster_Status(int status)
> ++{
> ++ if (ClusterDBData != NULL)
> ++ {
> ++ if (ClusterDBData->status != status)
> ++ {
> ++ ClusterDBData->status = status;
> ++ }
> ++ }
> ++}
> ++
> ++int
> ++PGR_Get_Cluster_Status(void)
> ++{
> ++ if (ClusterDBData != NULL)
> ++ {
> ++ return (ClusterDBData->status);
> ++ }
> ++ return 0;
> ++}
> ++
> ++int
> ++PGR_Check_Replicate_Server_Status(ReplicateServerInfo * sp)
> ++{
> ++ ReplicateHeader header;
> ++ char * result = NULL;
> ++ int status;
> ++ int fdP;
> ++
> ++ result = malloc(PGR_MESSAGE_BUFSIZE + 4);
> ++ if (result == NULL)
> ++ {
> ++ if (Debug_pretty_print)
> ++ elog(DEBUG1,"malloc failed in
> PGR_Check_Replicate_Server_Status()");
> ++ return STATUS_ERROR;
> ++ }
> ++
> ++ memset(&header, 0, sizeof(ReplicateHeader));
> ++ memset(result, 0, PGR_MESSAGE_BUFSIZE + 4);
> ++
> ++ header.cmdSys = CMD_SYS_PREREPLICATE;
> ++ header.cmdSts = CMD_STS_OTHER;
> ++ header.cmdType = CMD_TYPE_OTHER;
> ++ header.port = htons(PostPortNumber);
> ++ header.pid = htons(getpid());
> ++ header.query_size = 0;
> ++ strncpy(header.dbName ,(char
> *)(MyProcPort->database_name),sizeof(header.dbName)-1);
> ++ strncpy(header.userName , (char
> *)(MyProcPort->user_name),sizeof(header.userName)-1);
> ++ header.request_id = htonl(get_next_request_id());
> ++ header.rlog = 0;
> ++ if (PGRSelfHostName != NULL) {
> ++ strncpy(header.from_host, PGRSelfHostName,
> HOSTNAME_MAX_LENGTH);
> ++ }
> ++
> ++ /* open a new socket for lifecheck */
> ++ if ((status = PGR_Create_Socket_Connect(&fdP, sp->hostName,
> sp->portNumber)) == STATUS_ERROR) {
> ++ if (Debug_pretty_print) {
> ++ elog(DEBUG1,"create socket failed in
> PGR_Create_Socket_Connect()");
> ++ }
> ++
> ++ /* status = STATUS_OK */
> ++ } else {
> ++ if ((status = send_replicate_packet(fdP, &header, (char
> *)NULL)) == STATUS_OK) {
> ++ /* receive result to check for possible deadlock */
> ++ status = (0 < recv_replicate_result(fdP, result ,0))
> ++ ? STATUS_OK : STATUS_ERROR;
> ++ }
> ++ }
> ++
> ++ free(result);
> ++ PGR_Close_Sock(&fdP);
> ++
> ++ return status;
> ++}
> ++
> ++static int
> ++return_current_oid(void)
> ++{
> ++ char msg[PGR_MESSAGE_BUFSIZE];
> ++
> ++ LWLockAcquire(OidGenLock, LW_EXCLUSIVE);
> ++
> ++ if (ShmemVariableCache->nextOid < ((Oid) FirstBootstrapObjectId))
> ++ {
> ++ ShmemVariableCache->nextOid = FirstBootstrapObjectId;
> ++ ShmemVariableCache->oidCount = 0;
> ++ }
> ++
> ++ if (ShmemVariableCache->oidCount == 0)
> ++ {
> ++ XLogPutNextOid(ShmemVariableCache->nextOid +
> VAR_OID_PREFETCH);
> ++ ShmemVariableCache->oidCount = VAR_OID_PREFETCH;
> ++ }
> ++ LWLockRelease(OidGenLock);
> ++
> ++ memset(msg,0,sizeof(msg));
> ++ snprintf(msg, sizeof(msg), "%u", ShmemVariableCache->nextOid);
> ++ if (PGR_Check_Lock.dest == TO_FRONTEND)
> ++ {
> ++ /*
> ++ PGR_Send_Message_To_Frontend(msg);
> ++ */
> ++ 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];
> ++
> ++ LWLockAcquire(OidGenLock, LW_EXCLUSIVE);
> ++
> ++ 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 < FirstBootstrapObjectId)
> ++ {
> ++ ShmemVariableCache->nextOid = FirstBootstrapObjectId;
> ++ 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 (PGR_Check_Lock.dest == TO_FRONTEND)
> ++ {
> ++ /*
> ++ PGR_Send_Message_To_Frontend(msg);
> ++ */
> ++ pq_puttextmessage('C',msg);
> ++ pq_flush();
> ++ }
> ++ else
> ++ {
> ++ send_response_to_replication_server(msg);
> ++ }
> ++ return STATUS_OK;
> ++}
> ++
> ++int
> ++PGR_lo_import(char * filename)
> ++{
> ++ char * result = NULL;
> ++ LOArgs *lo_args;
> ++ int len = 0;
> ++ int buf_size = 0;
> ++
> ++ if ((PGR_Is_Replicated_Query == true) ||
> ++ (PGR_Retry_Query.cmdSts == CMD_STS_TRANSACTION))
> ++ {
> ++ return STATUS_OK;
> ++ }
> ++ if ((PGR_Retry_Query.cmdSts != CMD_STS_QUERY) ||
> ++ (PGR_Retry_Query.cmdType != CMD_TYPE_SELECT))
> ++ {
> ++ return STATUS_OK;
> ++ }
> ++
> ++ len = strlen(filename);
> ++ buf_size = sizeof(LOArgs) + len;
> ++ lo_args = (LOArgs *)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)len);
> ++ memcpy(lo_args->buf, filename, len);
> ++
> ++ result = PGR_Send_Replicate_Command((char *)lo_args,
> ++ buf_size,
> ++ CMD_STS_LARGE_OBJECT,
> ++ CMD_TYPE_LO_IMPORT);
> ++
> ++ free(lo_args);
> ++ if (result != NULL)
> ++ {
> ++ free(result);
> ++ return STATUS_OK;
> ++ }
> ++
> ++ return STATUS_ERROR;
> ++}
> ++
> ++int
> ++PGR_lo_create(int flags)
> ++{
> ++ char * result = NULL;
> ++ LOArgs lo_args;
> ++
> ++ if ((PGR_Is_Replicated_Query == true) ||
> ++ (PGR_Retry_Query.cmdSts == CMD_STS_TRANSACTION))
> ++ {
> ++ return STATUS_OK;
> ++ }
> ++ if ((PGR_Retry_Query.cmdSts != CMD_STS_QUERY) ||
> ++ (PGR_Retry_Query.cmdType != CMD_TYPE_SELECT))
> ++ {
> ++ 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 ((PGR_Is_Replicated_Query == true) ||
> ++ (PGR_Retry_Query.cmdSts == CMD_STS_TRANSACTION))
> ++ {
> ++ return STATUS_OK;
> ++ }
> ++ if ((PGR_Retry_Query.cmdSts != CMD_STS_QUERY) ||
> ++ (PGR_Retry_Query.cmdType != CMD_TYPE_SELECT))
> ++ {
> ++ 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 ((PGR_Is_Replicated_Query == true) ||
> ++ (PGR_Retry_Query.cmdSts == CMD_STS_TRANSACTION))
> ++ {
> ++ return STATUS_OK;
> ++ }
> ++ if ((PGR_Retry_Query.cmdSts != CMD_STS_QUERY) ||
> ++ (PGR_Retry_Query.cmdType != CMD_TYPE_SELECT))
> ++ {
> ++ 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 ((PGR_Is_Replicated_Query == true) ||
> ++ (PGR_Retry_Query.cmdSts == CMD_STS_TRANSACTION))
> ++ {
> ++ return STATUS_OK;
> ++ }
> ++ if ((PGR_Retry_Query.cmdSts != CMD_STS_QUERY) ||
> ++ (PGR_Retry_Query.cmdType != CMD_TYPE_SELECT))
> ++ {
> ++ 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 ((PGR_Is_Replicated_Query == true) ||
> ++ (PGR_Retry_Query.cmdSts == CMD_STS_TRANSACTION))
> ++ {
> ++ return STATUS_OK;
> ++ }
> ++ if ((PGR_Retry_Query.cmdSts != CMD_STS_QUERY) ||
> ++ (PGR_Retry_Query.cmdType != CMD_TYPE_SELECT))
> ++ {
> ++ 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 ((PGR_Is_Replicated_Query == true) ||
> ++ (PGR_Retry_Query.cmdSts == CMD_STS_TRANSACTION))
> ++ {
> ++ return STATUS_OK;
> ++ }
> ++ if ((PGR_Retry_Query.cmdSts != CMD_STS_QUERY) ||
> ++ (PGR_Retry_Query.cmdType != CMD_TYPE_SELECT))
> ++ {
> ++ 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;
> ++}
> ++
> ++Oid
> ++PGRGetNewObjectId(Oid last_id)
> ++{
> ++ Oid newId = 0;
> ++
> ++ if (last_id == 0)
> ++ {
> ++ newId = (Oid)PGRget_replication_id();
> ++ }
> ++ else
> ++ {
> ++ newId = last_id + 1;
> ++ }
> ++ return newId;
> ++}
> ++
> ++int
> ++PGR_Send_Input_Message(char cmdType,StringInfo input_message)
> ++{
> ++ int len = 0;
> ++ char * ptr = NULL;
> ++ char * result = NULL;
> ++
> ++ if (input_message == NULL)
> ++ {
> ++ return STATUS_ERROR;
> ++ }
> ++ if (PGR_Is_Replicated_Query == true)
> ++ {
> ++ return STATUS_OK;
> ++ }
> ++ len = input_message->len+1;
> ++ ptr = input_message->data;
> ++ result = PGR_Send_Replicate_Command(ptr,len, CMD_STS_PREPARE,cmdType);
> ++ if (result != NULL)
> ++ {
> ++ PGR_Reload_Start_Time();
> ++ free(result);
> ++ result = NULL;
> ++ return STATUS_OK;
> ++ }
> ++ else
> ++ {
> ++ return STATUS_ERROR;
> ++ }
> ++}
> ++
> ++#endif /* USE_REPLICATION */
> +diff -aruN postgresql-8.1.2/src/backend/libpq/replicate_com.c
> pgcluster-1.5.0rc7/src/backend/libpq/replicate_com.c
> +--- postgresql-8.1.2/src/backend/libpq/replicate_com.c 1970-01-01
> 01:00:00.000000000 +0100
> ++++ pgcluster-1.5.0rc7/src/backend/libpq/replicate_com.c 2006-01-10
> 17:39:39.000000000 +0100
> +@@ -0,0 +1,671 @@
> ++/*--------------------------------------------------------------------
> ++ * FILE:
> ++ * replicate_com.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'.
> ++ *
> ++ * Portions Copyright (c) 2003-2006, Atsushi Mitani
> ++ *--------------------------------------------------------------------
> ++ */
> ++
> ++/*--------------------------------------
> ++ * 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/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 "libpq/libpq.h"
> ++#include "miscadmin.h"
> ++#include "nodes/print.h"
> ++#include "utils/guc.h"
> ++#include "parser/parser.h"
> ++#include "access/xact.h"
> ++#include "replicate_com.h"
> ++
> ++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);
> ++
> ++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);
> ++
> ++/*--------------------------------------------------------------------
> ++ * 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);
> ++ if ((sock = accept(fd, &addr, &len)) < 0)
> ++ {
> ++ *sockP = -1;
> ++ return STATUS_ERROR;
> ++ }
> ++
> ++ 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));
> ++ }
> ++ memcpy(conf_data->key,key,sizeof(conf_data->key));
> ++ memcpy(conf_data->value,value,sizeof(conf_data->value));
> ++ conf_data->rec_no = rec_no;
> ++ if (ConfData_Top == (ConfDataType *)NULL)
> ++ {
> ++ ConfData_Top = conf_data;
> ++ conf_data->last = (char *)NULL;
> ++ }
> ++ if (ConfData_End == (ConfDataType *)NULL)
> ++ {
> ++ conf_data->last = (char *)NULL;
> ++ }
> ++ else
> ++ {
> ++ conf_data->last = (char *)ConfData_End;
> ++ ConfData_End->next = (char *)conf_data;
> ++ }
> ++ 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_Top == (ConfDataType *)NULL)
> ++ {
> ++ return STATUS_ERROR;
> ++ }
> ++ conf = ConfData_Top;
> ++
> ++ while (conf != (ConfDataType *)NULL)
> ++ {
> ++ nextp = (ConfDataType*)conf->next;
> ++ free (conf);
> ++ conf = nextp;
> ++ }
> ++ ConfData_Top = 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_Top = 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;
> ++}
> ++
> ++#if 0
> ++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;
> ++ }
> ++}
> ++#endif
> ++
> ++#endif /* USE_REPLICATION */
> +diff -aruN postgresql-8.1.2/src/backend/parser/parse_clause.c
> pgcluster-1.5.0rc7/src/backend/parser/parse_clause.c
> +--- postgresql-8.1.2/src/backend/parser/parse_clause.c 2005-11-22
> 19:23:13.000000000 +0100
> ++++ pgcluster-1.5.0rc7/src/backend/parser/parse_clause.c 2006-01-23
> 07:10:23.000000000 +0100
> +@@ -34,6 +34,10 @@
> + #include "utils/builtins.h"
> + #include "utils/guc.h"
> +
> ++#ifdef USE_REPLICATION
> ++#include "replicate.h"
> ++extern bool auto_lock_table;
> ++#endif /* USE_REPLICATION */
> +
> + #define ORDER_CLAUSE 0
> + #define GROUP_CLAUSE 1
> +@@ -154,7 +158,18 @@
> + * analyze.c will eventually do the corresponding heap_close(), but
> *not*
> + * release the lock.
> + */
> ++#ifdef USE_REPLICATION
> ++ if ((auto_lock_table == true) && (Transaction_Mode < 1))
> ++ {
> ++ pstate->p_target_relation = heap_openrv(relation,
> ShareRowExclusiveLock);
> ++ }
> ++ else
> ++ {
> ++ pstate->p_target_relation = heap_openrv(relation,
> RowExclusiveLock);
> ++ }
> ++#else
> + pstate->p_target_relation = heap_openrv(relation, RowExclusiveLock);
> ++#endif /* USE_REPLICATION */
> +
> + /*
> + * Now build an RTE.
> +diff -aruN postgresql-8.1.2/src/backend/parser/parse_relation.c
> pgcluster-1.5.0rc7/src/backend/parser/parse_relation.c
> +--- postgresql-8.1.2/src/backend/parser/parse_relation.c 2005-11-22
> 19:23:14.000000000 +0100
> ++++ pgcluster-1.5.0rc7/src/backend/parser/parse_relation.c 2006-01-23
> 07:12:19.000000000 +0100
> +@@ -30,6 +30,10 @@
> + #include "utils/lsyscache.h"
> + #include "utils/syscache.h"
> +
> ++#ifdef USE_REPLICATION
> ++#include "replicate.h"
> ++extern bool auto_lock_table;
> ++#endif /* USE_REPLICATION */
> +
> + /* GUC parameter */
> + bool add_missing_from;
> +@@ -587,7 +591,14 @@
> + * to a rel in a statement, be careful to get the right access level
> + * depending on whether we're doing SELECT FOR UPDATE/SHARE.
> + */
> ++#ifdef USE_REPLICATION
> ++ if ((auto_lock_table == true) && (Transaction_Mode < 2))
> ++ lockmode = isLockedRel(pstate, refname) ?
> ShareRowExclusiveLock : AccessShareLock;
> ++ else
> ++ lockmode = isLockedRel(pstate, refname) ? RowShareLock :
> AccessShareLock;
> ++#else
> + lockmode = isLockedRel(pstate, refname) ? RowShareLock :
> AccessShareLock;
> ++#endif /* USE_REPLICATION */
> + rel = heap_openrv(relation, lockmode);
> + rte->relid = RelationGetRelid(rel);
> +
> +diff -aruN postgresql-8.1.2/src/backend/postmaster/postmaster.c
> pgcluster-1.5.0rc7/src/backend/postmaster/postmaster.c
> +--- postgresql-8.1.2/src/backend/postmaster/postmaster.c 2006-01-06
> 03:58:32.000000000 +0100
> ++++ pgcluster-1.5.0rc7/src/backend/postmaster/postmaster.c 2006-01-31
> 13:12:17.000000000 +0100
> +@@ -128,6 +128,9 @@
> + #include "storage/spin.h"
> + #endif
> +
> ++#ifdef USE_REPLICATION
> ++#include "replicate.h"
> ++#endif /* USE_REPLICATION */
> +
> + /*
> + * List of active backends (or child processes anyway; we don't actually
> +@@ -370,6 +373,49 @@
> + #define StartupDataBase() StartChildProcess(BS_XLOG_STARTUP)
> + #define StartBackgroundWriter() StartChildProcess(BS_XLOG_BGWRITER)
> +
> ++#ifdef USE_REPLICATION
> ++char * Query_String = NULL;
> ++ReplicateServerInfo * ReplicateServerData = NULL;
> ++ReplicateServerInfo * CurrentReplicateServer = NULL;
> ++ReplicateServerInfo * LastReplicateServer = NULL;
> ++int ReplicateServerShmid = -1;
> ++int TransactionQuery = 0;
> ++int TransactionSock = -1;
> ++int Transaction_Mode = 0;
> ++int PGR_Noticed_Abort = 0;
> ++bool Session_Authorization_Mode = false;
> ++bool Create_Temp_Table_Mode = false;
> ++ConfDataType * ConfData_Top = (ConfDataType *)NULL;
> ++ConfDataType * ConfData_End = (ConfDataType *)NULL;
> ++int RecoveryPortNumber = 0;
> ++int Master_Pid = 0;
> ++char * RsyncPath = NULL;
> ++char * RsyncOption = NULL;
> ++bool RsyncCompress = true;
> ++ReplicateNow * ReplicateCurrentTime = NULL;
> ++CopyData * PGRCopyData = NULL;
> ++bool PGR_Copy_Data_Need_Replicate = false;
> ++PGR_Stand_Alone_Type * PGR_Stand_Alone = NULL;
> ++PGR_Not_Replicate_Type * PGR_Not_Replicate = NULL;
> ++int PGR_Not_Replicate_Rec_Num = 0;
> ++bool PGR_Is_Replicated_Query = false;
> ++PGR_Check_Lock_Type PGR_Check_Lock;
> ++int PGR_Sock_To_Replication_Server = -1;
> ++bool PGR_Need_Notice = false;
> ++bool PGR_Lock_Noticed = false;
> ++bool PGR_Recovery_Option = false;
> ++char * PGRSelfHostName = NULL;
> ++int PGR_Pending_Sem_Num = 0;
> ++bool PGR_Reliable_Mode_Wait = true;
> ++PGR_Retry_Query_Type PGR_Retry_Query;
> ++int ClusterDBShmid = -1;
> ++ClusterDBInfo * ClusterDBData = NULL;
> ++bool PGRforceLoadBalance=false;
> ++
> ++bool needToUpdateReplicateIdOnNextQueryIsDone=false;
> ++bool PGR_Is_Sync_OID = false;
> ++
> ++#endif /* USE_REPLICATION */
> +
> + /*
> + * Postmaster main entry point
> +@@ -382,6 +428,11 @@
> + char *userDoption = NULL;
> + int i;
> +
> ++#ifdef USE_REPLICATION
> ++ PGR_Check_Lock.check_lock_conflict = false;
> ++ PGR_Check_Lock.status_lock_conflict = STATUS_OK;
> ++#endif /* USE REPLICATION */
> ++
> + /* This will call exit() if strdup() fails. */
> + progname = get_progname(argv[0]);
> +
> +@@ -450,10 +501,15 @@
> +
> + 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)
> + {
> ++ case 'R':
> ++#ifdef USE_REPLICATION
> ++ PGR_Recovery_Option = true;
> ++ break;
> ++#endif /* USE_REPLICATION */
> + case 'A':
> + #ifdef USE_ASSERT_CHECKING
> + SetConfigOption("debug_assertions", optarg,
> PGC_POSTMASTER, PGC_S_ARGV);
> +@@ -685,6 +741,23 @@
> + */
> + CreateDataDirLockFile(true);
> +
> ++#ifdef USE_REPLICATION
> ++ if (PGR_Get_Conf_Data( DataDir, CLUSTER_CONF_FILE ) == STATUS_OK)
> ++ {
> ++ PGR_Init_Replicate_Server_Data();
> ++ PGR_Set_Replicate_Server_Socket();
> ++ PGR_Free_Conf_Data();
> ++ if (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)
> ++ {
> ++ ExitPostmaster(1);
> ++ }
> ++ }
> ++ }
> ++#endif /* USE_REPLICATION */
> + /*
> + * If timezone is not set, determine what the OS uses. (In theory
> this
> + * should be done during GUC initialization, but because it can take
> as
> +@@ -944,6 +1017,21 @@
> + */
> + autovac_init();
> +
> ++#ifdef USE_REPLICATION
> ++ Master_Pid = PGR_Master_Main();
> ++ if (Master_Pid < 0)
> ++ {
> ++ elog(DEBUG1,"PGR_Master_Main failed");
> ++ ExitPostmaster(1);
> ++ }
> ++ if (PGR_Recovery_Option)
> ++ {
> ++ PGR_recovery_finish_send();
> ++ PGR_Recovery_Option = false;
> ++ fprintf(stderr,"OK! The data synchronization with Master DB
> was finished. \n");
> ++ }
> ++#endif /* USE_REPLICATION */
> ++
> + status = ServerLoop();
> +
> + /*
> +@@ -1607,7 +1695,10 @@
> + case CAC_TOOMANY:
> + ereport(FATAL,
> +
> (errcode(ERRCODE_TOO_MANY_CONNECTIONS),
> +- errmsg("sorry, too many clients
> already")));
> ++ errmsg("sorry, too many clients already")));
> ++#ifdef USE_REPLICATION
> ++ return STATUS_ERROR;
> ++#endif
> + break;
> + case CAC_OK:
> + default:
> +@@ -1875,6 +1966,19 @@
> + (errmsg_internal("postmaster received signal %d",
> +
> postgres_signal_arg)));
> +
> ++#ifdef USE_REPLICATION
> ++ if (PGR_Recovery_Option)
> ++ {
> ++ PGR_recovery_error_send();
> ++ PGR_Recovery_Option = false;
> ++ }
> ++ if (Master_Pid > 0)
> ++ {
> ++ kill (Master_Pid,postgres_signal_arg);
> ++ }
> ++ PGR_delete_shm();
> ++#endif /* USE_REPLICATION */
> ++
> + switch (postgres_signal_arg)
> + {
> + case SIGTERM:
> +@@ -3348,6 +3452,16 @@
> + * MUST -- vadim 05-10-1999
> + */
> +
> ++#ifdef USE_REPLICATION
> ++ if (PGR_Recovery_Option)
> ++ {
> ++ write_stderr("sorry, recovery failed.");
> ++ PGR_recovery_error_send();
> ++ PGR_Recovery_Option = false;
> ++ }
> ++ PGR_delete_shm();
> ++#endif /* USE_REPLICATION */
> ++
> + proc_exit(status);
> + }
> +
> +diff -aruN postgresql-8.1.2/src/backend/storage/large_object/inv_api.c
> pgcluster-1.5.0rc7/src/backend/storage/large_object/inv_api.c
> +--- postgresql-8.1.2/src/backend/storage/large_object/inv_api.c
> 2005-10-15 04:49:26.000000000 +0200
> ++++ pgcluster-1.5.0rc7/src/backend/storage/large_object/inv_api.c
> 2006-01-10 17:39:39.000000000 +0100
> +@@ -28,6 +28,10 @@
> + #include "utils/lsyscache.h"
> + #include "utils/resowner.h"
> +
> ++#ifdef USE_REPLICATION
> ++#include "replicate.h"
> ++#endif /* USE_REPLICATION */
> ++
> +
> + /*
> + * All accesses to pg_largeobject and its index make use of a single
> Relation
> +@@ -39,7 +43,6 @@
> + static Relation lo_heap_r = NULL;
> + static Relation lo_index_r = NULL;
> +
> +-
> + /*
> + * Open pg_largeobject and its index, if not already done in current xact
> + */
> +@@ -180,6 +183,9 @@
> + * use. We can use the index on pg_largeobject for checking OID
> + * uniqueness, even though it has additional columns besides OID.
> + */
> ++#ifdef USE_REPLICATION
> ++ PGR_Is_Sync_OID = true;
> ++#endif /* USE_REPLICATION */
> + if (!OidIsValid(lobjId))
> + {
> + open_lo_relation();
> +@@ -198,6 +204,9 @@
> + */
> + CommandCounterIncrement();
> +
> ++#ifdef USE_REPLICATION
> ++ PGR_Is_Sync_OID = false;
> ++#endif /* USE_REPLICATION */
> + return lobjId;
> + }
> +
> +diff -aruN postgresql-8.1.2/src/backend/storage/lmgr/deadlock.c
> pgcluster-1.5.0rc7/src/backend/storage/lmgr/deadlock.c
> +--- postgresql-8.1.2/src/backend/storage/lmgr/deadlock.c 2005-10-29
> 02:31:51.000000000 +0200
> ++++ pgcluster-1.5.0rc7/src/backend/storage/lmgr/deadlock.c 2006-01-10
> 17:39:39.000000000 +0100
> +@@ -31,6 +31,9 @@
> + #include "storage/proc.h"
> + #include "utils/memutils.h"
> +
> ++#ifdef USE_REPLICATION
> ++#include "replicate.h"
> ++#endif /* USE_REPLICATION */
> +
> + /* One edge in the waits-for graph */
> + typedef struct
> +@@ -226,6 +229,13 @@
> + if (!FindLockCycle(proc, possibleConstraints, &nSoftEdges))
> + elog(FATAL, "deadlock seems to have disappeared");
> +
> ++#ifdef USE_REPLICATION
> ++ if (PGR_Notice_Conflict() == STATUS_ERROR)
> ++ {
> ++ return FALSE;
> ++ }
> ++ PGR_Lock_Noticed =true;
> ++#endif
> + return true; /* cannot find a
> non-deadlocked state */
> + }
> +
> +diff -aruN postgresql-8.1.2/src/backend/storage/lmgr/lmgr.c
> pgcluster-1.5.0rc7/src/backend/storage/lmgr/lmgr.c
> +--- postgresql-8.1.2/src/backend/storage/lmgr/lmgr.c 2005-10-15
> 04:49:26.000000000 +0200
> ++++ pgcluster-1.5.0rc7/src/backend/storage/lmgr/lmgr.c 2006-01-10
> 17:39:39.000000000 +0100
> +@@ -24,6 +24,9 @@
> + #include "storage/procarray.h"
> + #include "utils/inval.h"
> +
> ++#ifdef USE_REPLICATION
> ++#include "replicate.h"
> ++#endif /* USE_REPLICATION */
> +
> + /*
> + * This conflict table defines the semantics of the various lock modes.
> +@@ -466,10 +469,18 @@
> +
> + SET_LOCKTAG_TRANSACTION(tag, xid);
> +
> ++#ifdef USE_REPLICATION
> ++ if (!LockAcquire(LockTableId, &tag, false,
> ++ ExclusiveLock, false,false))
> ++ elog(ERROR, "XactLockTableWait: LockAcquire failed");
> ++
> ++ LockRelease(LockTableId, &tag, ExclusiveLock,false);
> ++#else
> + (void) LockAcquire(LockTableId, &tag, false,
> + ShareLock, false, false);
> +
> + LockRelease(LockTableId, &tag, ShareLock, false);
> ++#endif /* USE_REPLICATION */
> +
> + if (!TransactionIdIsInProgress(xid))
> + break;
> +@@ -605,3 +616,38 @@
> +
> + LockRelease(LockTableId, &tag, lockmode, false);
> + }
> ++
> ++#ifdef USE_REPLICATION
> ++/*
> ++ * XactLockTableWait
> ++ *
> ++ * Wait for the specified transaction to commit or abort.
> ++ */
> ++void
> ++XactLockTableWaitForCluster(TransactionId xid,Buffer buffer)
> ++{
> ++ LOCKTAG tag;
> ++ TransactionId myxid = GetCurrentTransactionId();
> ++
> ++ Assert(!TransactionIdEquals( xid, myxid ));
> ++
> ++ LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
> ++
> ++ SET_LOCKTAG_TRANSACTION(tag, xid);
> ++
> ++ if (!LockAcquire(LockTableId, &tag, false,
> ++ ExclusiveLock, false,false))
> ++ elog(ERROR, "XactLockTableWait: LockAcquire failed");
> ++
> ++ LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
> ++
> ++ LockRelease(LockTableId, &tag, ExclusiveLock,false);
> ++
> ++ /*
> ++ * Transaction was committed/aborted/crashed - we have to update
> ++ * pg_clog if transaction is still marked as running.
> ++ */
> ++ if (!TransactionIdDidCommit(xid) && !TransactionIdDidAbort(xid))
> ++ TransactionIdAbort(xid);
> ++}
> ++#endif /*USE_REPLICATION*/
> +diff -aruN postgresql-8.1.2/src/backend/storage/lmgr/lock.c
> pgcluster-1.5.0rc7/src/backend/storage/lmgr/lock.c
> +--- postgresql-8.1.2/src/backend/storage/lmgr/lock.c 2005-11-22
> 19:23:18.000000000 +0100
> ++++ pgcluster-1.5.0rc7/src/backend/storage/lmgr/lock.c 2006-01-10
> 17:39:39.000000000 +0100
> +@@ -42,6 +42,10 @@
> + #include "utils/ps_status.h"
> + #include "utils/resowner.h"
> +
> ++#ifdef USE_REPLICATION
> ++#include "storage/lmgr.h"
> ++#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 */
> +@@ -697,6 +701,10 @@
> + status = LockCheckConflicts(lockMethodTable, lockmode,
> + lock,
> proclock, MyProc);
> +
> ++#ifdef USE_REPLICATION
> ++ PGR_Check_Lock.status_lock_conflict = status;
> ++ PGR_Check_Lock.deadlock = false;
> ++#endif /* USE_REPLICATION */
> + if (status == STATUS_OK)
> + {
> + /* No conflict with held or previously requested locks */
> +@@ -706,6 +714,17 @@
> + else
> + {
> + Assert(status == STATUS_FOUND);
> ++#ifdef USE_REPLICATION
> ++ if ((PGR_Need_Notice == true) &&
> ++ (PGR_Check_Lock.check_lock_conflict == true))
> ++ {
> ++ if (!PGR_Lock_Noticed && PGR_Notice_Conflict() ==
> STATUS_ERROR)
> ++ {
> ++ return FALSE;
> ++ }
> ++ PGR_Lock_Noticed = true;
> ++ }
> ++#endif /* USE_REPLICATION */
> +
> + /*
> + * We can't acquire the lock immediately. If caller
> specified no
> +diff -aruN postgresql-8.1.2/src/backend/storage/lmgr/proc.c
> pgcluster-1.5.0rc7/src/backend/storage/lmgr/proc.c
> +--- postgresql-8.1.2/src/backend/storage/lmgr/proc.c 2005-11-22
> 19:23:19.000000000 +0100
> ++++ pgcluster-1.5.0rc7/src/backend/storage/lmgr/proc.c 2006-01-10
> 17:39:39.000000000 +0100
> +@@ -44,6 +44,9 @@
> + #include "storage/procarray.h"
> + #include "storage/spin.h"
> +
> ++#ifdef USE_REPLICATION
> ++#include "replicate.h"
> ++#endif /* USE_REPLICATION */
> +
> + /* GUC variables */
> + int DeadlockTimeout = 1000;
> +@@ -264,6 +267,9 @@
> + MyProc->lwWaitLink = NULL;
> + MyProc->waitLock = NULL;
> + MyProc->waitProcLock = NULL;
> ++#ifdef USE_REPLICATION
> ++ MyProc->replicationId = 0;
> ++#endif
> + SHMQueueInit(&(MyProc->procLocks));
> +
> + /*
> +@@ -360,6 +366,9 @@
> + MyProc->lwWaitLink = NULL;
> + MyProc->waitLock = NULL;
> + MyProc->waitProcLock = NULL;
> ++#ifdef USE_REPLICATION
> ++ MyProc->replicationId=0;
> ++#endif
> + SHMQueueInit(&(MyProc->procLocks));
> +
> + /*
> +@@ -691,6 +700,17 @@
> + GrantAwaitedLock();
> + return STATUS_OK;
> + }
> ++#ifdef USE_REPLICATION
> ++ if(proc->replicationId == 0 ||
> ++ (MyProc->replicationId >
> proc->replicationId &&
> ++ proc->heldLocks & aheadRequests) ) {
> ++ elog(DEBUG1,"origin's RId = %d ,
> MyProc->RId = %d , skip",proc->replicationId,MyProc->replicationId);
> ++ aheadRequests |= (1 <<
> proc->waitLockMode);
> ++ proc = (PGPROC *)
> MAKE_PTR(proc->links.next);
> ++ continue;
> ++ }
> ++
> ++#endif
> + /* Break out of loop to put myself before him
> */
> + break;
> + }
> +@@ -706,8 +726,21 @@
> + }
> + else
> + {
> ++#ifdef USE_REPLICATION
> ++ proc = (PGPROC *) &(waitQueue->links);
> ++ for (i = 0; i < waitQueue->size+1; i++){
> ++ elog(DEBUG1,"origin's RId = %d , MyProc->RId =
> %d",proc->replicationId,MyProc->replicationId);
> ++ if(proc->replicationId == 0 ||
> ++ MyProc->replicationId > proc->replicationId) {
> ++ proc= (PGPROC *) MAKE_PTR(proc->links.next);
> ++ }else {
> ++ break;
> ++ }
> ++ }
> ++#else
> + /* I hold no locks, so I can't push in front of anyone. */
> + proc = (PGPROC *) &(waitQueue->links);
> ++#endif
> + }
> +
> + /*
> +@@ -988,6 +1021,9 @@
> + * such processes.
> + */
> + LWLockRelease(LockMgrLock);
> ++#ifdef USE_REPLICATION
> ++ PGR_Notice_DeadLock();
> ++#endif
> + }
> +
> +
> +diff -aruN postgresql-8.1.2/src/backend/tcop/postgres.c
> pgcluster-1.5.0rc7/src/backend/tcop/postgres.c
> +--- postgresql-8.1.2/src/backend/tcop/postgres.c 2005-12-14
> 18:06:37.000000000 +0100
> ++++ pgcluster-1.5.0rc7/src/backend/tcop/postgres.c 2006-02-09
> 11:09:21.000000000 +0100
> +@@ -64,6 +64,10 @@
> +
> + #include "pgstat.h"
> +
> ++#ifdef USE_REPLICATION
> ++#include "replicate.h"
> ++#endif /* USE_REPLICATION */
> ++
> + extern int optind;
> + extern char *optarg;
> +
> +@@ -84,6 +88,9 @@
> + /* GUC variable for maximum stack depth (measured in kilobytes) */
> + int max_stack_depth = 2048;
> +
> ++#ifdef USE_REPLICATION
> ++bool PGR_Not_Replication_Query = false;
> ++#endif /* USE_REPLICATION */
> +
> + /* ----------------
> + * private variables
> +@@ -820,6 +827,24 @@
> + char *prepare_string = NULL;
> + bool was_logged = false;
> +
> ++#ifdef USE_REPLICATION
> ++ char * query_ptr = NULL;
> ++ char * null_ptr = NULL;
> ++ int skip_cnt = 0;
> ++ int status = 0;
> ++
> ++ PGR_Reliable_Mode_Wait = false;
> ++ query_ptr = (char *)query_string;
> ++ if (PGR_Is_Replicated_Query == false)
> ++ {
> ++ PGR_Is_Replicated_Query =
> PGR_Is_Replicated_Command(query_ptr);
> ++ }
> ++ PGR_Retry_Query.query_string = (char *)query_string;
> ++ PGR_Retry_Query.query_len = strlen(query_string);
> ++ PGR_Retry_Query.cmdSts = CMD_STS_OTHER;
> ++ PGR_Retry_Query.cmdType = CMD_TYPE_OTHER;
> ++#endif /* USE_REPLICATION */
> ++
> + /*
> + * Report query to various monitoring facilities.
> + */
> +@@ -898,6 +923,13 @@
> + DestReceiver *receiver;
> + int16 format;
> +
> ++#ifdef USE_REPLICATION
> ++ PGR_Not_Replication_Query = false;
> ++ PGR_Reliable_Mode_Wait = false;
> ++ PGR_Retry_Query.useFlag = DATA_INIT;
> ++ PGR_Lock_Noticed = false;
> ++#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
> +@@ -905,7 +937,6 @@
> + * destination.
> + */
> + commandTag = CreateCommandTag(parsetree);
> +-
> + set_ps_display(commandTag);
> +
> + BeginCommand(commandTag, dest);
> +@@ -920,10 +951,192 @@
> + */
> + if (IsAbortedTransactionBlockState() &&
> + !IsTransactionExitStmt(parsetree))
> ++ {
> ++#ifdef USE_REPLICATION
> ++ Transaction_Mode = 0;
> ++#endif
> + ereport(ERROR,
> +
> (errcode(ERRCODE_IN_FAILED_SQL_TRANSACTION),
> + errmsg("current transaction is
> aborted, "
> + "commands ignored until end
> of transaction block")));
> ++ }
> ++#ifdef USE_REPLICATION
> ++ Query_String = NULL;
> ++ query_ptr = PGR_Remove_Comment(query_ptr);
> ++ PGR_Check_Lock.dest = TO_FRONTEND;
> ++ PGR_Need_Notice = false;
> ++ PGR_Check_Lock.check_lock_conflict = false;
> ++ if (!xact_started)
> ++ {
> ++ start_xact_command();
> ++ xact_started = true;
> ++ }
> ++ if (skip_cnt == 0)
> ++ {
> ++ skip_cnt = PGR_Is_Skip_Replication(query_ptr);
> ++ }
> ++ null_ptr = PGR_scan_terminate (query_ptr);
> ++ if(null_ptr != NULL)
> ++ {
> ++ *null_ptr = '\0';
> ++ }
> ++ Transaction_Mode =
> PGR_Set_Transaction_Mode(Transaction_Mode,commandTag);
> ++ if ((PGR_Is_Replicated_Query ) ||
> ++ (skip_cnt != 0))
> ++ {
> ++ if (skip_cnt > 0)
> ++ {
> ++ skip_cnt --;
> ++ }
> ++ else
> ++ {
> ++ skip_cnt = 0;
> ++ }
> ++ PGR_Copy_Data_Need_Replicate = false;
> ++ if (!strncmp(commandTag,"SELECT",strlen("SELECT")))
> ++ {
> ++ if (PGR_Is_System_Command(query_ptr))
> ++ {
> ++ status =
> PGR_Call_System_Command(query_ptr);
> ++ if (status == STATUS_SKIP_QUERY)
> ++ {
> ++
> EndCommand(PGR_ALREADY_REPLICATED_NOTICE_CMD,dest);
> ++ break;
> ++ }
> ++ else
> ++ {
> ++
> EndCommand("SYSTEM_COMMAND",dest);
> ++ continue;
> ++ }
> ++ }
> ++ }
> ++ PGR_Check_Lock.status_lock_conflict = STATUS_OK;
> ++ PGR_Check_Lock.dest = TO_FRONTEND;
> ++ }
> ++ else
> ++ {
> ++ PGR_Copy_Data_Need_Replicate = false;
> ++
> ++ /* check cluster db status */
> ++ if ((PGR_Get_Cluster_Status() == STATUS_RECOVERY)
> &&
> ++ (PGR_Not_Replication_Query == false)
> &&
> ++ (Transaction_Mode == 0 ) )
> ++ {
> ++ elog(WARNING, "This query is not permitted
> while recovery db ");
> ++ if(null_ptr != NULL)
> ++ {
> ++ *null_ptr = ';';
> ++ query_ptr = null_ptr +1;
> ++ }
> ++ continue;
> ++ }
> ++ if (PGR_Is_Stand_Alone() == true)
> ++ {
> ++ if (PGR_Stand_Alone->permit ==
> PERMIT_READ_ONLY)
> ++ {
> ++ if (!strcmp(commandTag, "SHOW")) {
> ++ VariableShowStmt *stmt =
> (VariableShowStmt *)parsetree;
> ++ if (!strcmp(stmt->name,
> "replication_server")) {
> ++
> PGR_Not_Replication_Query = true;
> ++ }
> ++ }
> ++
> ++ if (PGR_Not_Replication_Query ==
> false)
> ++ elog(ERROR, "This query is
> not permitted when all replication servers fell down ");
> ++ }
> ++ }
> ++ else if ((PGRforceLoadBalance == false) &&
> ++ ((PGR_Not_Replication_Query == false
> ) ||
> ++ (!strcmp(commandTag,"SELECT"))))
> ++ {
> ++ status =
> PGR_replication(query_ptr,dest,parsetree,commandTag);
> ++ if (status == STATUS_REPLICATED)
> ++ {
> ++ if (xact_started)
> ++ {
> ++ finish_xact_command();
> ++ xact_started = false;
> ++ }
> ++ CommandCounterIncrement();
> ++ continue;
> ++ }
> ++ else if (status == STATUS_ERROR)
> ++ {
> ++ if (!strcmp(commandTag, "SHOW")) {
> ++ VariableShowStmt *stmt =
> (VariableShowStmt *)parsetree;
> ++ if (!strcmp(stmt->name,
> "replication_server")) {
> ++
> PGR_Not_Replication_Query = true;
> ++ }
> ++ }
> ++ else if (PGR_Stand_Alone->permit ==
> PERMIT_READ_ONLY)
> ++ {
> ++ elog(ERROR, "This query is
> not permitted when all replication servers fell down ");
> ++ }
> ++ }
> ++ else if (status == STATUS_DEADLOCK_DETECT)
> ++ {
> ++ PGR_Need_Notice = false;
> ++ elog(ERROR, "postmaster deadlock
> detected");
> ++ continue;
> ++ }
> ++ else if (status == STATUS_REPLICATION_ABORT)
> ++ {
> ++ PGR_Need_Notice = false;
> ++ elog(ERROR, "replication server
> should be down, transaction aborted.");
> ++ continue;
> ++ }
> ++ else if (status != STATUS_CONTINUE)
> ++ {
> ++ PGR_Check_Lock.dest = TO_FRONTEND;
> ++ }
> ++ else
> ++ {
> ++ PGR_Check_Lock.dest =
> TO_REPLICATION_SERVER;
> ++ PGR_Reliable_Mode_Wait = true;
> ++ }
> ++ }
> ++ }
> ++ if(null_ptr != NULL)
> ++ {
> ++ *null_ptr = ';';
> ++ query_ptr = null_ptr +1;
> ++ }
> ++ if (!PGR_Is_Replicated_Query )
> ++ {
> ++ if ((!strcmp(commandTag,"BEGIN")) ||
> ++ (!strcmp(commandTag, "START TRANSACTION")) ||
> ++ (Transaction_Mode == 0 ) )
> ++ {
> ++ PGR_Reload_Start_Time();
> ++ }
> ++ }
> ++ if (((IsA(parsetree, TransactionStmt)) ||
> ++ (Transaction_Mode > 0) ||
> ++ (Create_Temp_Table_Mode == true) ||
> ++ (Session_Authorization_Mode == true)) ||
> ++ (!strcmp(commandTag,"COPY")))
> ++ {
> ++ PGR_Need_Notice = true;
> ++ PGR_Check_Lock.check_lock_conflict = true;
> ++ }
> ++ else
> ++ {
> ++ if (PGR_Not_Replication_Query == false)
> ++ {
> ++ PGR_Need_Notice = true;
> ++ PGR_Check_Lock.check_lock_conflict = true;
> ++ }
> ++ else
> ++ {
> ++ if ((PGR_Is_Replicated_Query ) &&
> ++ (!strncmp(commandTag,
> "SELECT",strlen("SELECT"))))
> ++ {
> ++ PGR_Need_Notice = true;
> ++ PGR_Check_Lock.check_lock_conflict =
> true;
> ++ }
> ++ }
> ++ }
> ++#endif /* USE_REPLICATION */
> +
> + /* Make sure we are in a transaction command */
> + start_xact_command();
> +@@ -1046,7 +1259,42 @@
> + * command the client sent, regardless of rewriting. (But a
> command
> + * aborted by error will not send an EndCommand report at
> all.)
> + */
> ++#ifdef USE_REPLICATION
> ++ /*
> ++ * In Non-CONTROL LOCK CONFLICT mode, we *MUST NOT* send
> command tag twice.
> ++ * So , if it was already sent for lock notification , we
> didn't send
> ++ * tag here. also ReadyForQuery,too.
> ++ */
> ++ if(!(PGR_Is_Replicated_Query && PGR_Lock_Noticed))
> ++#endif
> + EndCommand(completionTag, dest);
> ++#ifdef USE_REPLICATION
> ++ if(PGR_Is_Replicated_Query &&
> ++ needToUpdateReplicateIdOnNextQueryIsDone) {
> ++ ++(ReplicationLog_Info.PGR_Replicate_ID);
> ++
> ++ if (CurrentReplicateServer != NULL)
> ++ {
> ++ /* set replicate id in this system */
> ++ ++(CurrentReplicateServer->replicate_id);
> ++ }
> ++ elog(DEBUG1,"increased replicate_id to
> %d",CurrentReplicateServer->replicate_id);
> ++ needToUpdateReplicateIdOnNextQueryIsDone=false;
> ++ }
> ++
> ++ if ((PGR_Need_Notice == true) &&
> ++ (PGRforceLoadBalance == false))
> ++ {
> ++ PGR_Notice_Transaction_Query_Done();
> ++ }
> ++ if (ReplicateCurrentTime != NULL)
> ++ {
> ++ if (Transaction_Mode == 0)
> ++ {
> ++ ReplicateCurrentTime->use_seed = 1;
> ++ }
> ++ }
> ++#endif
> + } /* end loop
> over parsetrees */
> +
> + /*
> +@@ -1234,11 +1482,15 @@
> + */
> + if (IsAbortedTransactionBlockState() &&
> + !IsTransactionExitStmt(parsetree))
> ++ {
> ++#ifdef USE_REPLICATION
> ++ Transaction_Mode = 0;
> ++#endif
> + 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
> complete,
> +@@ -1432,11 +1684,15 @@
> + if (IsAbortedTransactionBlockState() &&
> + (!IsTransactionExitStmtList(pstmt->query_list) ||
> + numParams != 0))
> ++ {
> ++#ifdef USE_REPLICATION
> ++ Transaction_Mode = 0;
> ++#endif
> + ereport(ERROR,
> + (errcode(ERRCODE_IN_FAILED_SQL_TRANSACTION),
> + errmsg("current transaction is aborted, "
> + "commands ignored until end
> of transaction block")));
> +-
> ++ }
> + /*
> + * Create the portal. Allow silent replacement of an existing portal
> only
> + * if the unnamed portal is specified.
> +@@ -1737,11 +1993,15 @@
> + */
> + if (IsAbortedTransactionBlockState() &&
> + !IsTransactionExitStmtList(portal->parseTrees))
> ++ {
> ++#ifdef USE_REPLICATION
> ++ Transaction_Mode = 0;
> ++#endif
> + 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();
> +
> +@@ -1882,11 +2142,15 @@
> + */
> + if (IsAbortedTransactionBlockState() &&
> + PreparedStatementReturnsTuples(pstmt))
> ++ {
> ++#ifdef USE_REPLICATION
> ++ Transaction_Mode = 0;
> ++#endif
> + ereport(ERROR,
> + (errcode(ERRCODE_IN_FAILED_SQL_TRANSACTION),
> + errmsg("current transaction is aborted, "
> + "commands ignored until end
> of transaction block")));
> +-
> ++ }
> + if (whereToSendOutput != DestRemote)
> + return; /* can't actually do
> anything... */
> +
> +@@ -1952,11 +2216,15 @@
> + */
> + if (IsAbortedTransactionBlockState() &&
> + portal->tupDesc)
> ++ {
> ++#ifdef USE_REPLICATION
> ++ Transaction_Mode = 0;
> ++#endif
> + ereport(ERROR,
> + (errcode(ERRCODE_IN_FAILED_SQL_TRANSACTION),
> + errmsg("current transaction is aborted, "
> + "commands ignored until end
> of transaction block")));
> +-
> ++ }
> + if (whereToSendOutput != DestRemote)
> + return; /* can't actually do
> anything... */
> +
> +@@ -2112,6 +2380,9 @@
> + * 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);
> + }
> +
> +@@ -2149,6 +2420,9 @@
> + }
> + }
> +
> ++#ifdef USE_REPLICATION
> ++ PGR_delete_shm();
> ++#endif /* USE_REPLICATION */
> + errno = save_errno;
> + }
> +
> +@@ -2163,6 +2437,9 @@
> + void
> + authdie(SIGNAL_ARGS)
> + {
> ++#ifdef USE_REPLICATION
> ++ PGR_delete_shm();
> ++#endif /* USE_REPLICATION */
> + exit(0);
> + }
> +
> +@@ -3165,6 +3442,14 @@
> + pgstat_report_activity("<IDLE>");
> + }
> +
> ++#ifdef USE_REPLICATION
> ++ /*
> ++ * In Non-CONTROL LOCK CONFLICT mode, we *MUST NOT*
> send command tag twice.
> ++ * So , if it was already sent for lock notification
> , we didn't send
> ++ * tag here. also ReadyForQuery,too.
> ++ */
> ++ if(!(PGR_Is_Replicated_Query && PGR_Lock_Noticed))
> ++#endif
> + ReadyForQuery(whereToSendOutput);
> + send_rfq = false;
> + }
> +@@ -3204,7 +3489,25 @@
> + */
> + if (ignore_till_sync && firstchar != EOF)
> + continue;
> +-
> ++#ifdef USE_REPLICATION
> ++ if ((firstchar == CMD_TYPE_P_PARSE) ||
> ++ (firstchar == CMD_TYPE_P_BIND) ||
> ++ (firstchar == CMD_TYPE_P_DESCRIBE) ||
> ++ (firstchar == CMD_TYPE_P_EXECUTE) ||
> ++ (firstchar == CMD_TYPE_P_SYNC) ||
> ++ (firstchar == CMD_TYPE_P_CLOSE))
> ++ {
> ++ if (PGR_Send_Input_Message(firstchar, &input_message)
> != STATUS_OK)
> ++ {
> ++ if ((PGR_Is_Stand_Alone() == true) &&
> ++ (PGR_Stand_Alone->permit ==
> PERMIT_READ_ONLY))
> ++ {
> ++ elog(WARNING, "This query is not
> permitted when all replication servers fell down ");
> ++ break;
> ++ }
> ++ }
> ++ }
> ++#endif /* USE_REPLICATION */
> + switch (firstchar)
> + {
> + case 'Q': /* simple query */
> +@@ -3213,9 +3516,7 @@
> +
> + query_string =
> pq_getmsgstring(&input_message);
> + pq_getmsgend(&input_message);
> +-
> + exec_simple_query(query_string);
> +-
> + send_rfq = true;
> + }
> + break;
> +@@ -3239,7 +3540,6 @@
> + paramTypes[i] =
> pq_getmsgint(&input_message, 4);
> + }
> + pq_getmsgend(&input_message);
> +-
> + exec_parse_message(query_string,
> stmt_name,
> +
> paramTypes, numParams);
> + }
> +@@ -3262,7 +3562,6 @@
> + portal_name =
> pq_getmsgstring(&input_message);
> + max_rows =
> pq_getmsgint(&input_message, 4);
> + pq_getmsgend(&input_message);
> +-
> + exec_execute_message(portal_name,
> max_rows);
> + }
> + break;
> +@@ -3356,7 +3655,6 @@
> + describe_type =
> pq_getmsgbyte(&input_message);
> + describe_target =
> pq_getmsgstring(&input_message);
> + pq_getmsgend(&input_message);
> +-
> + switch (describe_type)
> + {
> + case 'S':
> +@@ -3395,6 +3693,27 @@
> + case 'X':
> + case EOF:
> +
> ++#ifdef USE_REPLICATION
> ++ if (PGRforceLoadBalance == false)
> ++ {
> ++ if (PGR_Is_Replicated_Query == false)
> ++ {
> ++ PGR_Noticed_Abort = 1;
> ++
> PGRsend_system_command(CMD_STS_TRANSACTION_ABORT, CMD_TYPE_FRONTEND_CLOSED);
> ++ }
> ++ else if ((Transaction_Mode == 1) &&
> (PGR_Noticed_Abort == 0))
> ++ {
> ++ if
> (PGR_Did_Commit_Transaction() == true)
> ++ {
> ++
> pgstat_report_activity("commit");
> ++
> exec_simple_query("commit");
> ++ }
> ++ }
> ++ }
> ++ /*
> ++ PGR_Notice_Transaction_Query_Aborted();
> ++ */
> ++#endif /* USE_REPLICATION */
> + /*
> + * Reset whereToSendOutput to prevent ereport
> from attempting
> + * to send any more messages to client.
> +diff -aruN postgresql-8.1.2/src/backend/tcop/pquery.c
> pgcluster-1.5.0rc7/src/backend/tcop/pquery.c
> +--- postgresql-8.1.2/src/backend/tcop/pquery.c 2005-11-22
> 19:23:20.000000000 +0100
> ++++ pgcluster-1.5.0rc7/src/backend/tcop/pquery.c 2006-01-23
> 04:56:04.000000000 +0100
> +@@ -25,6 +25,9 @@
> + #include "utils/guc.h"
> + #include "utils/memutils.h"
> +
> ++#ifdef USE_REPLICATION
> ++#include "replicate.h"
> ++#endif /* USE_REPLICATION */
> +
> + /*
> + * ActivePortal is the currently executing Portal (the most closely
> nested,
> +@@ -143,6 +146,18 @@
> + */
> + dest = None_Receiver;
> + }
> ++#ifdef USE_REPLICATION
> ++ if (PGR_Is_Replicated_Query == true )
> ++ {
> ++ /*
> ++ * Replicated *SELECT* query is used to replicate
> ++ * ONLY lock and function execution , results . All of
> ++ * them will be discarded by pgrp processes.
> ++ * So , we don't need to send it.
> ++ */
> ++ dest = None_Receiver;
> ++ }
> ++#endif /*USE_REPLICATION */
> + }
> +
> + /*
> +diff -aruN postgresql-8.1.2/src/backend/tcop/utility.c
> pgcluster-1.5.0rc7/src/backend/tcop/utility.c
> +--- postgresql-8.1.2/src/backend/tcop/utility.c 2005-10-15
> 04:49:27.000000000 +0200
> ++++ pgcluster-1.5.0rc7/src/backend/tcop/utility.c 2006-01-23
> 22:51:52.000000000 +0100
> +@@ -57,6 +57,9 @@
> + #include "utils/lsyscache.h"
> + #include "utils/syscache.h"
> +
> ++#ifdef USE_REPLICATION
> ++#include "replicate.h"
> ++#endif /* USE_REPLICATION */
> +
> + /*
> + * Error-checking support for DROP commands
> +@@ -1198,29 +1201,48 @@
> +
> + case T_SelectStmt:
> + tag = "SELECT";
> ++#ifdef USE_REPLICATION
> ++ PGR_Not_Replication_Query = true;
> ++#endif /* USE_REPLICATION */
> + break;
> +
> + case T_TransactionStmt:
> + {
> + TransactionStmt *stmt = (TransactionStmt *)
> parsetree;
> +
> ++#ifdef USE_REPLICATION
> ++ bool isInTransaction=IsTransactionBlock();
> ++#endif /* USE_REPLICATION */
> ++
> + switch (stmt->kind)
> + {
> + case TRANS_STMT_BEGIN:
> + tag = "BEGIN";
> ++#ifdef USE_REPLICATION
> ++
> PGR_Not_Replication_Query=isInTransaction;
> ++#endif /* USE_REPLICATION */
> + break;
> +
> + case TRANS_STMT_START:
> + tag = "START TRANSACTION";
> ++#ifdef USE_REPLICATION
> ++
> PGR_Not_Replication_Query=isInTransaction;
> ++#endif /* USE_REPLICATION */
> + break;
> +
> + case TRANS_STMT_COMMIT:
> + tag = "COMMIT";
> ++#ifdef USE_REPLICATION
> ++
> PGR_Not_Replication_Query=!isInTransaction;
> ++#endif /* USE_REPLICATION */
> + break;
> +
> + case TRANS_STMT_ROLLBACK:
> + case TRANS_STMT_ROLLBACK_TO:
> + tag = "ROLLBACK";
> ++#ifdef USE_REPLICATION
> ++
> PGR_Not_Replication_Query=!isInTransaction;
> ++#endif /* USE_REPLICATION */
> + break;
> +
> + case TRANS_STMT_SAVEPOINT:
> +@@ -1252,10 +1274,16 @@
> +
> + case T_DeclareCursorStmt:
> + tag = "DECLARE CURSOR";
> ++#ifdef USE_REPLICATION
> ++ PGR_Not_Replication_Query = true;
> ++#endif /* USE_REPLICATION */
> + break;
> +
> + case T_ClosePortalStmt:
> + tag = "CLOSE CURSOR";
> ++#ifdef USE_REPLICATION
> ++ PGR_Not_Replication_Query = true;
> ++#endif /* USE_REPLICATION */
> + break;
> +
> + case T_FetchStmt:
> +@@ -1264,6 +1292,9 @@
> +
> + tag = (stmt->ismove) ? "MOVE" : "FETCH";
> + }
> ++#ifdef USE_REPLICATION
> ++ PGR_Not_Replication_Query = true;
> ++#endif /* USE_REPLICATION */
> + break;
> +
> + case T_CreateDomainStmt:
> +@@ -1581,10 +1612,16 @@
> + tag = "VACUUM";
> + else
> + tag = "ANALYZE";
> ++#ifdef USE_REPLICATION
> ++ PGR_Not_Replication_Query = true;
> ++#endif /* USE_REPLICATION */
> + break;
> +
> + case T_ExplainStmt:
> + tag = "EXPLAIN";
> ++#ifdef USE_REPLICATION
> ++ PGR_Not_Replication_Query = true;
> ++#endif /* USE_REPLICATION */
> + break;
> +
> + case T_VariableSetStmt:
> +@@ -1593,6 +1630,14 @@
> +
> + case T_VariableShowStmt:
> + tag = "SHOW";
> ++#ifdef USE_REPLICATION
> ++ {
> ++ VariableShowStmt *stmt = (VariableShowStmt
> *)parsetree;
> ++ if (strcmp(stmt->name, "replication_server"))
> {
> ++ PGR_Not_Replication_Query = true;
> ++ }
> ++ }
> ++#endif /* USE_REPLICATION */
> + break;
> +
> + case T_VariableResetStmt:
> +@@ -1651,10 +1696,16 @@
> +
> + case T_CheckPointStmt:
> + tag = "CHECKPOINT";
> ++#ifdef USE_REPLICATION
> ++ PGR_Not_Replication_Query = true;
> ++#endif /* USE_REPLICATION */
> + break;
> +
> + case T_ReindexStmt:
> + tag = "REINDEX";
> ++#ifdef USE_REPLICATION
> ++ PGR_Not_Replication_Query = true;
> ++#endif /* USE_REPLICATION */
> + break;
> +
> + case T_CreateConversionStmt:
> +@@ -1696,6 +1747,13 @@
> + break;
> + }
> +
> ++#ifdef USE_REPLICATION
> ++ if(PGRforceLoadBalance == true)
> ++ {
> ++ PGR_Not_Replication_Query = true;
> ++ }
> ++#endif /* USE_REPLICATION */
> ++
> + return tag;
> + }
> +
> +@@ -1729,7 +1787,12 @@
> + tag = "SELECT FOR SHARE";
> + }
> + else
> ++ {
> + tag = "SELECT";
> ++#ifdef USE_REPLICATION
> ++ PGR_Not_Replication_Query = true;
> ++#endif /* USE_REPLICATION */
> ++ }
> + break;
> + case CMD_UPDATE:
> + tag = "UPDATE";
> +@@ -1747,6 +1810,9 @@
> + elog(WARNING, "unrecognized commandType: %d",
> + (int) parsetree->commandType);
> + tag = "???";
> ++#ifdef USE_REPLICATION
> ++ PGR_Not_Replication_Query = true;
> ++#endif /* USE_REPLICATION */
> + break;
> + }
> +
> +diff -aruN postgresql-8.1.2/src/backend/utils/adt/datetime.c
> pgcluster-1.5.0rc7/src/backend/utils/adt/datetime.c
> +--- postgresql-8.1.2/src/backend/utils/adt/datetime.c 2005-12-01
> 18:56:43.000000000 +0100
> ++++ pgcluster-1.5.0rc7/src/backend/utils/adt/datetime.c 2006-01-18
> 23:42:03.000000000 +0100
> +@@ -25,7 +25,6 @@
> + #include "utils/datetime.h"
> + #include "utils/guc.h"
> +
> +-
> + static int DecodeNumber(int flen, char *field, bool haveTextMonth,
> + int fmask, int *tmask,
> + struct pg_tm * tm, fsec_t *fsec, int *is2digits);
> +diff -aruN postgresql-8.1.2/src/backend/utils/adt/float.c
> pgcluster-1.5.0rc7/src/backend/utils/adt/float.c
> +--- postgresql-8.1.2/src/backend/utils/adt/float.c 2005-10-15
> 04:49:28.000000000 +0200
> ++++ pgcluster-1.5.0rc7/src/backend/utils/adt/float.c 2006-01-10
> 17:39:38.000000000 +0100
> +@@ -68,6 +68,9 @@
> + #include "utils/array.h"
> + #include "utils/builtins.h"
> +
> ++#ifdef USE_REPLICATION
> ++#include "replicate.h"
> ++#endif /* USE_REPLICATION */
> +
> + #ifndef M_PI
> + /* from my RH5.2 gcc math.h file - thomas 2000-04-03 */
> +@@ -1834,7 +1837,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 -aruN postgresql-8.1.2/src/backend/utils/adt/nabstime.c
> pgcluster-1.5.0rc7/src/backend/utils/adt/nabstime.c
> +--- postgresql-8.1.2/src/backend/utils/adt/nabstime.c 2005-10-22
> 16:27:29.000000000 +0200
> ++++ pgcluster-1.5.0rc7/src/backend/utils/adt/nabstime.c 2006-01-18
> 23:58:50.000000000 +0100
> +@@ -29,6 +29,10 @@
> + #include "utils/builtins.h"
> + #include "utils/nabstime.h"
> +
> ++#ifdef USE_REPLICATION
> ++#include "replicate.h"
> ++#endif /* USE_REPLICATION */
> ++
> + #define MIN_DAYNUM (-24856) /* December 13, 1901 */
> + #define MAX_DAYNUM 24854 /* January 18, 2038 */
> +
> +@@ -94,7 +98,13 @@
> + {
> + time_t now;
> +
> ++#ifdef USE_REPLICATION
> ++ struct timeval tp;
> ++ PGR_GetTimeOfDay(&tp,NULL);
> ++ now = tp.tv_sec;
> ++#else
> + now = time(NULL);
> ++#endif /* USE_REPLICATION */
> + return (AbsoluteTime) now;
> + }
> +
> +@@ -1033,9 +1043,14 @@
> + {
> + time_t sec;
> +
> ++#ifdef USE_REPLICATION
> ++ struct timeval tp;
> ++ PGR_GetTimeOfDay(&tp,NULL);
> ++ sec = tp.tv_sec;
> ++#else
> + if (time(&sec) < 0)
> + PG_RETURN_ABSOLUTETIME(INVALID_ABSTIME);
> +-
> ++#endif
> + PG_RETURN_ABSOLUTETIME((AbsoluteTime) sec);
> + }
> +
> +@@ -1590,7 +1605,11 @@
> + int len;
> + pg_time_t tt;
> +
> ++#ifdef USE_REPLICATION
> ++ PGR_GetTimeOfDay(&tp,NULL);
> ++#else
> + gettimeofday(&tp, NULL);
> ++#endif /* USE_REPLICATION */
> + tt = (pg_time_t) tp.tv_sec;
> + pg_strftime(templ, sizeof(templ), "%a %b %d %H:%M:%S.%%06d %Y %Z",
> + pg_localtime(&tt, global_timezone));
> +diff -aruN postgresql-8.1.2/src/backend/utils/adt/ri_triggers.c
> pgcluster-1.5.0rc7/src/backend/utils/adt/ri_triggers.c
> +--- postgresql-8.1.2/src/backend/utils/adt/ri_triggers.c 2005-11-22
> 19:23:21.000000000 +0100
> ++++ pgcluster-1.5.0rc7/src/backend/utils/adt/ri_triggers.c 2006-01-10
> 17:39:38.000000000 +0100
> +@@ -45,6 +45,10 @@
> + #include "utils/typcache.h"
> + #include "miscadmin.h"
> +
> ++#ifdef USE_REPLICATION
> ++#include "replicate.h"
> ++extern bool check_constraint_with_lock;
> ++#endif /* USE_REPLICATION */
> +
> + /* ----------
> + * Local definitions
> +@@ -266,8 +270,18 @@
> + * ----------
> + */
> + quoteRelationName(pkrelname, pk_rel);
> ++#ifdef USE_REPLICATION
> ++ if (check_constraint_with_lock)
> ++ snprintf(querystr, sizeof(querystr), "SELECT
> 1 FROM ONLY %s x FOR UPDATE OF x",
> ++ pkrelname);
> ++ else
> ++ snprintf(querystr, sizeof(querystr), "SELECT
> 1 FROM ONLY %s x ",
> ++ pkrelname);
> ++
> ++#else
> + snprintf(querystr, sizeof(querystr), "SELECT 1 FROM
> ONLY %s x FOR SHARE OF x",
> + pkrelname);
> ++#endif /* USE_REPLICATION */
> +
> + /* Prepare and save the plan */
> + qplan = ri_PlanCheck(querystr, 0, NULL,
> +@@ -411,6 +425,9 @@
> + queryoids[i] = SPI_gettypeid(fk_rel->rd_att,
> +
> qkey.keypair[i][RI_KEYPAIR_FK_IDX]);
> + }
> ++#ifdef USE_REPLICATION
> ++ if (check_constraint_with_lock)
> ++#endif /* USE_REPLICATION */
> + strcat(querystr, " FOR SHARE OF x");
> +
> + /* Prepare and save the plan */
> +@@ -572,6 +589,9 @@
> + queryoids[i] = SPI_gettypeid(pk_rel->rd_att,
> +
> qkey.keypair[i][RI_KEYPAIR_PK_IDX]);
> + }
> ++#ifdef USE_REPLICATION
> ++ if (check_constraint_with_lock)
> ++#endif /* USE_REPLICATION */
> + strcat(querystr, " FOR SHARE OF x");
> +
> + /* Prepare and save the plan */
> +@@ -728,6 +748,9 @@
> + queryoids[i] =
> SPI_gettypeid(pk_rel->rd_att,
> +
> qkey.keypair[i][RI_KEYPAIR_PK_IDX]);
> + }
> ++#ifdef USE_REPLICATION
> ++ if (check_constraint_with_lock)
> ++#endif /* USE_REPLICATION */
> + strcat(querystr, " FOR SHARE OF x");
> +
> + /* Prepare and save the plan */
> +@@ -917,6 +940,9 @@
> + queryoids[i] =
> SPI_gettypeid(pk_rel->rd_att,
> +
> qkey.keypair[i][RI_KEYPAIR_PK_IDX]);
> + }
> ++#ifdef USE_REPLICATION
> ++ if (check_constraint_with_lock)
> ++#endif /* USE_REPLICATION */
> + strcat(querystr, " FOR SHARE OF x");
> +
> + /* Prepare and save the plan */
> +@@ -1423,6 +1449,9 @@
> + queryoids[i] =
> SPI_gettypeid(pk_rel->rd_att,
> +
> qkey.keypair[i][RI_KEYPAIR_PK_IDX]);
> + }
> ++#ifdef USE_REPLICATION
> ++ if (check_constraint_with_lock)
> ++#endif /* USE_REPLICATION */
> + strcat(querystr, " FOR SHARE OF x");
> +
> + /* Prepare and save the plan */
> +@@ -1602,6 +1631,9 @@
> + queryoids[i] =
> SPI_gettypeid(pk_rel->rd_att,
> +
> qkey.keypair[i][RI_KEYPAIR_PK_IDX]);
> + }
> ++#ifdef USE_REPLICATION
> ++ if (check_constraint_with_lock)
> ++#endif /* USE_REPLICATION */
> + strcat(querystr, " FOR SHARE OF x");
> +
> + /* Prepare and save the plan */
> +diff -aruN postgresql-8.1.2/src/backend/utils/adt/timestamp.c
> pgcluster-1.5.0rc7/src/backend/utils/adt/timestamp.c
> +--- postgresql-8.1.2/src/backend/utils/adt/timestamp.c 2005-11-22
> 19:23:22.000000000 +0100
> ++++ pgcluster-1.5.0rc7/src/backend/utils/adt/timestamp.c 2006-01-18
> 23:59:10.000000000 +0100
> +@@ -31,6 +31,9 @@
> + #include "utils/builtins.h"
> + #include "utils/datetime.h"
> +
> ++#ifdef USE_REPLICATION
> ++#include "replicate.h"
> ++#endif /* USE_REPLICATION */
> +
> + /*
> + * gcc's -ffast-math switch breaks routines that expect exact results from
> +@@ -937,7 +940,11 @@
> + TimestampTz result;
> + struct timeval tp;
> +
> ++#ifdef USE_REPLICATION
> ++ PGR_GetTimeOfDay(&tp,NULL);
> ++#else
> + gettimeofday(&tp, NULL);
> ++#endif
> +
> + result = (TimestampTz) tp.tv_sec -
> + ((POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * SECS_PER_DAY);
> +diff -aruN postgresql-8.1.2/src/backend/utils/error/assert.c
> pgcluster-1.5.0rc7/src/backend/utils/error/assert.c
> +--- postgresql-8.1.2/src/backend/utils/error/assert.c 2005-10-15
> 04:49:32.000000000 +0200
> ++++ pgcluster-1.5.0rc7/src/backend/utils/error/assert.c 2006-01-10
> 17:39:34.000000000 +0100
> +@@ -19,6 +19,10 @@
> +
> + #include <unistd.h>
> +
> ++#ifdef USE_REPLICATION
> ++#include "replicate.h"
> ++#endif /* USE_REPLICATION */
> ++
> + /*
> + * ExceptionalCondition - Handles the failure of an Assert()
> + */
> +@@ -39,6 +43,18 @@
> + fileName, lineNumber);
> + }
> +
> ++#ifdef USE_REPLICATION
> ++ if ((PGR_Check_Lock.dest == TO_REPLICATION_SERVER ) &&
> ++ (PGR_Need_Notice == true))
> ++ {
> ++ PGR_Notice_Transaction_Query_Aborted();
> ++ }
> ++ if (PGR_Copy_Data_Need_Replicate)
> ++ {
> ++ PGR_Set_Copy_Data(PGRCopyData,NULL,0,1);
> ++ }
> ++#endif /* USE_REPLICATION */
> ++
> + #ifdef SLEEP_ON_ASSERT
> +
> + /*
> +diff -aruN postgresql-8.1.2/src/backend/utils/error/elog.c
> pgcluster-1.5.0rc7/src/backend/utils/error/elog.c
> +--- postgresql-8.1.2/src/backend/utils/error/elog.c 2005-11-22
> 19:23:23.000000000 +0100
> ++++ pgcluster-1.5.0rc7/src/backend/utils/error/elog.c 2006-01-10
> 17:39:34.000000000 +0100
> +@@ -69,6 +69,9 @@
> + #include "utils/guc.h"
> + #include "utils/ps_status.h"
> +
> ++#ifdef USE_REPLICATION
> ++#include "replicate.h"
> ++#endif /* USE_REPLICATION */
> +
> + /* Global variables */
> + ErrorContextCallback *error_context_stack = NULL;
> +@@ -313,6 +316,16 @@
> + MemoryContext oldcontext;
> + ErrorContextCallback *econtext;
> +
> ++#ifdef USE_REPLICATION
> ++ int status = 0;
> ++ bool parse_error_flag = false;
> ++
> ++ if ((edata->message) && (strstr(edata->message,"parse error") !=
> NULL))
> ++ {
> ++ parse_error_flag = true;
> ++ }
> ++#endif /* USE_REPLICATION */
> ++
> + recursion_depth++;
> + CHECK_STACK_DEPTH();
> +
> +@@ -362,6 +375,24 @@
> + * handler should reset it to something else soon.
> + */
> +
> ++#ifdef USE_REPLICATION
> ++ if (parse_error_flag)
> ++ {
> ++ if ((PGR_Check_Lock.dest != TO_FRONTEND) &&
> ++ (Transaction_Mode > 0))
> ++ {
> ++ PGR_Force_Replicate_Query();
> ++ }
> ++ }
> ++ if (PGR_Copy_Data_Need_Replicate)
> ++ {
> ++ PGR_Set_Copy_Data(PGRCopyData,NULL,0,1);
> ++ }
> ++ else if (PGR_Need_Notice == true)
> ++ {
> ++ PGR_Notice_Transaction_Query_Done();
> ++ }
> ++#endif /* USE_REPLICATION */
> + recursion_depth--;
> + PG_RE_THROW();
> + }
> +@@ -376,7 +407,16 @@
> + * client_min_messages above FATAL, so don't look at output_to_client.
> + */
> + if (elevel >= FATAL && whereToSendOutput == DestRemote)
> ++ {
> ++#ifdef USE_REPLICATION
> ++ if (PGR_Copy_Data_Need_Replicate)
> ++ {
> ++ PGR_Set_Copy_Data(PGRCopyData,NULL,0,1);
> ++ }
> ++#endif /* USE_REPLICATION */
> + pq_endcopyout(true);
> ++ }
> ++
> +
> + /* Emit the message to the right places */
> + EmitErrorReport();
> +@@ -416,6 +456,34 @@
> + if (PG_exception_stack == NULL && whereToSendOutput ==
> DestRemote)
> + whereToSendOutput = DestNone;
> +
> ++#ifdef USE_REPLICATION
> ++ if (CurrentReplicateServer != NULL)
> ++ {
> ++ if (PGR_Need_Notice == true)
> ++ {
> ++ PGR_Notice_Transaction_Query_Aborted();
> ++ }
> ++ if (PGR_Copy_Data_Need_Replicate)
> ++ {
> ++ PGR_Set_Copy_Data(PGRCopyData,NULL,0,1);
> ++ }
> ++ else
> ++ {
> ++ if ((!PGR_Is_Replicated_Query ) &&
> ++ (PGR_Check_Lock.dest != TO_FRONTEND)
> &&
> ++ (PGR_Reliable_Mode_Wait == true) &&
> ++
> (CurrentReplicateServer->response_mode == PGR_RELIABLE_MODE))
> ++ {
> ++ status = PGR_Recv_Trigger(0);
> ++ }
> ++ }
> ++ }
> ++ if (TransactionSock != -1)
> ++ {
> ++ close (TransactionSock);
> ++ TransactionSock = -1;
> ++ }
> ++#endif /* USE_REPLICATION */
> + /*
> + * fflush here is just to improve the odds that we get to see
> the
> + * error message, in case things are so hosed that proc_exit
> crashes.
> +@@ -437,6 +505,34 @@
> +
> + if (elevel >= PANIC)
> + {
> ++#ifdef USE_REPLICATION
> ++ if (CurrentReplicateServer != NULL)
> ++ {
> ++ if (PGR_Need_Notice == true)
> ++ {
> ++ PGR_Notice_Transaction_Query_Aborted();
> ++ }
> ++ if (PGR_Copy_Data_Need_Replicate)
> ++ {
> ++ PGR_Set_Copy_Data(PGRCopyData,NULL,0,1);
> ++ }
> ++ else
> ++ {
> ++ if ((!PGR_Is_Replicated_Query ) &&
> ++ (PGR_Check_Lock.dest != TO_FRONTEND)
> &&
> ++ (PGR_Reliable_Mode_Wait == true) &&
> ++
> (CurrentReplicateServer->response_mode == PGR_RELIABLE_MODE))
> ++ {
> ++ status =
> PGR_Recv_Trigger(PGR_RECV_TIMEOUT);
> ++ }
> ++ }
> ++ }
> ++ if (TransactionSock != -1)
> ++ {
> ++ close (TransactionSock);
> ++ TransactionSock = -1;
> ++ }
> ++#endif /* USE_REPLICATION */
> + /*
> + * Serious crash time. Postmaster will observe nonzero
> process exit
> + * status and kill the other backends too.
> +diff -aruN postgresql-8.1.2/src/backend/utils/fmgr/dfmgr.c
> pgcluster-1.5.0rc7/src/backend/utils/fmgr/dfmgr.c
> +--- postgresql-8.1.2/src/backend/utils/fmgr/dfmgr.c 2005-10-15
> 04:49:32.000000000 +0200
> ++++ pgcluster-1.5.0rc7/src/backend/utils/fmgr/dfmgr.c 2006-01-10
> 17:39:34.000000000 +0100
> +@@ -20,6 +20,9 @@
> + #include "dynloader.h"
> + #include "miscadmin.h"
> + #include "utils/dynamic_loader.h"
> ++#ifdef USE_REPLICATION
> ++#include "replicate.h"
> ++#endif /* USE_REPLICATION */
> +
> +
> + /*
> +@@ -82,6 +85,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)
> +@@ -176,6 +182,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 -aruN postgresql-8.1.2/src/backend/utils/mb/mbutils.c
> pgcluster-1.5.0rc7/src/backend/utils/mb/mbutils.c
> +--- postgresql-8.1.2/src/backend/utils/mb/mbutils.c 2005-10-15
> 04:49:33.000000000 +0200
> ++++ pgcluster-1.5.0rc7/src/backend/utils/mb/mbutils.c 2006-01-10
> 17:39:34.000000000 +0100
> +@@ -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
> +@@ -404,6 +407,11 @@
> + dest_encoding;
> + FmgrInfo *flinfo;
> +
> ++#ifdef USE_REPLICATION
> ++ if (PGR_Is_Replicated_Query)
> ++ return src;
> ++#endif /* USE_REPLICATION */
> ++
> + if (len <= 0)
> + return (char *) src;
> +
> +diff -aruN postgresql-8.1.2/src/backend/utils/misc/guc.c
> pgcluster-1.5.0rc7/src/backend/utils/misc/guc.c
> +--- postgresql-8.1.2/src/backend/utils/misc/guc.c 2005-11-22
> 19:23:24.000000000 +0100
> ++++ pgcluster-1.5.0rc7/src/backend/utils/misc/guc.c 2006-01-23
> 04:55:40.000000000 +0100
> +@@ -64,6 +64,14 @@
> + #include "utils/pg_locale.h"
> + #include "pgstat.h"
> +
> ++#ifdef USE_REPLICATION
> ++#include "replicate.h"
> ++#endif /* USE_REPLICATION */
> ++
> ++#ifdef USE_REPLICATION
> ++bool check_constraint_with_lock = false;
> ++bool auto_lock_table = true;
> ++#endif /* USE_REPLICATION */
> +
> + #ifndef PG_KRB_SRVTAB
> + #define PG_KRB_SRVTAB ""
> +@@ -225,6 +233,9 @@
> + char *role_string;
> + char *session_authorization_string;
> +
> ++#ifdef USE_REPLICATION
> ++static void ShowReplicationServerConfig(DestReceiver *dest);
> ++#endif /* USE_REPLICATION */
> +
> + /*
> + * Displayable names for context types (enum GucContext)
> +@@ -947,6 +958,32 @@
> + &pg_krb_caseins_users,
> + false, NULL, NULL
> + },
> ++#ifdef USE_REPLICATION
> ++ {
> ++ {"pgr_force_loadbalance", PGC_USERSET, CLIENT_CONN_STATEMENT,
> ++ gettext_noop("force loadbalance mode"),
> ++ NULL
> ++ },
> ++ &PGRforceLoadBalance,
> ++ false, NULL, NULL
> ++ },
> ++ {
> ++ {"check_constraint_with_lock", PGC_USERSET,
> CLIENT_CONN_STATEMENT,
> ++ gettext_noop("check constrain with lock"),
> ++ NULL
> ++ },
> ++ &check_constraint_with_lock,
> ++ false, NULL, NULL
> ++ },
> ++ {
> ++ {"auto_lock_table", PGC_USERSET, CLIENT_CONN_STATEMENT,
> ++ gettext_noop("auto lock table"),
> ++ NULL
> ++ },
> ++ &auto_lock_table,
> ++ true, NULL, NULL
> ++ },
> ++#endif
> +
> + {
> + {"escape_string_warning", PGC_USERSET,
> COMPAT_OPTIONS_PREVIOUS,
> +@@ -4544,6 +4581,10 @@
> + {
> + if (pg_strcasecmp(name, "all") == 0)
> + ShowAllGUCConfig(dest);
> ++#ifdef USE_REPLICATION
> ++ else if (strcasecmp(name, "replication_server") == 0)
> ++ ShowReplicationServerConfig(dest);
> ++#endif
> + else
> + ShowGUCConfigOption(name, dest);
> + }
> +@@ -5976,5 +6017,72 @@
> + return nbuf;
> + }
> +
> ++#ifdef USE_REPLICATION
> ++/*
> ++ * SHOW REPLICATION SERVER command
> ++ */
> ++static void
> ++ShowReplicationServerConfig(DestReceiver *dest)
> ++{
> ++ TupOutputState *tstate;
> ++ TupleDesc tupdesc;
> ++ char *values[4];
> ++ char buffer[256];
> ++ ReplicateServerInfo *sp;
> ++
> ++ /* need a tuple descriptor representing two TEXT columns */
> ++ tupdesc = CreateTemplateTupleDesc(4, false);
> ++ TupleDescInitEntry(tupdesc, (AttrNumber) 1, "status",
> ++ TEXTOID, -1, 0 );
> ++ TupleDescInitEntry(tupdesc, (AttrNumber) 2, "host_name",
> ++ TEXTOID, -1, 0 );
> ++ TupleDescInitEntry(tupdesc, (AttrNumber) 3, "port_num",
> ++ TEXTOID, -1, 0 );
> ++ TupleDescInitEntry(tupdesc, (AttrNumber) 4, "recovery_port_num",
> ++ TEXTOID, -1, 0 );
> ++
> ++ /* prepare for projection of tuples */
> ++ tstate = begin_tup_output_tupdesc(dest, tupdesc);
> ++
> ++ sp = ReplicateServerData;
> ++ while (sp->useFlag != DATA_END) {
> ++ if (PGR_Check_Replicate_Server_Status(sp) == STATUS_ERROR) {
> ++ PGR_Set_Replication_Server_Status(sp, DATA_ERR);
> ++ }
> ++
> ++ sp++;
> ++ }
> ++
> ++ sp = ReplicateServerData;
> ++ while (sp->useFlag != DATA_END) {
> ++ if (sp->useFlag == DATA_USE) {
> ++ values[0] = "ALIVE";
> ++ } else if (sp->useFlag == DATA_ERR) {
> ++ values[0] = "DEAD";
> ++ } else if (sp->useFlag == DATA_INIT) {
> ++ values[0] = "STANDBY";
> ++ } else {
> ++ values[0] = "UNKNOWN";
> ++ }
> ++
> ++ values[1] = (char *) sp->hostName;
> ++
> ++ snprintf(buffer, sizeof(buffer), "%d", sp->portNumber);
> ++ values[2] = pstrdup(buffer);
> ++
> ++ snprintf(buffer, sizeof(buffer), "%d",
> sp->recoveryPortNumber);
> ++ values[3] = pstrdup(buffer);
> ++
> ++ do_tup_output(tstate, values);
> ++
> ++ pfree(values[2]);
> ++ pfree(values[3]);
> ++
> ++ sp++;
> ++ }
> ++
> ++ end_tup_output(tstate);
> ++}
> ++#endif /* USE_REPLICATION */
> +
> + #include "guc-file.c"
> +diff -aruN postgresql-8.1.2/src/backend/utils/misc/postgresql.conf.sample
> pgcluster-1.5.0rc7/src/backend/utils/misc/postgresql.conf.sample
> +--- postgresql-8.1.2/src/backend/utils/misc/postgresql.conf.sample
> 2005-11-10 15:02:59.000000000 +0100
> ++++ pgcluster-1.5.0rc7/src/backend/utils/misc/postgresql.conf.sample
> 2006-01-10 17:39:38.000000000 +0100
> +@@ -428,3 +428,11 @@
> +
> #---------------------------------------------------------------------------
> +
> + #custom_variable_classes = '' # list of custom variable
> class names
> ++
> ++
> ++#---------------------------------------------------------------------------
> ++# PGCluster
> ++#---------------------------------------------------------------------------
> ++
> ++# auto_lock_table = false
> ++# check_constraint_with_lock = false
> +diff -aruN postgresql-8.1.2/src/bin/initdb/initdb.c
> pgcluster-1.5.0rc7/src/bin/initdb/initdb.c
> +--- postgresql-8.1.2/src/bin/initdb/initdb.c 2005-11-22 19:23:26.000000000
> +0100
> ++++ pgcluster-1.5.0rc7/src/bin/initdb/initdb.c 2006-01-10
> 17:39:49.000000000 +0100
> +@@ -107,6 +107,11 @@
> + static char *info_schema_file;
> + static char *features_file;
> + static char *system_views_file;
> ++#ifdef USE_REPLICATION
> ++static char *cluster_conf_file;
> ++static char *pgreplicate_conf_file;
> ++static char *pglb_conf_file;
> ++#endif /* USE_REPLICATION */
> + static char *effective_user;
> + static bool made_new_pgdata = false;
> + static bool found_existing_pgdata = false;
> +@@ -1284,6 +1289,14 @@
> +
> + free(conflines);
> +
> ++#ifdef USE_REPLICATION
> ++ /* cluster.conf */
> ++ conflines = readfile(cluster_conf_file);
> ++ snprintf(path, sizeof(path), "%s/cluster.conf", pg_data);
> ++ writefile(path, conflines);
> ++ chmod(path, 0600);
> ++ free(conflines);
> ++#endif /* USE_REPLICATION */
> + check_ok();
> + }
> +
> +@@ -2468,6 +2481,11 @@
> + set_input(&info_schema_file, "information_schema.sql");
> + set_input(&features_file, "sql_features.txt");
> + set_input(&system_views_file, "system_views.sql");
> ++#ifdef USE_REPLICATION
> ++ set_input(&cluster_conf_file, "cluster.conf.sample");
> ++ set_input(&pgreplicate_conf_file, "pgreplicate.conf.sample");
> ++ set_input(&pglb_conf_file, "pglb.conf.sample");
> ++#endif /* USE_REPLICATION */
> +
> + set_info_version();
> +
> +@@ -2484,6 +2502,16 @@
> + effective_user, bki_file,
> + desc_file, conf_file,
> + hba_file, ident_file);
> ++#ifdef USE_REPLICATION
> ++ fprintf(stderr,
> ++ "PGCLUSTER_VERSION=%s\n"
> ++
> "CLUSTER_CONF_SAMPLE=%s\nPGREPLICATE_CONF_SAMPLE=%s\n"
> ++ "PGLB_CONF_SAMPLE=%s\n",
> ++ PGCLUSTER_VERSION,
> ++ cluster_conf_file,
> ++ pgreplicate_conf_file,
> ++ pglb_conf_file);
> ++#endif /* USE_REPLICATION */
> + if (show_setting)
> + exit(0);
> + }
> +@@ -2497,6 +2525,11 @@
> + check_input(info_schema_file);
> + check_input(features_file);
> + check_input(system_views_file);
> ++#ifdef USE_REPLICATION
> ++ check_input(cluster_conf_file);
> ++ check_input(pgreplicate_conf_file);
> ++ check_input(pglb_conf_file);
> ++#endif /* USE_REPLICATION */
> +
> + setlocales();
> +
> +diff -aruN postgresql-8.1.2/src/bin/pg_dump/pg_dump.c
> pgcluster-1.5.0rc7/src/bin/pg_dump/pg_dump.c
> +--- postgresql-8.1.2/src/bin/pg_dump/pg_dump.c 2005-11-22
> 19:23:26.000000000 +0100
> ++++ pgcluster-1.5.0rc7/src/bin/pg_dump/pg_dump.c 2006-01-23
> 21:35:54.000000000 +0100
> +@@ -111,6 +111,9 @@
> + /* flag to turn on/off dollar quoting */
> + static int disable_dollar_quoting = 0;
> +
> ++#ifdef USE_REPLICATION
> ++ bool nonReplicate=true;
> ++#endif
> +
> + static void help(const char *progname);
> + static NamespaceInfo *findNamespace(Oid nsoid, Oid objoid);
> +@@ -220,6 +223,9 @@
> + {"column-inserts", no_argument, NULL, 'D'},
> + {"host", required_argument, NULL, 'h'},
> + {"ignore-version", no_argument, NULL, 'i'},
> ++#ifdef USE_REPLICATION
> ++ {"non-replicate", no_argument ,NULL, 'r'},
> ++#endif
> + {"no-reconnect", no_argument, NULL, 'R'},
> + {"oids", no_argument, NULL, 'o'},
> + {"no-owner", no_argument, NULL, 'O'},
> +@@ -280,7 +286,7 @@
> + }
> + }
> +
> +- while ((c = getopt_long(argc, argv,
> "abcCdDE:f:F:h:in:oOp:RsS:t:uU:vWxX:Z:",
> ++ while ((c = getopt_long(argc, argv,
> "abcCdDE:f:F:h:in:oOp:rRsS:t:uU:vWxX:Z:",
> + long_options,
> &optindex)) != -1)
> + {
> + switch (c)
> +@@ -347,6 +353,12 @@
> + pgport = optarg;
> + break;
> +
> ++#ifdef USE_REPLICATION
> ++ case 'r':
> ++ nonReplicate = true;
> ++ break;
> ++#endif
> ++
> + case 'R':
> + /* no-op, still accepted for backwards
> compatibility */
> + break;
> +@@ -514,6 +526,11 @@
> + /*
> + * Start serializable transaction to dump consistent data.
> + */
> ++#ifdef USE_REPLICATION
> ++ if(nonReplicate) {
> ++ do_sql_command(g_conn, "set pgr_force_loadbalance to on");
> ++ }
> ++#endif /* USE_REPLICATION */
> + do_sql_command(g_conn, "BEGIN");
> +
> + do_sql_command(g_conn, "SET TRANSACTION ISOLATION LEVEL
> SERIALIZABLE");
> +@@ -685,6 +702,9 @@
> + printf(_(" -o, --oids include OIDs in dump\n"));
> + printf(_(" -O, --no-owner skip restoration of object
> ownership\n"
> + " in plain text
> format\n"));
> ++#ifdef USE_REPLICATION
> ++ printf(_(" -r, --non-replicate No queries replicate. Available
> only in pgcluster.\n"));
> ++#endif
> + printf(_(" -s, --schema-only dump only the schema, no
> data\n"));
> + printf(_(" -S, --superuser=NAME specify the superuser user name
> to use in\n"
> + " plain text format\n"));
> +diff -aruN postgresql-8.1.2/src/bin/pg_dump/pg_dumpall.c
> pgcluster-1.5.0rc7/src/bin/pg_dump/pg_dumpall.c
> +--- postgresql-8.1.2/src/bin/pg_dump/pg_dumpall.c 2005-10-15
> 04:49:39.000000000 +0200
> ++++ pgcluster-1.5.0rc7/src/bin/pg_dump/pg_dumpall.c 2006-01-10
> 17:39:48.000000000 +0100
> +@@ -99,6 +99,9 @@
> + {"oids", no_argument, NULL, 'o'},
> + {"no-owner", no_argument, NULL, 'O'},
> + {"port", required_argument, NULL, 'p'},
> ++#ifdef USE_REPLICATION
> ++ {"non-replicate", no_argument ,NULL, 'r'},
> ++#endif
> + {"password", no_argument, NULL, 'W'},
> + {"schema-only", no_argument, NULL, 's'},
> + {"superuser", required_argument, NULL, 'S'},
> +@@ -164,7 +167,7 @@
> +
> + pgdumpopts = createPQExpBuffer();
> +
> +- while ((c = getopt_long(argc, argv, "acdDgh:ioOp:sS:U:vWxX:",
> long_options, &optindex)) != -1)
> ++ while ((c = getopt_long(argc, argv, "acdDgh:ioOp:rsS:U:vWxX:",
> long_options, &optindex)) != -1)
> + {
> + switch (c)
> + {
> +@@ -218,6 +221,11 @@
> + #endif
> + break;
> +
> ++#ifdef USE_REPLICATION
> ++ case 'r':
> ++ appendPQExpBuffer(pgdumpopts, " -r");
> ++ break;
> ++#endif /* USE_REPLICATION */
> + case 's':
> + schema_only = true;
> + appendPQExpBuffer(pgdumpopts, " -s");
> +@@ -383,6 +391,9 @@
> + printf(_("\nConnection options:\n"));
> + printf(_(" -h, --host=HOSTNAME database server host or socket
> directory\n"));
> + printf(_(" -p, --port=PORT database server port number\n"));
> ++#ifdef USE_REPLICATION
> ++ printf(_(" -r, --non-replicate No queries replicate. Available
> only in pgcluster.\n"));
> ++#endif /* USE_REPLICATION */
> + printf(_(" -U, --username=NAME connect as specified database
> user\n"));
> + printf(_(" -W, --password force password prompt (should
> happen automatically)\n"));
> +
> +diff -aruN postgresql-8.1.2/src/bin/psql/sql_help.h
> pgcluster-1.5.0rc7/src/bin/psql/sql_help.h
> +--- postgresql-8.1.2/src/bin/psql/sql_help.h 2006-01-06 05:09:44.000000000
> +0100
> ++++ pgcluster-1.5.0rc7/src/bin/psql/sql_help.h 2006-01-10
> 17:39:49.000000000 +0100
> +@@ -3,7 +3,7 @@
> + * *** generated from the DocBook documentation.
> + *
> + * generated by
> +- * /usr/local/bin/perl create_help.pl ../../../doc/src/sgml/ref
> sql_help.h
> ++ * /usr/bin/perl create_help.pl ../../../doc/src/sgml/ref sql_help.h
> + *
> + */
> +
> +diff -aruN postgresql-8.1.2/src/include/catalog/catalog.h
> pgcluster-1.5.0rc7/src/include/catalog/catalog.h
> +--- postgresql-8.1.2/src/include/catalog/catalog.h 2005-10-15
> 04:49:42.000000000 +0200
> ++++ pgcluster-1.5.0rc7/src/include/catalog/catalog.h 2006-01-10
> 17:39:43.000000000 +0100
> +@@ -35,5 +35,4 @@
> + extern Oid GetNewOidWithIndex(Relation relation, Relation indexrel);
> + extern Oid GetNewRelFileNode(Oid reltablespace, bool relisshared,
> + Relation pg_class);
> +-
> + #endif /* CATALOG_H */
> +diff -aruN postgresql-8.1.2/src/include/pg_config.h.in
> pgcluster-1.5.0rc7/src/include/pg_config.h.in
> +--- postgresql-8.1.2/src/include/pg_config.h.in 2005-12-06
> 03:29:26.000000000 +0100
> ++++ pgcluster-1.5.0rc7/src/include/pg_config.h.in 2006-01-10
> 17:39:43.000000000 +0100
> +@@ -676,3 +676,7 @@
> + /* Define to empty if the keyword `volatile' does not work. Warning: valid
> + code using `volatile' can become incorrect without. Disable with care.
> */
> + #undef volatile
> ++
> ++/* PGCluster version */
> ++#undef PGCLUSTER_VERSION
> ++
> +diff -aruN postgresql-8.1.2/src/include/pg_config.h.win32
> pgcluster-1.5.0rc7/src/include/pg_config.h.win32
> +--- postgresql-8.1.2/src/include/pg_config.h.win32 2006-01-05
> 05:02:26.000000000 +0100
> ++++ pgcluster-1.5.0rc7/src/include/pg_config.h.win32 2006-01-10
> 17:39:43.000000000 +0100
> +@@ -5,6 +5,7 @@
> + */
> + #define PG_VERSION "8.1.2"
> + #define PG_VERSION_STR "8.1.2 (win32)"
> ++#define PGCLUSTER_VERSION "1.5.0"
> +
> + #define DEF_PGPORT 5432
> + #define DEF_PGPORT_STR "5432"
> +diff -aruN postgresql-8.1.2/src/include/replicate.h
> pgcluster-1.5.0rc7/src/include/replicate.h
> +--- postgresql-8.1.2/src/include/replicate.h 1970-01-01 01:00:00.000000000
> +0100
> ++++ pgcluster-1.5.0rc7/src/include/replicate.h 2006-01-31
> 13:12:04.000000000 +0100
> +@@ -0,0 +1,198 @@
> ++/*-------------------------------------------------------------------------
> ++ *
> ++ * 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 "lib/stringinfo.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 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 SYS_QUERY_1 "set pgr_force_loadbalance to on"
> ++
> ++#define PGR_SEND_RETRY_CNT (3)
> ++#define PGR_SEND_WAIT_MSEC (150)
> ++#define PGR_RECV_RETRY_CNT (3)
> ++#define PGR_RECV_WAIT_MSEC (150)
> ++#define PGR_SEND_TIMEOUT (5)
> ++#define PGR_RECV_TIMEOUT (5)
> ++#define PGR_LOCK_RETRY_CNT (50)
> ++#define PGR_LOCK_WAIT_MSEC (20)
> ++
> ++#define PGR_1ST_RECOVERY (1)
> ++#define PGR_2ND_RECOVERY (2)
> ++
> ++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
> ++{
> ++ char * query_string;
> ++ int query_len;
> ++ char cmdSts;
> ++ char cmdType;
> ++ char useFlag;
> ++} PGR_Retry_Query_Type;
> ++
> ++
> ++/* replicaition log */
> ++typedef struct {
> ++ uint32_t PGR_Replicate_ID;
> ++ uint32_t PGR_Request_ID;
> ++} PGR_ReplicationLog_Info;
> ++
> ++
> ++extern char * Query_String;
> ++extern int TransactionQuery;
> ++extern int Transaction_Mode;
> ++extern int PGR_Noticed_Abort;
> ++extern bool Session_Authorization_Mode;
> ++extern bool Create_Temp_Table_Mode;
> ++extern int RecoveryPortNumber;
> ++extern char * RsyncPath;
> ++extern char * RsyncOption;
> ++extern bool RsyncCompress;
> ++extern int TransactionSock;
> ++extern ReplicateNow * ReplicateCurrentTime;
> ++extern CopyData * PGRCopyData;
> ++extern bool PGR_Copy_Data_Need_Replicate;
> ++extern PGR_Stand_Alone_Type * PGR_Stand_Alone;
> ++extern PGR_Not_Replicate_Type * PGR_Not_Replicate;
> ++extern int PGR_Not_Replicate_Rec_Num;
> ++extern bool autocommit;
> ++extern bool PGR_Is_Replicated_Query;
> ++extern PGR_Check_Lock_Type PGR_Check_Lock;
> ++extern int PGR_Sock_To_Replication_Server;
> ++extern bool PGR_Need_Notice;
> ++extern bool PGR_Lock_Noticed;
> ++extern ReplicateServerInfo * CurrentReplicateServer;
> ++extern ReplicateServerInfo * LastReplicateServer;
> ++extern char * PGRSelfHostName;
> ++extern int PGR_Pending_Sem_Num;
> ++extern int PGR_Response_Mode;
> ++extern bool PGR_Reliable_Mode_Wait;
> ++extern PGR_Retry_Query_Type PGR_Retry_Query;
> ++extern bool PGRforceLoadBalance;
> ++extern bool needToUpdateReplicateIdOnNextQueryIsDone;
> ++extern PGR_ReplicationLog_Info ReplicationLog_Info;
> ++extern bool PGR_Not_Replication_Query;
> ++extern bool PGR_Is_Sync_OID;
> ++
> ++/* in backend/libpq/replicate.c */
> ++extern int PGR_Init_Replicate_Server_Data(void);
> ++extern int PGR_Set_Replicate_Server_Socket(void);
> ++extern ReplicateServerInfo * PGR_get_replicate_server_info(void);
> ++extern char * PGR_Send_Replicate_Command(char * query_string, int
> query_len, char cmdSts ,char cmdType);
> ++extern bool PGR_Is_Replicated_Command(char * query);
> ++extern int Xlog_Check_Replicate(int operation);
> ++extern int PGR_Replicate_Function_Call(void);
> ++extern void PGR_delete_shm(void);
> ++extern int PGR_replication(char * query_string, CommandDest dest, Node
> *parsetree, const char * commandTag);
> ++extern bool PGR_Is_System_Command(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( char * str);
> ++extern bool PGR_Is_Stand_Alone(void);
> ++extern void PGR_Send_Message_To_Frontend(const char * msg);
> ++extern void PGR_Notice_Transaction_Query_Done(void);
> ++extern void PGR_Notice_Transaction_Query_Aborted(void);
> ++extern int PGRsend_system_command(char cmdSts, char cmdType);
> ++extern int PGR_Notice_Conflict(void);
> ++extern int PGR_Recv_Trigger (int user_timeout);
> ++#if 0
> ++extern bool PGR_Check_DeadLock(LOCKMETHODTABLE *lockMethodTable, LOCKMODE
> lockmode, LOCK *lock, PROCLOCK *holder);
> ++#endif
> ++extern void PGR_Set_Replication_Server_Status( ReplicateServerInfo * sp,
> int status);
> ++extern int PGR_Is_Skip_Replication(char * query);
> ++extern bool PGR_Did_Commit_Transaction(void);
> ++extern int PGR_Set_Transaction_Mode(int mode,const char * commandTag);
> ++extern char * PGR_Remove_Comment(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_Check_Replicate_Server_Status(ReplicateServerInfo * sp);
> ++extern int PGR_lo_import(char * filename);
> ++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 uint32_t PGRget_replication_id(void);
> ++extern Oid PGRGetNewObjectId(Oid last_id);
> ++extern int PGR_Send_Input_Message(char cmdType,StringInfo input_message);
> ++
> ++/* in backend/libpq/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 -aruN postgresql-8.1.2/src/include/replicate_com.h
> pgcluster-1.5.0rc7/src/include/replicate_com.h
> +--- postgresql-8.1.2/src/include/replicate_com.h 1970-01-01
> 01:00:00.000000000 +0100
> ++++ pgcluster-1.5.0rc7/src/include/replicate_com.h 2006-01-29
> 22:45:17.000000000 +0100
> +@@ -0,0 +1,388 @@
> ++/*-------------------------------------------------------------------------
> ++ *
> ++ * 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
> ++
> ++#include "pg_config.h"
> ++
> ++/* 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_CONNECTION_CLOSE 'x'
> ++#define CMD_TYPE_SESSION_AUTHORIZATION_BEGIN 'a'
> ++#define CMD_TYPE_SESSION_AUTHORIZATION_END 'b'
> ++#define CMD_TYPE_SAVEPOINT 's'
> ++#define CMD_TYPE_ROLLBACK_TO_SAVEPOINT 'r'
> ++#define CMD_TYPE_RELEASE_SAVEPOINT 'l'
> ++#define CMD_TYPE_OTHER 'O'
> ++
> ++/*=========================
> ++ System call packet id
> ++===========================*/
> ++#define CMD_SYS_CALL 'S'
> ++#define CMD_SYS_PREREPLICATE 'Z'
> ++
> ++#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'
> ++
> ++/*----------------------------
> ++ 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_IMPORT 'I'
> ++#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'
> ++
> ++/*-------------------------
> ++ Prepare/Params Query
> ++--------------------------*/
> ++#define CMD_STS_PREPARE 'P'
> ++
> ++#define CMD_TYPE_P_PARSE 'P'
> ++#define CMD_TYPE_P_BIND 'B'
> ++#define CMD_TYPE_P_EXECUTE 'E'
> ++#define CMD_TYPE_P_FASTPATH 'F'
> ++#define CMD_TYPE_P_CLOSE 'C'
> ++#define CMD_TYPE_P_DESCRIBE 'D'
> ++#define CMD_TYPE_P_FLUSH 'H'
> ++#define CMD_TYPE_P_SYNC 'S'
> ++
> ++#define PGR_TRANSACTION_SOCKET (0)
> ++#define PGR_QUERY_SOCKET (1)
> ++
> ++#define DATA_FREE (0)
> ++#define DATA_INIT (1)
> ++#define DATA_USE (2)
> ++#define DATA_ERR (90)
> ++#define DATA_END (-1)
> ++#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 (100000)
> ++#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_TARGET_ONLY (102)
> ++#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 RSYNC_COMPRESS_TAG "Rsync_Compress"
> ++#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_RELIABLE_MODE_DONE_FUNC_NO (6)
> ++#define PGR_NOTICE_ABORT_FUNC_NO (7)
> ++#define PGR_SET_CURRENT_REPLICATION_QUERY_ID_NO (8)
> ++#define PGR_QUERY_CONFIRM_ANSWER_FUNC_NO (9)
> ++#define PGR_GET_OID_FUNC_NO (10)
> ++#define PGR_SET_OID_FUNC_NO (11)
> ++
> ++#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 (8192)
> ++#define MAX_WORDS (24)
> ++#define MAX_WORD_LETTERS (48)
> ++#define PGR_MESSAGE_BUFSIZE (128)
> ++#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;
> ++ char cmdSts; /*
> ++ Q:query
> ++ T:transaction
> ++ */
> ++ char cmdType; /*
> ++ S:select
> ++ I:insert
> ++ D:delete
> ++ U:update
> ++ B:begin
> ++ E:commit/rollback/end
> ++ O:others
> ++ */
> ++ 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;
> ++ int isAutoCommit; /* 0 if autocommit is off. 1 if autocommit is on */
> ++ 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
> ++{
> ++ uint32_t replicate_id;
> ++ int useFlag;
> ++ int use_seed;
> ++ int use_time;
> ++ int offset_sec;
> ++ int offset_usec;
> ++ struct timeval tp;
> ++} ReplicateNow;
> ++
> ++typedef struct CopyDataType
> ++{
> ++ int cnt;
> ++ char copy_data[COPYBUFSIZ];
> ++} CopyData;
> ++
> ++typedef struct ClusterDBInfoType
> ++{
> ++ int status;
> ++} ClusterDBInfo;
> ++
> ++typedef struct
> ++{
> ++ uint32_t arg1;
> ++ uint32_t arg2;
> ++ uint32_t arg3;
> ++ char buf[1];
> ++} LOArgs;
> ++
> ++extern ConfDataType * ConfData_Top;
> ++extern ConfDataType * ConfData_End;
> ++extern ReplicateServerInfo * ReplicateServerData;
> ++extern ClusterDBInfo * ClusterDBData;
> ++extern int ReplicateServerShmid;
> ++extern int ClusterDBShmid;
> ++
> ++
> ++/* 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 PGRwrite_log_file(FILE * fp, const char * fmt,...);
> ++extern void show_debug(const char * fmt,...);
> ++extern void show_error(const char * fmt,...);
> ++
> ++
> ++
> ++#endif /* REPLICATE_COM_H */
> +diff -aruN postgresql-8.1.2/src/include/storage/lmgr.h
> pgcluster-1.5.0rc7/src/include/storage/lmgr.h
> +--- postgresql-8.1.2/src/include/storage/lmgr.h 2005-10-15
> 04:49:46.000000000 +0200
> ++++ pgcluster-1.5.0rc7/src/include/storage/lmgr.h 2006-01-10
> 17:39:43.000000000 +0100
> +@@ -15,6 +15,7 @@
> + #define LMGR_H
> +
> + #include "storage/lock.h"
> ++#include "storage/bufmgr.h"
> + #include "utils/rel.h"
> +
> +
> +@@ -85,4 +86,5 @@
> + extern void UnlockSharedObject(Oid classid, Oid objid, uint16 objsubid,
> + LOCKMODE lockmode);
> +
> ++extern void XactLockTableWaitForCluster(TransactionId xid,Buffer buffer);
> + #endif /* LMGR_H */
> +diff -aruN postgresql-8.1.2/src/include/storage/proc.h
> pgcluster-1.5.0rc7/src/include/storage/proc.h
> +--- postgresql-8.1.2/src/include/storage/proc.h 2005-10-15
> 04:49:46.000000000 +0200
> ++++ pgcluster-1.5.0rc7/src/include/storage/proc.h 2006-01-10
> 17:39:43.000000000 +0100
> +@@ -90,6 +90,9 @@
> + * awaited by
> this backend */
> +
> + struct XidCache subxids; /* cache for subtransaction XIDs */
> ++#ifdef USE_REPLICATION
> ++ unsigned int replicationId; /* id for replication. */
> ++#endif
> + };
> +
> + /* NOTE: "typedef struct PGPROC PGPROC" appears in storage/lock.h. */
> +diff -aruN postgresql-8.1.2/src/interfaces/libpq/Makefile
> pgcluster-1.5.0rc7/src/interfaces/libpq/Makefile
> +--- postgresql-8.1.2/src/interfaces/libpq/Makefile 2005-08-29
> 02:47:35.000000000 +0200
> ++++ pgcluster-1.5.0rc7/src/interfaces/libpq/Makefile 2006-01-10
> 17:39:43.000000000 +0100
> +@@ -30,7 +30,7 @@
> +
> + OBJS= fe-auth.o fe-connect.o fe-exec.o fe-misc.o fe-print.o
> fe-lobj.o \
> + fe-protocol2.o fe-protocol3.o pqexpbuffer.o pqsignal.o fe-secure.o \
> +- md5.o ip.o wchar.o encnames.o noblock.o pgstrcasecmp.o thread.o \
> ++ dllist.o md5.o ip.o wchar.o encnames.o noblock.o pgstrcasecmp.o
> thread.o \
> + $(filter crypt.o getaddrinfo.o inet_aton.o open.o snprintf.o
> strerror.o, $(LIBOBJS))
> +
> + ifeq ($(PORTNAME), cygwin)
> +@@ -86,6 +86,9 @@
> + encnames.c wchar.c : % : $(backend_src)/utils/mb/%
> + rm -f $@ && $(LN_S) $< .
> +
> ++dllist.c : % : $(backend_src)/lib/dllist.c
> ++ rm -f $@ && $(LN_S) $< .
> ++
> +
> + # We need several not-quite-identical variants of .DEF files to build
> libpq
> + # DLLs for Windows. These are made from the single source file
> exports.txt.
> +@@ -144,7 +147,7 @@
> + rm -f $(DESTDIR)$(includedir)/libpq-fe.h
> $(DESTDIR)$(includedir_internal)/libpq-int.h
> $(DESTDIR)$(includedir_internal)/pqexpbuffer.h
> +
> + clean distclean: clean-lib
> +- rm -f $(OBJS) pg_config_paths.h crypt.c getaddrinfo.c inet_aton.c
> noblock.c pgstrcasecmp.c snprintf.c strerror.c open.c thread.c md5.c ip.c
> encnames.c wchar.c pthread.h
> ++ rm -f $(OBJS) pg_config_paths.h crypt.c getaddrinfo.c inet_aton.c
> noblock.c pgstrcasecmp.c snprintf.c strerror.c open.c thread.c md5.c ip.c
> encnames.c wchar.c pthread.h dllist.c
> + rm -f pg_config_paths.h # Might be left over from a Win32 client-only
> build
> +
> + maintainer-clean: distclean
> +diff -aruN postgresql-8.1.2/src/interfaces/libpq/libpq.rc
> pgcluster-1.5.0rc7/src/interfaces/libpq/libpq.rc
> +--- postgresql-8.1.2/src/interfaces/libpq/libpq.rc 2006-01-06
> 05:09:37.000000000 +0100
> ++++ pgcluster-1.5.0rc7/src/interfaces/libpq/libpq.rc 2006-02-09
> 23:03:29.000000000 +0100
> +@@ -1,8 +1,8 @@
> + #include <winver.h>
> +
> + VS_VERSION_INFO VERSIONINFO
> +- FILEVERSION 8,1,2,6006
> +- PRODUCTVERSION 8,1,2,6006
> ++ FILEVERSION 8,1,2,6040
> ++ PRODUCTVERSION 8,1,2,6040
> + FILEFLAGSMASK 0x3fL
> + FILEFLAGS 0
> + FILEOS VOS__WINDOWS32
> +diff -aruN postgresql-8.1.2/src/makefiles/Makefile.aix
> pgcluster-1.5.0rc7/src/makefiles/Makefile.aix
> +--- postgresql-8.1.2/src/makefiles/Makefile.aix 2005-10-28
> 19:32:22.000000000 +0200
> ++++ pgcluster-1.5.0rc7/src/makefiles/Makefile.aix 2006-01-10
> 17:39:48.000000000 +0100
> +@@ -36,3 +36,5 @@
> + $(CC) $(LDFLAGS) $(LDFLAGS_SL) -o $@ $*.o -Wl,-bE:$*$(EXPSUFF)
> $(SHLIB_LINK)
> +
> + sqlmansect = 7
> ++CFLAGS += -pthread
> ++LDFLAGS += -L/usr/lib/threads
> +diff -aruN postgresql-8.1.2/src/makefiles/Makefile.freebsd
> pgcluster-1.5.0rc7/src/makefiles/Makefile.freebsd
> +--- postgresql-8.1.2/src/makefiles/Makefile.freebsd 2005-08-24
> 22:20:38.000000000 +0200
> ++++ pgcluster-1.5.0rc7/src/makefiles/Makefile.freebsd 2006-01-10
> 17:39:48.000000000 +0100
> +@@ -28,3 +28,5 @@
> + endif
> +
> + sqlmansect = 7
> ++
> ++LIBS += -lc_r
> +diff -aruN postgresql-8.1.2/src/makefiles/Makefile.hpux
> pgcluster-1.5.0rc7/src/makefiles/Makefile.hpux
> +--- postgresql-8.1.2/src/makefiles/Makefile.hpux 2004-12-21
> 19:47:42.000000000 +0100
> ++++ pgcluster-1.5.0rc7/src/makefiles/Makefile.hpux 2006-01-10
> 17:39:48.000000000 +0100
> +@@ -16,6 +16,9 @@
> + # correctly in the LP64 data model.
> + LIBS := -lxnet $(LIBS)
> +
> ++# add thread lib for PGCluster
> ++LIBS := -lpthread $(LIBS)
> ++
> + # Set up rpath so that the executables don't need SHLIB_PATH to be set.
> + # (Note: --disable-rpath is a really bad idea on this platform...)
> + ifeq ($(with_gnu_ld), yes)
> +diff -aruN postgresql-8.1.2/src/makefiles/Makefile.linux
> pgcluster-1.5.0rc7/src/makefiles/Makefile.linux
> +--- postgresql-8.1.2/src/makefiles/Makefile.linux 2004-12-21
> 19:47:42.000000000 +0100
> ++++ pgcluster-1.5.0rc7/src/makefiles/Makefile.linux 2006-01-10
> 17:39:48.000000000 +0100
> +@@ -14,3 +14,4 @@
> + $(CC) -shared -o $@ $<
> +
> + sqlmansect = 7
> ++LIBS += -lpthread
> +diff -aruN postgresql-8.1.2/src/makefiles/Makefile.netbsd
> pgcluster-1.5.0rc7/src/makefiles/Makefile.netbsd
> +--- postgresql-8.1.2/src/makefiles/Makefile.netbsd 2004-12-21
> 19:47:42.000000000 +0100
> ++++ pgcluster-1.5.0rc7/src/makefiles/Makefile.netbsd 2006-01-10
> 17:39:48.000000000 +0100
> +@@ -30,3 +30,4 @@
> + endif
> +
> + sqlmansect = 7
> ++LIBS += -lpthread
> +diff -aruN postgresql-8.1.2/src/makefiles/Makefile.openbsd
> pgcluster-1.5.0rc7/src/makefiles/Makefile.openbsd
> +--- postgresql-8.1.2/src/makefiles/Makefile.openbsd 2004-12-21
> 19:47:42.000000000 +0100
> ++++ pgcluster-1.5.0rc7/src/makefiles/Makefile.openbsd 2006-01-10
> 17:39:48.000000000 +0100
> +@@ -28,3 +28,4 @@
> + endif
> +
> + sqlmansect = 7
> ++LIBS += -lc_r
> +diff -aruN postgresql-8.1.2/src/makefiles/Makefile.solaris
> pgcluster-1.5.0rc7/src/makefiles/Makefile.solaris
> +--- postgresql-8.1.2/src/makefiles/Makefile.solaris 2004-12-21
> 19:47:42.000000000 +0100
> ++++ pgcluster-1.5.0rc7/src/makefiles/Makefile.solaris 2006-01-10
> 17:39:48.000000000 +0100
> +@@ -20,3 +20,4 @@
> + $(LD) -G -Bdynamic -o $@ $<
> +
> + sqlmansect = 5sql
> ++LIBS += -lpthread
> +diff -aruN postgresql-8.1.2/src/makefiles/Makefile.sunos4
> pgcluster-1.5.0rc7/src/makefiles/Makefile.sunos4
> +--- postgresql-8.1.2/src/makefiles/Makefile.sunos4 2002-09-05
> 00:54:18.000000000 +0200
> ++++ pgcluster-1.5.0rc7/src/makefiles/Makefile.sunos4 2006-01-10
> 17:39:48.000000000 +0100
> +@@ -11,3 +11,4 @@
> + $(LD) -assert pure-text -Bdynamic -o $@ $<
> +
> + sqlmansect = 7
> ++LIBS += -lpthread
> +diff -aruN postgresql-8.1.2/src/pgcluster/Makefile
> pgcluster-1.5.0rc7/src/pgcluster/Makefile
> +--- postgresql-8.1.2/src/pgcluster/Makefile 1970-01-01 01:00:00.000000000
> +0100
> ++++ pgcluster-1.5.0rc7/src/pgcluster/Makefile 2006-01-10
> 17:39:44.000000000 +0100
> +@@ -0,0 +1,17 @@
> ++#-------------------------------------------------------------------------
> ++#
> ++# Makefile for src/pgcluster (client programs)
> ++#
> ++#-------------------------------------------------------------------------
> ++
> ++subdir = src/pgcluster
> ++top_builddir = ../..
> ++include $(top_builddir)/src/Makefile.global
> ++
> ++DIRS := libpgc 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 -aruN postgresql-8.1.2/src/pgcluster/libpgc/Makefile
> pgcluster-1.5.0rc7/src/pgcluster/libpgc/Makefile
> +--- postgresql-8.1.2/src/pgcluster/libpgc/Makefile 1970-01-01
> 01:00:00.000000000 +0100
> ++++ pgcluster-1.5.0rc7/src/pgcluster/libpgc/Makefile 2006-01-10
> 17:39:44.000000000 +0100
> +@@ -0,0 +1,32 @@
> ++#-------------------------------------------------------------------------
> ++#
> ++# Makefile--
> ++# Makefile for libpq subsystem (backend half of libpq interface)
> ++#
> ++# IDENTIFICATION
> ++# $Header: /cvsroot/pgsql-server/src/backend/libpq/Makefile,v 1.33
> 2002/06/14 04:23:17 momjian Exp $
> ++#
> ++#-------------------------------------------------------------------------
> ++
> ++subdir = src/pgcluster/libpgc
> ++top_builddir = ../../..
> ++include $(top_builddir)/src/Makefile.global
> ++
> ++OBJS = sem.o show.o
> ++
> ++all: SUBSYS.o
> ++
> ++SUBSYS.o: $(OBJS)
> ++ $(LD) $(LDREL) $(LDOUT) SUBSYS.o $(OBJS)
> ++
> ++depend dep:
> ++ $(CC) -MM $(CFLAGS) *.c >depend
> ++
> ++distclean: clean
> ++
> ++clean:
> ++ rm -f SUBSYS.o $(OBJS)
> ++
> ++ifeq (depend,$(wildcard depend))
> ++include depend
> ++endif
> +diff -aruN postgresql-8.1.2/src/pgcluster/libpgc/libpgc.h
> pgcluster-1.5.0rc7/src/pgcluster/libpgc/libpgc.h
> +--- postgresql-8.1.2/src/pgcluster/libpgc/libpgc.h 1970-01-01
> 01:00:00.000000000 +0100
> ++++ pgcluster-1.5.0rc7/src/pgcluster/libpgc/libpgc.h 2006-01-10
> 17:39:44.000000000 +0100
> +@@ -0,0 +1,22 @@
> ++/*-------------------------------------------------------------------------
> ++ *
> ++ * lilbpgc.h
> ++ * external definition of the function for pgreplicate and pglb
> ++ *
> ++ * This should be the first file included by replicate modules.
> ++ *
> ++
> *-------------------------------------------------------------------------
> ++ */
> ++#ifndef LIBPGC_H
> ++#define LIBPGC_H
> ++
> ++/* external definition of the function in sem.c */
> ++extern void PGRsem_unlock( int semid, short sem_num );
> ++extern void PGRsem_lock( int semid, short sem_num );
> ++
> ++/* external definition of the function in show.c */
> ++extern void show_debug(const char * fmt,...);
> ++extern void show_error(const char * fmt,...);
> ++extern void PGRwrite_log_file(FILE * fp, const char * fmt,...);
> ++
> ++#endif /* LIBPGC_H */
> +diff -aruN postgresql-8.1.2/src/pgcluster/libpgc/sem.c
> pgcluster-1.5.0rc7/src/pgcluster/libpgc/sem.c
> +--- postgresql-8.1.2/src/pgcluster/libpgc/sem.c 1970-01-01
> 01:00:00.000000000 +0100
> ++++ pgcluster-1.5.0rc7/src/pgcluster/libpgc/sem.c 2006-01-10
> 17:39:44.000000000 +0100
> +@@ -0,0 +1,67 @@
> ++/*--------------------------------------------------------------------
> ++ * FILE:
> ++ * sem.c
> ++ *
> ++ * NOTE:
> ++ * This file is composed of the functions to call with the source
> ++ * at pgreplicate for the semapho control.
> ++ *
> ++ * Portions Copyright (c) 2003-2006, Atsushi Mitani
> ++ *--------------------------------------------------------------------
> ++ */
> ++#include <stdio.h>
> ++#include <unistd.h>
> ++#include <sys/types.h>
> ++#include <errno.h>
> ++#include <sys/ipc.h>
> ++#include <sys/sem.h>
> ++#include <signal.h>
> ++
> ++extern void show_debug(const char * fmt,...);
> ++
> ++void PGRsem_unlock( int semid, short sem_num );
> ++void PGRsem_lock( int semid, short sem_num );
> ++
> ++#define PGR_SEM_UNLOCK_WAIT_MSEC (100)
> ++#define PGR_SEM_LOCK_WAIT_MSEC (500)
> ++
> ++void
> ++PGRsem_unlock( int semid, short sem_num )
> ++{
> ++ int status = 0;
> ++ struct sembuf sops;
> ++
> ++ sops.sem_num = sem_num;
> ++ sops.sem_op = 1;
> ++ /*sops.sem_flg = IPC_NOWAIT;*/
> ++ sops.sem_flg = 0;
> ++ do
> ++ {
> ++ status = semop(semid, &sops, 1);
> ++ if ((status == -1) && (errno != EINTR))
> ++ {
> ++ usleep(PGR_SEM_UNLOCK_WAIT_MSEC);
> ++ }
> ++ } while (status == -1);
> ++}
> ++
> ++void
> ++PGRsem_lock( int semid, short sem_num )
> ++{
> ++ int status = 0;
> ++ struct sembuf sops;
> ++
> ++ sops.sem_num = sem_num;
> ++ sops.sem_op = -1;
> ++ /*sops.sem_flg = IPC_NOWAIT;*/
> ++ sops.sem_flg = 0;
> ++ do
> ++ {
> ++ status = semop(semid, &sops, 1);
> ++ if ((status == -1) && (errno != EINTR))
> ++ {
> ++ usleep(PGR_SEM_LOCK_WAIT_MSEC);
> ++ }
> ++ } while (status == -1);
> ++}
> ++
> +diff -aruN postgresql-8.1.2/src/pgcluster/libpgc/show.c
> pgcluster-1.5.0rc7/src/pgcluster/libpgc/show.c
> +--- postgresql-8.1.2/src/pgcluster/libpgc/show.c 1970-01-01
> 01:00:00.000000000 +0100
> ++++ pgcluster-1.5.0rc7/src/pgcluster/libpgc/show.c 2006-01-10
> 17:39:44.000000000 +0100
> +@@ -0,0 +1,119 @@
> ++/*--------------------------------------------------------------------
> ++ * FILE:
> ++ * show.c
> ++ *
> ++ * NOTE:
> ++ * This file is composed of the logging and debug functions
> ++ *
> ++ * Portions Copyright (c) 2003-2006, Atsushi Mitani
> ++ *--------------------------------------------------------------------
> ++ */
> ++#include <stdio.h>
> ++#include <stdarg.h>
> ++#include <stdlib.h>
> ++#include <errno.h>
> ++#include <string.h>
> ++#include <unistd.h>
> ++#include <time.h>
> ++#include <sys/time.h>
> ++#include <sys/types.h>
> ++
> ++#define TIMESTAMP_SIZE 19 /* format `YYYY-MM-DD HH:MM:SS' */
> ++
> ++/*--------------------------------------
> ++ * PROTOTYPE DECLARATION
> ++ *--------------------------------------
> ++ */
> ++void show_debug(const char * fmt,...);
> ++void show_error(const char * fmt,...);
> ++void PGRwrite_log_file(FILE * fp, const char * fmt,...);
> ++
> ++extern int Debug_Print;
> ++extern int Log_Print;
> ++extern FILE * LogFp;
> ++
> ++static char*
> ++get_current_timestamp(void)
> ++{
> ++ time_t now;
> ++ static char buf[TIMESTAMP_SIZE + 1];
> ++
> ++ now = time(NULL);
> ++ strftime(buf, sizeof(buf),
> ++ "%Y-%m-%d %H:%M:%S", localtime(&now));
> ++ return buf;
> ++}
> ++
> ++void
> ++show_debug(const char * fmt,...)
> ++{
> ++ va_list ap;
> ++ char *timestamp;
> ++
> ++ if (Debug_Print)
> ++ {
> ++ timestamp = get_current_timestamp();
> ++ fprintf(stdout,"%s [%d] DEBUG:",timestamp, getpid());
> ++ 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], *timestamp;
> ++
> ++ if (Debug_Print)
> ++ {
> ++ timestamp = get_current_timestamp();
> ++ fprintf(stderr,"%s [%d] ERROR:",timestamp, getpid());
> ++ va_start(ap,fmt);
> ++ vfprintf(stderr,fmt,ap);
> ++ va_end(ap);
> ++ fprintf(stderr,"\n");
> ++ fflush(stderr);
> ++ }
> ++ if ((Log_Print) && (LogFp != NULL))
> ++ {
> ++ va_start(ap,fmt);
> ++ vsnprintf(buf,sizeof(buf),fmt,ap);
> ++ va_end(ap);
> ++ PGRwrite_log_file(LogFp,buf);
> ++ }
> ++}
> ++
> ++void
> ++PGRwrite_log_file(FILE * fp, const char * fmt,...)
> ++{
> ++ char buf[256];
> ++ char log[288];
> ++ char * timestamp;
> ++ va_list ap;
> ++ time_t t;
> ++
> ++ if (fp == NULL)
> ++ {
> ++ return;
> ++ }
> ++ if (time(&t) < 0)
> ++ {
> ++ return;
> ++ }
> ++ timestamp = get_current_timestamp();
> ++ snprintf(log,sizeof(log),"%s ",timestamp);
> ++ 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);
> ++ }
> ++}
> ++
> +diff -aruN postgresql-8.1.2/src/pgcluster/pglb/AUTHORS
> pgcluster-1.5.0rc7/src/pgcluster/pglb/AUTHORS
> +--- postgresql-8.1.2/src/pgcluster/pglb/AUTHORS 1970-01-01
> 01:00:00.000000000 +0100
> ++++ pgcluster-1.5.0rc7/src/pgcluster/pglb/AUTHORS 2006-01-10
> 17:39:44.000000000 +0100
> +@@ -0,0 +1,3 @@
> ++Authors of pglb
> ++
> ++pglb was written by Atsushi Mitani
> +diff -aruN postgresql-8.1.2/src/pgcluster/pglb/COPYING
> pgcluster-1.5.0rc7/src/pgcluster/pglb/COPYING
> +--- postgresql-8.1.2/src/pgcluster/pglb/COPYING 1970-01-01
> 01:00:00.000000000 +0100
> ++++ pgcluster-1.5.0rc7/src/pgcluster/pglb/COPYING 2006-01-10
> 17:39:44.000000000 +0100
> +@@ -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 -aruN postgresql-8.1.2/src/pgcluster/pglb/Makefile
> pgcluster-1.5.0rc7/src/pgcluster/pglb/Makefile
> +--- postgresql-8.1.2/src/pgcluster/pglb/Makefile 1970-01-01
> 01:00:00.000000000 +0100
> ++++ pgcluster-1.5.0rc7/src/pgcluster/pglb/Makefile 2006-01-10
> 17:39:44.000000000 +0100
> +@@ -0,0 +1,38 @@
> ++#-------------------------------------------------------------------------
> ++#
> ++# Makefile for src/pgcluster/pgrp
> ++#
> ++#-------------------------------------------------------------------------
> ++
> ++subdir = src/pgcluster/pglb
> ++top_builddir = ../../..
> ++include $(top_builddir)/src/Makefile.global
> ++
> ++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/replicate_com.o
> ../libpgc/SUBSYS.o
> ++
> ++CFLAGS += -DPRINT_DEBUG
> ++override CPPFLAGS := -I$(libpq_srcdir) $(CPPFLAGS) -DBINDIR=\"$(bindir)\"
> ++
> ++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)$(datadir)/pglb.conf.sample
> ++
> ++installdirs:
> ++ $(mkinstalldirs) $(DESTDIR)$(bindir)
> ++ $(mkinstalldirs) $(DESTDIR)$(datadir)
> ++
> ++uninstall:
> ++ rm -f $(addprefix $(DESTDIR)$(bindir)/, pglb$(X))
> ++ rm -f $(DESTDIR)$(datadir)/pglb.conf.sample
> ++
> ++clean distclean maintainer-clean:
> ++ rm -f pglb$(X) $(OBJS)
> +diff -aruN postgresql-8.1.2/src/pgcluster/pglb/README
> pgcluster-1.5.0rc7/src/pgcluster/pglb/README
> +--- postgresql-8.1.2/src/pgcluster/pglb/README 1970-01-01
> 01:00:00.000000000 +0100
> ++++ pgcluster-1.5.0rc7/src/pgcluster/pglb/README 2006-01-10
> 17:39:44.000000000 +0100
> +@@ -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 -aruN postgresql-8.1.2/src/pgcluster/pglb/child.c
> pgcluster-1.5.0rc7/src/pgcluster/pglb/child.c
> +--- postgresql-8.1.2/src/pgcluster/pglb/child.c 1970-01-01
> 01:00:00.000000000 +0100
> ++++ pgcluster-1.5.0rc7/src/pgcluster/pglb/child.c 2006-01-10
> 17:39:44.000000000 +0100
> +@@ -0,0 +1,1194 @@
> ++/*--------------------------------------------------------------------
> ++ * 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-2006, Atsushi Mitani
> ++ * Portions Copyright (c) 2003-2006, 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.h"
> ++
> ++#include <stdio.h>
> ++#include <string.h>
> ++#include <unistd.h>
> ++#include <signal.h>
> ++#include <sys/wait.h>
> ++#include <sys/time.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 <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 PGRreturn_no_connection_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);
> ++static void PGRreturn_with_error(char *msg);
> ++
> ++
> ++/*--------------------------------------------------------------------
> ++ * 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;
> ++
> ++ pid = getpid();
> ++#ifdef PRINT_DEBUG
> ++ show_debug("%s:I am %d",func, pid);
> ++#endif
> ++
> ++ /* set up signal handlers */
> ++ signal(SIGALRM, SIG_DFL);
> ++ 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
> ++
> ++retry_accept:
> ++ /* 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_FREE);
> ++ 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_FREE);
> ++ 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;
> ++
> ++ if ((backend = connect_backend(sp, frontend)) == NULL)
> ++ {
> ++ /*
> ++
> PGRset_status_on_cluster_tbl(TBL_ERROR,CurrentCluster);
> ++ return STATUS_ERROR;
> ++ */
> ++ goto retry_accept;
> ++ }
> ++ }
> ++ 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") ||
> use_pool == NOT_USE_CONNECTION_POOL)
> ++ {
> ++ 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:
> ++ show_error("%s:do_child: fatal error
> occured",func);
> ++ 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_FREE);
> ++ 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();
> ++
> ++ 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;
> ++ pid_t pid;
> ++
> ++ pid = getpid();
> ++ rtn = PGRdo_child(USE_CONNECTION_POOL);
> ++ PGRrelease_connection(CurrentCluster);
> ++ if (rtn != STATUS_OK)
> ++ {
> ++ show_error("%s:PGRdo_child failed",func);
> ++ child_end(SIGTERM);
> ++ }
> ++ 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)
> ++{
> ++ PGRreturn_with_error( "Sorry, backend connection is full\n");
> ++}
> ++
> ++void
> ++PGRreturn_no_connection_error(void) {
> ++ PGRreturn_with_error("pglb could not connect to server: no cluster
> available.\n");
> ++}
> ++
> ++static void
> ++PGRreturn_with_error (char *msg)
> ++{
> ++ PGR_StartupPacket *sp = NULL;
> ++ POOL_CONNECTION *frontend = NULL;
> ++
> ++
> ++ /* 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)))
> ++ {
> ++ free(sp);
> ++ return NULL;
> ++ }
> ++ len = ntohl(len);
> ++ len -= sizeof(len);
> ++
> ++ if (len <= 0)
> ++ {
> ++ show_error("%s:read_startup_packet: incorrect packet length
> (%d)", func,len);
> ++ free(sp);
> ++ return NULL;
> ++ }
> ++
> ++ sp->startup_packet = calloc(len, 1);
> ++ if (!sp->startup_packet)
> ++ {
> ++ show_error("%s:read_startup_packet: out of memory",func);
> ++ free(sp);
> ++ return NULL;
> ++ }
> ++
> ++ /* read startup packet */
> ++ if (pool_read(cp, sp->startup_packet, len))
> ++ {
> ++ free(sp);
> ++ 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);
> ++ free(sp);
> ++ 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);
> ++ free(sp);
> ++ 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);
> ++ free(sp);
> ++ 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);
> ++ free(sp);
> ++ 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);
> ++ free(sp);
> ++ return NULL;
> ++ }
> ++ sp->user = calloc(1, 1);
> ++ if (!sp->user)
> ++ {
> ++ show_error("%s:read_startup_packet: out of
> memory",func);
> ++ free(sp);
> ++ return NULL;
> ++ }
> ++ break;
> ++
> ++ default:
> ++ show_error("%s:read_startup_packet: invalid major no:
> %d",func, sp->major);
> ++ free(sp);
> ++ 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);
> ++}
> +diff -aruN postgresql-8.1.2/src/pgcluster/pglb/cluster_table.c
> pgcluster-1.5.0rc7/src/pgcluster/pglb/cluster_table.c
> +--- postgresql-8.1.2/src/pgcluster/pglb/cluster_table.c 1970-01-01
> 01:00:00.000000000 +0100
> ++++ pgcluster-1.5.0rc7/src/pgcluster/pglb/cluster_table.c 2006-01-10
> 17:39:44.000000000 +0100
> +@@ -0,0 +1,338 @@
> ++/*--------------------------------------------------------------------
> ++ * FILE:
> ++ * cluster_tbl.c
> ++ *
> ++ * NOTE:
> ++ * This file is composed of the functions to use a cluster table.
> ++ *
> ++ * Portions Copyright (c) 2003-2006, 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.
> ++ *
> ++*/
> ++#include <stdio.h>
> ++#include <stdarg.h>
> ++#include <string.h>
> ++#include <stdlib.h>
> ++#include <unistd.h>
> ++#include <signal.h>
> ++#include <sys/wait.h>
> ++#include <sys/time.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 <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 PGRis_cluster_alive(void) ;
> ++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);
> ++
> ++int PGRis_cluster_alive(void)
> ++{
> ++ ClusterTbl * ptr = NULL;
> ++ int use=0;
> ++ ptr = Cluster_Tbl;
> ++
> ++ PGRsem_lock(ClusterSemid,MAX_DB_SERVER);
> ++ while (ptr->useFlag != TBL_END)
> ++ {
> ++ if (ptr->useFlag == TBL_USE)
> ++ {
> ++ use++;
> ++ }
> ++ ptr++;
> ++ }
> ++ PGRsem_unlock(ClusterSemid,MAX_DB_SERVER);
> ++ return use==0 ? STATUS_ERROR : STATUS_OK;
> ++}
> ++
> ++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
> ++ cnt ++;
> ++ if (ptr->useFlag != TBL_USE)
> ++ {
> ++ ptr ++;
> ++ continue;
> ++ }
> ++ 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));
> ++ memcpy(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(StatusFp,"port(%d) host:%s free",
> ++ ptr->port,
> ++ ptr->hostName);
> ++ break;
> ++ case TBL_INIT:
> ++ PGRwrite_log_file(StatusFp,"port(%d) host:%s
> initialize",
> ++ ptr->port,
> ++ ptr->hostName);
> ++ break;
> ++ case TBL_USE:
> ++ PGRwrite_log_file(StatusFp,"port(%d) host:%s start
> use",
> ++ ptr->port,
> ++ ptr->hostName);
> ++ break;
> ++ case TBL_ERROR:
> ++ PGRwrite_log_file(StatusFp,"port(%d) host:%s error",
> ++ ptr->port,
> ++ ptr->hostName);
> ++ break;
> ++ case TBL_END:
> ++ PGRwrite_log_file(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 (ptr->port > 0)
> ++ {
> ++ 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;
> ++ memcpy(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;
> ++}
> ++
> +diff -aruN postgresql-8.1.2/src/pgcluster/pglb/load_balance.c
> pgcluster-1.5.0rc7/src/pgcluster/pglb/load_balance.c
> +--- postgresql-8.1.2/src/pgcluster/pglb/load_balance.c 1970-01-01
> 01:00:00.000000000 +0100
> ++++ pgcluster-1.5.0rc7/src/pgcluster/pglb/load_balance.c 2006-01-10
> 17:39:44.000000000 +0100
> +@@ -0,0 +1,252 @@
> ++/*--------------------------------------------------------------------
> ++ * 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-2006, 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.
> ++ *
> ++*/
> ++#include "postgres.h"
> ++#include <stdio.h>
> ++#include <stdlib.h>
> ++#include <string.h>
> ++#include <unistd.h>
> ++#include <signal.h>
> ++#include <sys/wait.h>
> ++#include <sys/time.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 <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);
> ++ 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_no_connection_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);
> ++}
> ++
> ++void
> ++PGRchild_wait(int sig)
> ++{
> ++ pid_t pid = 0;
> ++ int ret = 0;
> ++
> ++ do {
> ++ pid = waitpid(-1,&ret,WNOHANG);
> ++ if ((pid <= 0) && (WTERMSIG(ret) > 0))
> ++ {
> ++ pid = 1;
> ++ }
> ++ } while(pid > 0);
> ++}
> +diff -aruN postgresql-8.1.2/src/pgcluster/pglb/main.c
> pgcluster-1.5.0rc7/src/pgcluster/pglb/main.c
> +--- postgresql-8.1.2/src/pgcluster/pglb/main.c 1970-01-01
> 01:00:00.000000000 +0100
> ++++ pgcluster-1.5.0rc7/src/pgcluster/pglb/main.c 2006-01-10
> 17:39:44.000000000 +0100
> +@@ -0,0 +1,1050 @@
> ++/*--------------------------------------------------------------------
> ++ * FILE:
> ++ * main.c
> ++ *
> ++ * NOTE:
> ++ * This file is composed of the main function of pglb.
> ++ *
> ++ * Portions Copyright (c) 2003-2006, 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.
> ++ *
> ++*/
> ++#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/time.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 <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 */
> ++ConfDataType * ConfData_Top = (ConfDataType *)NULL;
> ++ConfDataType * ConfData_End = (ConfDataType *)NULL;
> ++int SynSemID = -1;
> ++int MapTableShmid = -1;
> ++int LifeCheckStartShmid = -1;
> ++char * LifeCheckStartFlag = NULL;
> ++int LifeCheckTimeOut = 10;
> ++FILE * StatusFp = (FILE *)NULL;
> ++FILE * LogFp = (FILE *)NULL;
> ++char * PGRStatusFileName = NULL;
> ++char * PGRLogFileName = NULL;
> ++int Log_Print = 0;
> ++int Debug_Print = 0;
> ++
> ++int Recv_Port_Number = 0;
> ++int Recovery_Port_Number = 0;
> ++uint16_t LifeCheck_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 (PGRStatusFileName == NULL)
> ++ {
> ++
> snprintf(fname,sizeof(fname),"%s/%s",PGR_Write_Path,PGLB_STATUS_FILE);
> ++ }
> ++ else
> ++ {
> ++ memcpy(fname,PGRStatusFileName,sizeof(fname));
> ++ }
> ++ StatusFp = fopen(fname, "a");
> ++ if (StatusFp == NULL)
> ++ {
> ++ show_error("%s:open() %s file failed. (%s)",
> ++ func,fname, strerror(errno));
> ++ exit(1);
> ++ }
> ++ /* pglb log file open */
> ++ if (Log_Print)
> ++ {
> ++ if (PGRLogFileName == NULL)
> ++ {
> ++
> snprintf(fname,sizeof(fname),"%s/%s",PGR_Write_Path,PGLB_LOG_FILE);
> ++ }
> ++ else
> ++ {
> ++ memcpy(fname,PGRLogFileName,sizeof(fname));
> ++ }
> ++ LogFp = fopen(fname,"a");
> ++ if (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 = 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))
> ++ {
> ++
> memcpy(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))
> ++ {
> ++ Recovery_Port_Number = atoi(conf->value);
> ++ conf = (ConfDataType*)conf->next;
> ++ continue;
> ++ }
> ++ /*
> ++ if (!STRCMP(conf->key,LIFECHECK_PORT_TAG))
> ++ {
> ++ LifeCheck_Port_Number = atoi(conf->value);
> ++ conf = (ConfDataType*)conf->next;
> ++ continue;
> ++ }
> ++ if (!STRCMP(conf->key,STATUS_LOG_FILE_TAG))
> ++ {
> ++ PGRStatusFileName = strdup(conf->value);
> ++ conf = (ConfDataType*)conf->next;
> ++ continue;
> ++ }
> ++ if (!STRCMP(conf->key,ERROR_LOG_FILE_TAG))
> ++ {
> ++ 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((char *)Cluster_Tbl);
> ++ shmctl(ClusterShmid,IPC_RMID,(struct shmid_ds *)NULL);
> ++ ClusterShmid = 0;
> ++ Cluster_Tbl = NULL;
> ++ }
> ++ if (ChildShmid > 0)
> ++ {
> ++ rtn = shmdt((char *)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 (StatusFp != NULL)
> ++ {
> ++ fflush(StatusFp);
> ++ fclose(StatusFp);
> ++ }
> ++ if (LogFp != NULL)
> ++ {
> ++ fflush(LogFp);
> ++ fclose(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(PGRis_cluster_alive() == STATUS_ERROR) {
> ++ show_error("%s:all clusters were dead.",func);
> PGRreturn_no_connection_error();
> ++ count=0;
> ++ }
> ++ else
> ++ {
> ++ 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;
> ++
> ++ReWait:
> ++
> ++ errno = 0;
> ++#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);
> ++ }
> ++ if ((pid < 0) && (errno == EINTR))
> ++ goto ReWait;
> ++}
> ++
> ++/*--------------------------------------------------------------------
> ++ * 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;
> ++ 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)
> ++ {
> ++ 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++;
> ++ }
> ++ signal(SIGUSR2, close_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 | restart]\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");
> ++ fprintf(stderr," restart: restart 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;
> ++
> ++ 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':
> ++ Log_Print = 1;
> ++ break;
> ++ case 'v':
> ++ 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")) ||
> ++ (!strcmp(argv[optind],"restart"))))
> ++ {
> ++ stop_pglb();
> ++ if (!strcmp(argv[optind],"stop"))
> ++ {
> ++ 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;
> ++}
> ++
> +diff -aruN postgresql-8.1.2/src/pgcluster/pglb/pglb.conf.sample
> pgcluster-1.5.0rc7/src/pgcluster/pglb/pglb.conf.sample
> +--- postgresql-8.1.2/src/pgcluster/pglb/pglb.conf.sample 1970-01-01
> 01:00:00.000000000 +0100
> ++++ pgcluster-1.5.0rc7/src/pgcluster/pglb/pglb.conf.sample 2006-01-10
> 17:39:44.000000000 +0100
> +@@ -0,0 +1,46 @@
> ++#============================================================
> ++# 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 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> 6001 </Recovery_Port>
> ++<Max_Cluster_Num> 128 </Max_Cluster_Num>
> ++<Use_Connection_Pooling> no </Use_Connection_Pooling>
> ++
> +diff -aruN postgresql-8.1.2/src/pgcluster/pglb/pglb.h
> pgcluster-1.5.0rc7/src/pgcluster/pglb/pglb.h
> +--- postgresql-8.1.2/src/pgcluster/pglb/pglb.h 1970-01-01
> 01:00:00.000000000 +0100
> ++++ pgcluster-1.5.0rc7/src/pgcluster/pglb/pglb.h 2006-02-09
> 17:46:26.000000000 +0100
> +@@ -0,0 +1,458 @@
> ++/*--------------------------------------------------------------------
> ++ * FILE:
> ++ * pglb.h
> ++ *
> ++ * Portions Copyright (c) 2003-2006 Atsushi Mitani
> ++ *--------------------------------------------------------------------
> ++ */
> ++#ifndef PGLB_H
> ++#define PGLB_H
> ++
> ++#define PGLB_VERSION "1.5.0rc7"
> ++
> ++#include "../libpgc/libpgc.h"
> ++
> ++/*
> ++ * 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 int Recovery_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;
> ++extern FILE * StatusFp;
> ++
> ++/* 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 PGRreturn_no_connection_error(void);
> ++extern void PGRquit_children_on_cluster(int rec_no);
> ++
> ++/* extern of cluster_table.c */
> ++extern int PGRis_cluster_alive(void) ;
> ++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 void PGRchild_wait(int sig);
> ++
> ++/* 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 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);
> ++
> ++/*
> ++ * external prototype in show.c
> ++ */
> ++extern void show_error(const char * fmt,...);
> ++extern void show_debug(const char * fmt,...);
> ++extern void PGRwrite_log_file(FILE * fp, const char * fmt,...);
> ++
> ++#endif /* PGLB_H */
> +diff -aruN postgresql-8.1.2/src/pgcluster/pglb/pool_auth.c
> pgcluster-1.5.0rc7/src/pgcluster/pglb/pool_auth.c
> +--- postgresql-8.1.2/src/pgcluster/pglb/pool_auth.c 1970-01-01
> 01:00:00.000000000 +0100
> ++++ pgcluster-1.5.0rc7/src/pgcluster/pglb/pool_auth.c 2006-02-02
> 22:31:51.000000000 +0100
> +@@ -0,0 +1,959 @@
> ++/*--------------------------------------------------------------------
> ++ * FILE:
> ++ * pool_auth.c
> ++ *
> ++ * NOTE:
> ++ * authenticaton stuff
> ++ *
> ++ * Portions Copyright (c) 2003-2006, Atsushi Mitani
> ++ * Portions Copyright (c) 2003-2006, 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 <sys/types.h>
> ++#include <netinet/in.h>
> ++#include <sys/param.h>
> ++#include <arpa/inet.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;
> ++}
> +diff -aruN postgresql-8.1.2/src/pgcluster/pglb/pool_connection_pool.c
> pgcluster-1.5.0rc7/src/pgcluster/pglb/pool_connection_pool.c
> +--- postgresql-8.1.2/src/pgcluster/pglb/pool_connection_pool.c
> 1970-01-01 01:00:00.000000000 +0100
> ++++ pgcluster-1.5.0rc7/src/pgcluster/pglb/pool_connection_pool.c
> 2006-02-02 22:32:25.000000000 +0100
> +@@ -0,0 +1,535 @@
> ++/*--------------------------------------------------------------------
> ++ * FILE:
> ++ * pool_connection_pool.c
> ++ *
> ++ * NOTE:
> ++ * connection pool stuff
> ++ *
> ++ * Portions Copyright (c) 2003-2006, Atsushi Mitani
> ++ * Portions Copyright (c) 2003-2006, 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.h"
> ++#include <sys/types.h>
> ++#include <sys/socket.h>
> ++#include <sys/time.h>
> ++#include <sys/un.h>
> ++#include <arpa/inet.h>
> ++#include <netdb.h>
> ++#include <stdio.h>
> ++#include <stdlib.h>
> ++#include <errno.h>
> ++#include <signal.h>
> ++#include <string.h>
> ++#include <unistd.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);
> ++ }
> ++
> ++ 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;
> ++return;
> ++ if (p == NULL)
> ++ {
> ++ show_error("%s:pool_connection_pool is not initialized",func);
> ++ return ;
> ++ }
> ++
> ++ for (i=0 ; i<Max_Pool ; i++)
> ++ {
> ++ if (p == NULL)
> ++ break;
> ++ /*
> ++ if (MASTER_CONNECTION(p)->sp->user != NULL)
> ++ {
> ++ free(MASTER_CONNECTION(p)->sp->user);
> ++ MASTER_CONNECTION(p)->sp->user = NULL;
> ++ }
> ++ if (MASTER_CONNECTION(p)->sp->database != NULL)
> ++ {
> ++ free(MASTER_CONNECTION(p)->sp->database);
> ++ MASTER_CONNECTION(p)->sp->database = NULL;
> ++ }
> ++ if (MASTER_CONNECTION(p)->sp->startup_packet != NULL)
> ++ {
> ++ free(MASTER_CONNECTION(p)->sp->startup_packet);
> ++ MASTER_CONNECTION(p)->sp->startup_packet = NULL;
> ++ }
> ++ */
> ++ if (MASTER_CONNECTION(p)->con != NULL)
> ++ {
> ++ pool_close(MASTER_CONNECTION(p)->con);
> ++ MASTER_CONNECTION(p)->con = NULL;
> ++ }
> ++ memset(p, 0, sizeof(POOL_CONNECTION_POOL));
> ++ p++;
> ++ }
> ++ free((char *)pool_connection_pool);
> ++ pool_connection_pool = NULL;
> ++}
> ++
> +diff -aruN postgresql-8.1.2/src/pgcluster/pglb/pool_params.c
> pgcluster-1.5.0rc7/src/pgcluster/pglb/pool_params.c
> +--- postgresql-8.1.2/src/pgcluster/pglb/pool_params.c 1970-01-01
> 01:00:00.000000000 +0100
> ++++ pgcluster-1.5.0rc7/src/pgcluster/pglb/pool_params.c 2006-01-10
> 17:39:44.000000000 +0100
> +@@ -0,0 +1,184 @@
> ++/*--------------------------------------------------------------------
> ++ * FILE:
> ++ * pool_params.c
> ++ *
> ++ * NOTE:
> ++ * connection pool stuff
> ++ *
> ++ * Portions Copyright (c) 2003-2006, Atsushi Mitani
> ++ * Portions Copyright (c) 2003-2006 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 <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
> ++ }
> ++}
> +diff -aruN postgresql-8.1.2/src/pgcluster/pglb/pool_process_query.c
> pgcluster-1.5.0rc7/src/pgcluster/pglb/pool_process_query.c
> +--- postgresql-8.1.2/src/pgcluster/pglb/pool_process_query.c 1970-01-01
> 01:00:00.000000000 +0100
> ++++ pgcluster-1.5.0rc7/src/pgcluster/pglb/pool_process_query.c
> 2006-02-02 22:32:08.000000000 +0100
> +@@ -0,0 +1,2100 @@
> ++/*--------------------------------------------------------------------
> ++ * FILE:
> ++ * pool_process_query.c
> ++ *
> ++ * NOTE:
> ++ * query processing stuff
> ++ *
> ++ * Portions Copyright (c) 2003-2006, Atsushi Mitani
> ++ * Portions Copyright (c) 2003-2006, 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 <errno.h>
> ++#include <sys/types.h>
> ++#include <sys/time.h>
> ++#include <arpa/inet.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 = 0;
> ++
> ++ /* 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;
> ++#endif
> ++
> ++ for (;;)
> ++ {
> ++ if (copyin)
> ++ {
> ++ if (MAJOR(backend) == PROTO_MAJOR_V3)
> ++ {
> ++ char kind;
> ++ POOL_STATUS status;
> ++
> ++ if (pool_read(frontend, &kind, 1) < 0)
> ++ return POOL_END;
> ++
> ++ status = SimpleForwardToBackend(kind,
> frontend, backend);
> ++ if (status == POOL_END)
> ++ return status;
> ++
> ++ /* CopyData? */
> ++ if (kind == 'd')
> ++ continue;
> ++ else
> ++ break;
> ++ }
> ++ else
> ++ {
> ++ string = pool_read_string(frontend, &len, 1);
> ++ if (string == NULL)
> ++ return POOL_END;
> ++ }
> ++ }
> ++ else
> ++ {
> ++ /* CopyOut */
> ++ if (MAJOR(backend) == PROTO_MAJOR_V3)
> ++ {
> ++ signed char kind;
> ++ POOL_STATUS status;
> ++
> ++ if ((kind = pool_read_kind(backend)) < 0)
> ++ return POOL_END;
> ++
> ++ status = SimpleForwardToFrontend(kind,
> frontend, backend);
> ++ if (status == POOL_END)
> ++ return status;
> ++
> ++ /* 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
> ++ buf = malloc(len + 1);
> ++ if (buf == NULL)
> ++ {
> ++ show_error("CopyDataRows: malloc failed: %s",
> strerror(errno));
> ++ return POOL_END;
> ++ }
> ++ strncpy(buf, string, len);
> ++ buf[len] = '\0';
> ++ show_debug("%s: copy line %d %d bytes :%s:",func, i++, len,
> buf);
> ++ free(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)
> ++ return 2;
> ++
> ++ if (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);
> ++}
> +diff -aruN postgresql-8.1.2/src/pgcluster/pglb/pool_stream.c
> pgcluster-1.5.0rc7/src/pgcluster/pglb/pool_stream.c
> +--- postgresql-8.1.2/src/pgcluster/pglb/pool_stream.c 1970-01-01
> 01:00:00.000000000 +0100
> ++++ pgcluster-1.5.0rc7/src/pgcluster/pglb/pool_stream.c 2006-02-02
> 22:30:03.000000000 +0100
> +@@ -0,0 +1,585 @@
> ++/*--------------------------------------------------------------------
> ++ * FILE:
> ++ * pool_stream.c
> ++ *
> ++ * NOTE:
> ++ * stream I/O modules
> ++ *
> ++ * Portions Copyright (c) 2003-2006, Atsushi Mitani
> ++ * Portions Copyright (c) 2003-2006 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 <stdio.h>
> ++#include <stdlib.h>
> ++#include <string.h>
> ++#include <errno.h>
> ++#include <sys/types.h>
> ++#include <unistd.h>
> ++#include <sys/time.h>
> ++
> ++#include "postgres_fe.h"
> ++#include "libpq/pqcomm.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)
> ++{
> ++ close(cp->fd);
> ++ 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;
> ++ char * ptr = (char *)buf;
> ++
> ++ consume_size = consume_pending_data(cp, ptr, len);
> ++ len -= consume_size;
> ++ ptr += 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(ptr, readbuf, len);
> ++ break;
> ++ }
> ++
> ++ memmove(ptr, readbuf, readlen);
> ++ ptr += 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;
> ++ }
> ++ }
> ++
> ++ if (readlen == 0)
> ++ 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;
> ++}
> +diff -aruN postgresql-8.1.2/src/pgcluster/pglb/recovery.c
> pgcluster-1.5.0rc7/src/pgcluster/pglb/recovery.c
> +--- postgresql-8.1.2/src/pgcluster/pglb/recovery.c 1970-01-01
> 01:00:00.000000000 +0100
> ++++ pgcluster-1.5.0rc7/src/pgcluster/pglb/recovery.c 2006-01-10
> 17:39:44.000000000 +0100
> +@@ -0,0 +1,234 @@
> ++/*--------------------------------------------------------------------
> ++ * 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-2006, 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.
> ++ *
> ++*/
> ++#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 <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("", 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,"",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;
> ++}
> +diff -aruN postgresql-8.1.2/src/pgcluster/pglb/socket.c
> pgcluster-1.5.0rc7/src/pgcluster/pglb/socket.c
> +--- postgresql-8.1.2/src/pgcluster/pglb/socket.c 1970-01-01
> 01:00:00.000000000 +0100
> ++++ pgcluster-1.5.0rc7/src/pgcluster/pglb/socket.c 2006-01-10
> 17:39:44.000000000 +0100
> +@@ -0,0 +1,395 @@
> ++/*--------------------------------------------------------------------
> ++ * FILE:
> ++ * socket.c
> ++ *
> ++ * NOTE:
> ++ * This file is composed of the communication modules
> ++ *
> ++ * Portions Copyright (c) 2003-2006, 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.
> ++ *
> ++*/
> ++#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 <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;
> ++}
> ++
> +diff -aruN postgresql-8.1.2/src/pgcluster/pgrp/AUTHORS
> pgcluster-1.5.0rc7/src/pgcluster/pgrp/AUTHORS
> +--- postgresql-8.1.2/src/pgcluster/pgrp/AUTHORS 1970-01-01
> 01:00:00.000000000 +0100
> ++++ pgcluster-1.5.0rc7/src/pgcluster/pgrp/AUTHORS 2006-01-10
> 17:39:44.000000000 +0100
> +@@ -0,0 +1,3 @@
> ++Authors of pglb
> ++
> ++pglb was written by Atsushi Mitani
> +diff -aruN postgresql-8.1.2/src/pgcluster/pgrp/COPYING
> pgcluster-1.5.0rc7/src/pgcluster/pgrp/COPYING
> +--- postgresql-8.1.2/src/pgcluster/pgrp/COPYING 1970-01-01
> 01:00:00.000000000 +0100
> ++++ pgcluster-1.5.0rc7/src/pgcluster/pgrp/COPYING 2006-01-10
> 17:39:44.000000000 +0100
> +@@ -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 -aruN postgresql-8.1.2/src/pgcluster/pgrp/Makefile
> pgcluster-1.5.0rc7/src/pgcluster/pgrp/Makefile
> +--- postgresql-8.1.2/src/pgcluster/pgrp/Makefile 1970-01-01
> 01:00:00.000000000 +0100
> ++++ pgcluster-1.5.0rc7/src/pgcluster/pgrp/Makefile 2006-01-31
> 15:14:33.000000000 +0100
> +@@ -0,0 +1,39 @@
> ++#-------------------------------------------------------------------------
> ++#
> ++# Makefile for src/pgcluster/pgrp
> ++#
> ++#-------------------------------------------------------------------------
> ++
> ++subdir = src/pgcluster/pgrp
> ++top_builddir = ../../..
> ++include $(top_builddir)/src/Makefile.global
> ++
> ++OBJS= pqformat.o cascade.o conf.o main.o recovery.o replicate.o rlog.o
> ++
> ++EXTRA_OBJS = $(top_builddir)/src/backend/libpq/replicate_com.o
> ++EXTRA_OBJS += ../libpgc/SUBSYS.o
> ++
> ++CFLAGS += -DPRINT_DEBUG -g
> ++override CPPFLAGS := -I$(libpq_srcdir) $(CPPFLAGS) -DBINDIR=\"$(bindir)\"
> ++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)$(datadir)/pgreplicate.conf.sample
> ++
> ++installdirs:
> ++ $(mkinstalldirs) $(DESTDIR)$(bindir)
> ++ $(mkinstalldirs) $(DESTDIR)$(datadir)
> ++
> ++uninstall:
> ++ rm -f $(addprefix $(DESTDIR)$(bindir)/, pgreplicate$(X))
> ++ rm -f $(DESTDIR)$(datadir)/pgreplicate.conf.sample
> ++
> ++clean distclean maintainer-clean:
> ++ rm -f pgreplicate$(X) $(OBJS)
> ++
> ++clean_obj:
> ++ rm -f $(OBJS)
> +diff -aruN postgresql-8.1.2/src/pgcluster/pgrp/README
> pgcluster-1.5.0rc7/src/pgcluster/pgrp/README
> +--- postgresql-8.1.2/src/pgcluster/pgrp/README 1970-01-01
> 01:00:00.000000000 +0100
> ++++ pgcluster-1.5.0rc7/src/pgcluster/pgrp/README 2006-01-10
> 17:39:44.000000000 +0100
> +@@ -0,0 +1,275 @@
> ++=============================================================
> ++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>
> ++<Rsync_Compress> yes </Rsync_Compress>
> ++<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 -aruN postgresql-8.1.2/src/pgcluster/pgrp/cascade.c
> pgcluster-1.5.0rc7/src/pgcluster/pgrp/cascade.c
> +--- postgresql-8.1.2/src/pgcluster/pgrp/cascade.c 1970-01-01
> 01:00:00.000000000 +0100
> ++++ pgcluster-1.5.0rc7/src/pgcluster/pgrp/cascade.c 2006-01-31
> 23:41:36.000000000 +0100
> +@@ -0,0 +1,948 @@
> ++/*--------------------------------------------------------------------
> ++ * 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-2006, 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"
> ++
> ++void PGRinit_cascade_child(void);
> ++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);
> ++int PGRsend_notice_quit(void);
> ++
> ++#if 0
> ++static int count_cascade(int flag);
> ++#endif
> ++
> ++static int fixup_socket_for_cascades(int *sock ,ReplicateServerInfo *
> target);
> ++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);
> ++
> ++/**
> ++ * socket variables, moved from Cascade_Inf->(lower|upper)->sock.
> ++ * Cascade->Inf is in shared memory, so sometimes cascades returns EBADF
> due to not initialized socket in specified process.
> ++ * 05/10/05 tanida AT sraoss.co.jp
> ++ */
> ++
> ++int lsock=-1; /* socket for lower-cascade. */
> ++int usock=-1; /* socket for upper-cascade. */
> ++
> ++/*--------------------------------------
> ++ * 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 != DB_TBL_END)
> ++ {
> ++ if (cascade->useFlag == DB_TBL_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 */
> ++
> ++void
> ++PGRinit_cascade_child(void) {
> ++ fixup_socket_for_cascades(&usock,NULL);
> ++ fixup_socket_for_cascades(&lsock,NULL);
> ++}
> ++
> ++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;
> ++ default:
> ++ free(buf);
> ++ *cnt = 0;
> ++ return NULL;
> ++
> ++ }
> ++
> ++ if (cascade == NULL)
> ++ {
> ++ free(buf);
> ++ *cnt = 0;
> ++ return NULL;
> ++ }
> ++ PGRsem_lock(CascadeSemID,1);
> ++ i = 0;
> ++ loop_cnt = 0;
> ++ while (cascade->useFlag != DB_TBL_END)
> ++ {
> ++ if (cascade->useFlag == DB_TBL_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;
> ++ PGRsem_unlock(CascadeSemID,1);
> ++
> ++ 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];
> ++
> ++
> ++#ifdef PRINT_DEBUG
> ++ show_debug("executing %s",func);
> ++#endif
> ++ 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 = DB_TBL_INIT;
> ++ fixup_socket_for_cascades(&usock,NULL);
> ++ fixup_socket_for_cascades(&lsock,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 = DB_TBL_END;
> ++ }
> ++ Cascade_Inf->useFlag = DB_TBL_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 = DB_TBL_INIT;
> ++ fixup_socket_for_cascades(&lsock,NULL);
> ++ 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);
> ++ cascade->replicate_id=-1;
> ++ cascade->response_mode=-1;
> ++
> ++ Cascade_Inf->end = cascade;
> ++
> ++ if
> ((!strncmp(cascade->hostName,hostName,sizeof(cascade->hostName))) &&
> ++ (cascade->portNumber == Port_Number) &&
> ++ (cascade->recoveryPortNumber == Recovery_Port_Number))
> ++ {
> ++ ptr ++;
> ++ cnt --;
> ++ continue;
> ++ }
> ++ cascade ++;
> ++ cascade->useFlag = DB_TBL_END;
> ++ ptr ++;
> ++ cnt --;
> ++ }
> ++ Cascade_Inf->useFlag = DB_TBL_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)
> ++ {
> ++ status=STATUS_ERROR;
> ++ }
> ++ else if((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);
> ++ }
> ++
> ++ }
> ++#ifdef PRINT_DEBUG
> ++ show_debug("%s:startup packet result is %d",func,status);
> ++#endif
> ++ return status;
> ++}
> ++
> ++int
> ++PGRsend_lower_cascade(ReplicateHeader * header, char * query)
> ++{
> ++
> ++
> ++ char * func = "PGRsend_lower_cascade()";
> ++ ReplicateServerInfo *lower = PGRget_lower_cascade();
> ++
> ++
> ++ while(lower!=NULL)
> ++ {
> ++ /**
> ++ * check lower_cascade validaty.
> ++ *
> ++ */
> ++ if(lsock!=-1 &&
> ++
> PGRsend_cascade(lsock,header,query)==STATUS_OK)
> ++ {
> ++ return STATUS_OK;
> ++ }
> ++ else
> ++ {
> ++ /**
> ++ * current lower cascade is
> missing.
> ++ * fix socket , or go to next
> one.
> ++ *
> ++ */
> ++ while( lower!=NULL &&
> ++
> fixup_socket_for_cascades(&lsock,lower)!=STATUS_OK)
> ++ {
> ++
> show_error("%s:lower cascade maybe down,challenge new one.",func);
> ++
> PGRset_cascade_server_status(lower,DB_TBL_ERROR);
> ++ lower
> =PGRget_lower_cascade();
> ++ }
> ++ }
> ++ Cascade_Inf->lower=lower;
> ++ }
> ++
> ++
> ++ return STATUS_ERROR;
> ++}
> ++
> ++
> ++int
> ++PGRsend_upper_cascade(ReplicateHeader * header, char * query)
> ++{
> ++ char * func = "PGRsend_upper_cascade()";
> ++ ReplicateServerInfo *upper = PGRget_upper_cascade();
> ++
> ++
> ++ while(upper!=NULL)
> ++ {
> ++ /**
> ++ * check upper_cascade validaty.
> ++ *
> ++ */
> ++ if(usock!=-1 &&
> ++ PGRsend_cascade(usock,header,query)==STATUS_OK)
> ++ {
> ++ return STATUS_OK;
> ++ }
> ++ else
> ++ {
> ++ /**
> ++ * current upper cascade is missing.
> ++ * fix socket , or go to next one.
> ++ *
> ++ */
> ++ while( upper!=NULL &&
> ++
> fixup_socket_for_cascades(&usock,upper)!=STATUS_OK)
> ++ {
> ++ show_error("%s:upper
> cascade maybe down,challenge new one.",func);
> ++
> PGRset_cascade_server_status(upper,DB_TBL_ERROR);
> ++ upper
> =PGRget_upper_cascade();
> ++ }
> ++ }
> ++ Cascade_Inf->upper=upper;
> ++ }
> ++
> ++ return STATUS_ERROR;
> ++}
> ++
> ++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 != DB_TBL_END)
> ++ {
> ++ cascade ++;
> ++ }
> ++ while (cascade->useFlag != DB_TBL_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 == DB_TBL_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 == DB_TBL_USE)
> ++ {
> ++ return cascade;
> ++ }
> ++ if (Cascade_Inf->top == cascade)
> ++ {
> ++ break;
> ++ }
> ++ cascade --;
> ++ }
> ++ return NULL;
> ++}
> ++
> ++static void
> ++write_cascade_status_file(ReplicateServerInfo * cascade)
> ++{
> ++ switch( cascade->useFlag)
> ++ {
> ++ case DB_TBL_FREE:
> ++ PGRwrite_log_file(StatusFp,"cascade(%s) port(%d)
> free",
> ++ cascade->hostName,
> ++ cascade->portNumber);
> ++ break;
> ++ case DB_TBL_INIT:
> ++ PGRwrite_log_file(StatusFp,"cascade(%s) port(%d)
> initialize",
> ++ cascade->hostName,
> ++ cascade->portNumber);
> ++ break;
> ++ case DB_TBL_USE:
> ++ PGRwrite_log_file(StatusFp,"cascade(%s) port(%d)
> start use",
> ++ cascade->hostName,
> ++ cascade->portNumber);
> ++ break;
> ++ case DB_TBL_ERROR:
> ++ PGRwrite_log_file(StatusFp,"cascade(%s) port(%d)
> error",
> ++ cascade->hostName,
> ++ cascade->portNumber);
> ++ break;
> ++ case DB_TBL_TOP:
> ++ PGRwrite_log_file(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;
> ++ int sock;
> ++
> ++ if ((cascade == NULL) || (header == NULL))
> ++ {
> ++ return NULL;
> ++ }
> ++
> ++ /* FIXME: ReplicateServerInfo->sock must be removed in cascading. */
> ++ if(cascade == Cascade_Inf->upper )
> ++ {
> ++ sock=usock;
> ++ }
> ++ else if (cascade == Cascade_Inf->lower )
> ++ {
> ++ sock=lsock;
> ++ }
> ++ else
> ++ {
> ++#ifdef PRINT_DEBUG
> ++ show_debug("PGRrecv_cascade_answer:receiving packet from sock not
> belogs to cascade->upper / lower. maybe missing .");
> ++#endif
> ++ sock=cascade->sock;
> ++ }
> ++ answer = (ReplicateServerInfo*)PGRread_packet(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 == -1))
> ++ {
> ++ 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;
> ++
> ++ for (;;)
> ++ {
> ++ 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 < 0)
> ++ {
> ++ if (errno == EINTR || errno == EAGAIN)
> ++ continue;
> ++
> ++ show_error("%s:select failed ,errno is %s",func ,
> strerror(errno));
> ++ free(buf);
> ++ return STATUS_ERROR;
> ++ }
> ++
> ++ if (rtn && FD_ISSET(sock, &wmask))
> ++ {
> ++ s = send(sock,send_ptr + send_size,buf_size -
> send_size ,0);
> ++ if (s < 0)
> ++ {
> ++ if (errno == EINTR || errno == EAGAIN)
> ++ continue;
> ++ else
> ++ {
> ++ show_error("%s:send failed:
> %d(%s)",func, errno, strerror(errno));
> ++ free(buf);
> ++ return STATUS_ERROR;
> ++ }
> ++ }
> ++ else if (s == 0)
> ++ {
> ++ show_error("%s:unexpected EOF", func);
> ++ 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;
> ++}
> ++/**
> ++ * fixup_socket_for_cascades checks socket's validaty.
> ++ * returns STATUS_OK if succeeded , or STATUS_ERROR if some error occured.
> ++ * if target is null , only close socket.
> ++ *
> ++ * originally written by tanida AT sraoss.co.jp
> ++ */
> ++static int
> ++fixup_socket_for_cascades(int *sock, ReplicateServerInfo *target)
> ++{
> ++ if (*sock > 0)
> ++ {
> ++ close(*sock);
> ++ *sock=-1;
> ++ }
> ++ if(target!=NULL) {
> ++ return
> PGR_Create_Socket_Connect(sock,target->hostName,target->portNumber);
> ++ }
> ++ return STATUS_OK;
> ++}
> ++
> ++
> ++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];
> ++ ReplicateServerInfo *s=NULL;
> ++
> ++ if (Cascade_Inf->lower == NULL)
> ++ {
> ++ Cascade_Inf->lower = PGRget_lower_cascade();
> ++ }
> ++ if (Cascade_Inf->lower == NULL)
> ++ {
> ++ return STATUS_ERROR;
> ++ }
> ++ s=Cascade_Inf->lower;
> ++ memset(userName,0,sizeof(userName));
> ++ strncpy(userName ,getenv("LOGNAME"),sizeof(userName)-1);
> ++
> ++ PGRnotice_replication_server(s->hostName,
> ++
> s->portNumber,
> ++
> s->recoveryPortNumber,
> ++
> s->lifecheckPortNumber,
> ++ userName);
> ++
> ++ return STATUS_OK;
> ++}
> ++
> ++int
> ++PGRwait_notice_rlog_done(void)
> ++{
> ++ ReplicateHeader header;
> ++ if (lsock != -1)
> ++ {
> ++ PGRread_packet(lsock,&header);
> ++ return STATUS_OK;
> ++ }
> ++ return STATUS_ERROR;
> ++
> ++}
> ++
> ++
> ++int
> ++PGRsend_notice_quit(void )
> ++{
> ++ ReplicateHeader header;
> ++ int size = 0;
> ++
> ++ size = strlen("QUIT_SAFELY");
> ++ memset(&header,0,sizeof(ReplicateHeader));
> ++ header.cmdSys = CMD_SYS_CALL ;
> ++ header.cmdSts = CMD_STS_RESPONSE ;
> ++ header.cmdType = CMD_TYPE_FRONTEND_CLOSED;
> ++ header.query_size = htonl(size);
> ++ PGRsend_lower_cascade(&header, "QUIT_SAFELY");
> ++ PGRwait_notice_rlog_done();
> ++ return STATUS_OK;
> ++}
> ++
> ++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 -aruN postgresql-8.1.2/src/pgcluster/pgrp/conf.c
> pgcluster-1.5.0rc7/src/pgcluster/pgrp/conf.c
> +--- postgresql-8.1.2/src/pgcluster/pgrp/conf.c 1970-01-01
> 01:00:00.000000000 +0100
> ++++ pgcluster-1.5.0rc7/src/pgcluster/pgrp/conf.c 2006-01-31
> 23:42:41.000000000 +0100
> +@@ -0,0 +1,602 @@
> ++/*--------------------------------------------------------------------
> ++ * FILE:
> ++ * conf.c
> ++ * Replication server for PostgreSQL
> ++ *
> ++ * NOTE:
> ++ * Read and set configuration data in this modul.
> ++ *
> ++ * Portions Copyright (c) 2003-2006, Atsushi Mitani
> ++ *--------------------------------------------------------------------
> ++ */
> ++#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 "libpq-int.h"
> ++#include "fe-auth.h"
> ++
> ++#include "replicate_com.h"
> ++#include "pgreplicate.h"
> ++
> ++int PGRget_Conf_Data(char * path);
> ++
> ++/*--------------------------------------------------------------------
> ++ * SYMBOL
> ++ * PGRget_Conf_Data()
> ++ * NOTES
> ++ * Initialize mamory and tables
> ++ * ARGS
> ++ * char * path: path of the setup file (I)
> ++ * RETURN
> ++ * OK: STATUS_OK
> ++ * NG: STATUS_ERROR
> ++ *--------------------------------------------------------------------
> ++ */
> ++int
> ++PGRget_Conf_Data(char * path)
> ++{
> ++ char * func = "PGRget_Conf_Data()";
> ++ 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 = ".";
> ++ }
> ++
> ++ LogFp = NULL;
> ++ if (Log_Print)
> ++ {
> ++
> snprintf(fname,sizeof(fname),"%s/%s",path,PGREPLICATE_LOG_FILE);
> ++ LogFp = fopen(fname,"a");
> ++ if (LogFp == NULL)
> ++ {
> ++ show_error("%s:fopen failed:
> (%s)",func,strerror(errno));
> ++ return STATUS_ERROR;
> ++ }
> ++#ifdef PRINT_DEBUG
> ++ show_debug("%s open ok\n",fname);
> ++#endif
> ++ }
> ++
> ++ snprintf(fname,sizeof(fname),"%s/%s",path,PGREPLICATE_STATUS_FILE);
> ++ StatusFp = fopen(fname,"a");
> ++ if (StatusFp == NULL)
> ++ {
> ++ show_error("%s:fopen failed: (%s)",func,strerror(errno));
> ++ return STATUS_ERROR;
> ++ }
> ++
> ++ snprintf(fname,sizeof(fname),"%s/%s",path,PGREPLICATE_RID_FILE);
> ++ RidFp = fopen(fname,"r+");
> ++ if (RidFp == NULL)
> ++ {
> ++ RidFp = fopen(fname,"w+");
> ++ if (RidFp == NULL)
> ++ {
> ++ show_error("%s:fopen failed:
> (%s)",func,strerror(errno));
> ++ return STATUS_ERROR;
> ++ }
> ++ }
> ++
> ++ /*
> ++ * 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;
> ++ }
> ++#ifdef PRINT_DEBUG
> ++ show_debug("PGR_Get_Conf_Data ok");
> ++#endif
> ++
> ++ /* 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
> ++ */
> ++ LoadBalanceTbl = (RecoveryTbl
> *)malloc(sizeof(RecoveryTbl)*MAX_DB_SERVER);
> ++ if (LoadBalanceTbl == (RecoveryTbl *)NULL)
> ++ {
> ++ show_error("%s:malloc failed: (%s)",func,strerror(errno));
> ++ return STATUS_ERROR;
> ++ }
> ++#ifdef PRINT_DEBUG
> ++ show_debug("LoadBalanceTbl allocate ok");
> ++#endif
> ++
> ++ /*
> ++ * 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;
> ++ }
> ++#ifdef PRINT_DEBUG
> ++ show_debug("%s:CascadeTbl shmget ok",func);
> ++#endif
> ++ 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;
> ++ }
> ++#ifdef PRINT_DEBUG
> ++ show_debug("%s:CascadeTbl shmat ok",func);
> ++#endif
> ++ 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;
> ++ }
> ++#ifdef PRINT_DEBUG
> ++ show_debug("%s:CascadeInf shmget ok",func);
> ++#endif
> ++ 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;
> ++ }
> ++#ifdef PRINT_DEBUG
> ++ show_debug("%s:CascadeInf shmat ok",func);
> ++#endif
> ++ 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;
> ++ }
> ++#ifdef PRINT_DEBUG
> ++ show_debug("%s:CommitLog shmget ok",func);
> ++#endif
> ++ 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;
> ++ }
> ++#ifdef PRINT_DEBUG
> ++ show_debug("%s:Commit_Log_Tbl shmat ok",func);
> ++#endif
> ++ memset(Commit_Log_Tbl , 0 , size );
> ++ (Commit_Log_Tbl + (MAX_DB_SERVER * MAX_CONNECTIONS) -1)->inf.useFlag
> = DB_TBL_END;
> ++
> ++ /* create semapho */
> ++ if ((SemID = semget(IPC_PRIVATE,2,IPC_CREAT | IPC_EXCL | 0600)) < 0)
> ++ {
> ++ show_error("%s:semget() failed. (%s)",func,strerror(errno));
> ++ return STATUS_ERROR;
> ++ }
> ++ for ( i = 0 ; i < 2 ; i ++)
> ++ {
> ++ semctl(SemID, i, GETVAL, sem_arg);
> ++ sem_arg.val = 1;
> ++ semctl(SemID, i, SETVAL, sem_arg);
> ++ }
> ++
> ++ /* create semapho */
> ++ if ((CascadeSemID = semget(IPC_PRIVATE,2,IPC_CREAT | IPC_EXCL |
> 0600)) < 0)
> ++ {
> ++ show_error("%s:semget() failed. (%s)",func,strerror(errno));
> ++ return STATUS_ERROR;
> ++ }
> ++ for ( i = 0 ; i < 2 ; i ++)
> ++ {
> ++ semctl(CascadeSemID, i, GETVAL, sem_arg);
> ++ sem_arg.val = 1;
> ++ semctl(CascadeSemID, i, SETVAL, sem_arg);
> ++ }
> ++
> ++
> ++ if ((VacuumSemID = semget(IPC_PRIVATE,2,IPC_CREAT | IPC_EXCL | 0600))
> < 0)
> ++ {
> ++ show_error("%s:semget() failed. (%s)",func,strerror(errno));
> ++ return STATUS_ERROR;
> ++ }
> ++ for ( i = 0 ; i < 2 ; i ++)
> ++ {
> ++ semctl(VacuumSemID, i, GETVAL, sem_arg);
> ++ sem_arg.val = 1;
> ++ semctl(VacuumSemID, 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;
> ++#ifdef PRINT_DEBUG
> ++ show_debug("%s:RLog Memory Allocation ok",func);
> ++#endif
> ++
> ++
> ++ /*
> ++ * set each datas into the tables
> ++ */
> ++ conf = ConfData_Top;
> ++ while (conf != (ConfDataType *)NULL)
> ++ {
> ++#ifdef PRINT_DEBUG
> ++ show_debug("registering
> (key,value)=(%s,%s)",conf->key,conf->value);
> ++#endif
> ++ /* 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))
> ++ {
> ++ int ip;
> ++
> memcpy(host_tbl[rec_no].hostName,conf->value,sizeof(host_tbl[rec_no].hostName));
> ++#ifdef PRINT_DEBUG
> ++ show_debug("registering hostname
> %s",host_tbl[rec_no].hostName);
> ++#endif
> ++ ip=PGRget_ip_by_name(conf->value);
> ++
> ++ sprintf(host_tbl[rec_no].resolvedName,
> ++ "%d.%d.%d.%d",
> ++ (ip ) & 0xff ,
> ++ (ip >> 8) & 0xff ,
> ++ (ip >> 16) & 0xff ,
> ++ (ip >> 24) & 0xff );
> ++#ifdef PRINT_DEBUG
> ++ show_debug("resolved name is
> %s",host_tbl[rec_no].resolvedName);
> ++#endif
> ++ 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;
> ++ }
> ++ }
> ++ /* 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))
> ++ {
> ++
> memcpy((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;
> ++ }
> ++ (Cascade_Tbl+cascade_rec_no)->sock = -1;
> ++
> ++ conf = (ConfDataType*)conf->next;
> ++
> PGRset_cascade_server_status(Cascade_Tbl+cascade_rec_no,DB_TBL_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;
> ++ }
> ++ (Cascade_Tbl+cascade_rec_no)->rlog_sock=-1;
> ++ (Cascade_Tbl+cascade_rec_no +1)->useFlag =
> DB_TBL_END;
> ++ 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))
> ++ {
> ++ memcpy((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)->recoveryPort =
> atoi(conf->value);
> ++ (LoadBalanceTbl + lb_rec_no)->sock = -1;
> ++ (LoadBalanceTbl + lb_rec_no)->recovery_sock =
> -1;
> ++ conf = (ConfDataType*)conf->next;
> ++ continue;
> ++ }
> ++ }
> ++ else
> ++ {
> ++ if (!strcmp(conf->key,REPLICATE_PORT_TAG))
> ++ {
> ++ Port_Number = atoi(conf->value);
> ++ conf = (ConfDataType*)conf->next;
> ++ continue;
> ++ }
> ++ /* get port number for recovery cluster db server */
> ++ 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;
> ++ }
> ++ conf = (ConfDataType*)conf->next;
> ++ }
> ++ conf = (ConfDataType*)conf->next;
> ++ }
> ++
> ++
> ++ /* 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;
> ++ }
> ++#ifdef PRINT_DEBUG
> ++ show_debug("%s:HostTbl shmget ok",func);
> ++#endif
> ++ 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;
> ++ }
> ++#ifdef PRINT_DEBUG
> ++ show_debug("%s:HostTbl shmat ok",func);
> ++#endif
> ++ memset(Host_Tbl_Begin , 0 , size );
> ++ Host_Tbl_Begin -> useFlag = DB_TBL_END;
> ++
> ++ for ( i = 0 ; i <= cnt ; i ++)
> ++ {
> ++ PGRadd_HostTbl(&host_tbl[i],DB_TBL_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 (size);
> ++ 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);
> ++ 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 =
> Recovery_Port_Number;
> ++ (Cascade_Tbl+cascade_rec_no)->sock = -1;
> ++
> ++ PGRset_cascade_server_status(Cascade_Tbl+cascade_rec_no,DB_TBL_USE);
> ++ /* terminate */
> ++ (Cascade_Tbl+(cascade_rec_no+1))->useFlag = DB_TBL_END;
> ++
> ++ Cascade_Inf->top = Cascade_Tbl;
> ++ Cascade_Inf->end = Cascade_Tbl+cascade_rec_no;
> ++ Cascade_Inf->upper = NULL;
> ++ Cascade_Inf->lower = NULL;
> ++ if (cascade_rec_no >= 1)
> ++ {
> ++ Cascade_Inf->upper = (Cascade_Tbl+cascade_rec_no - 1);
> ++ }
> ++ (Cascade_Tbl+(cascade_rec_no+1))->useFlag = DB_TBL_END;
> ++
> ++ Cascade_Inf->myself = (Cascade_Tbl+cascade_rec_no);
> ++ Cascade_Inf->useFlag = DB_TBL_USE;
> ++
> ++ PGR_Response_Inf->response_mode = PGR_NORMAL_MODE;
> ++
> ++ return STATUS_OK;
> ++}
> ++
> +diff -aruN postgresql-8.1.2/src/pgcluster/pgrp/main.c
> pgcluster-1.5.0rc7/src/pgcluster/pgrp/main.c
> +--- postgresql-8.1.2/src/pgcluster/pgrp/main.c 1970-01-01
> 01:00:00.000000000 +0100
> ++++ pgcluster-1.5.0rc7/src/pgcluster/pgrp/main.c 2006-01-31
> 23:40:32.000000000 +0100
> +@@ -0,0 +1,1001 @@
> ++/*--------------------------------------------------------------------
> ++ * FILE:
> ++ * main.c
> ++ * Replication server for PostgreSQL
> ++ *
> ++ * NOTE:
> ++ * This is the main module of the replication server.
> ++ *
> ++ * Portions Copyright (c) 2003-2006, Atsushi Mitani
> ++ *--------------------------------------------------------------------
> ++ */
> ++#include "postgres.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>
> ++#include <pthread.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 */
> ++
> ++ConfDataType * ConfData_Top = (ConfDataType *)NULL;
> ++ConfDataType * ConfData_End = (ConfDataType *)NULL;
> ++
> ++/* replication server data */
> ++uint16_t Port_Number = 0;
> ++uint16_t LifeCheck_Port_Number = 0;
> ++uint16_t Recovery_Port_Number = 0;
> ++bool PGR_Parse_Session_Started = false;
> ++
> ++/* global table data */
> ++HostTbl *Host_Tbl_Begin = NULL;
> ++Dllist * Transaction_Tbl_Begin = NULL;
> ++TransactionTbl * Transaction_Tbl_End = NULL;
> ++RecoveryTbl * LoadBalanceTbl = NULL;
> ++RecoveryStatusInf * Recovery_Status_Inf = 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 ReplicateSerializationShmid=0;
> ++int RecoveryMsgShmid = 0;
> ++int *RecoveryMsgid = NULL;
> ++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 RecovErysemid = 0;
> ++int VacuumSemID = 0;
> ++int CascadeSemID= 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;
> ++bool exit_processing = false;
> ++int pgreplicate_pid = 0;
> ++
> ++int ReplicateSock = -1;
> ++
> ++RecoveryQueueInf RecoveryQueue;
> ++char * Backend_Socket_Dir = NULL;
> ++
> ++unsigned int * PGR_ReplicateSerializationID = NULL;
> ++
> ++int Log_Print = 0;
> ++int Debug_Print = 0;
> ++FILE * LogFp = (FILE *)NULL;
> ++FILE * StatusFp = (FILE *)NULL;
> ++FILE * RidFp = (FILE *)NULL;
> ++
> ++extern char *optarg;
> ++char * PGRuserName = NULL;
> ++
> ++int fork_wait_time = 0;
> ++int Idle_Flag = IDLE_MODE;
> ++bool Exit_Request = false;
> ++
> ++pthread_mutex_t transaction_table_mutex;
> ++
> ++/*--------------------------------------
> ++ * 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 void stop_pgreplicate(void);
> ++static bool is_exist_pid_file(void);
> ++static void usage(void);
> ++
> ++/*--------------------------------------------------------------------
> ++ * 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;
> ++ int cnt = 0;
> ++ int result;
> ++ bool exist_sys_log=false;
> ++ bool exist_replicate=false;
> ++
> ++
> ++ result = PGR_Create_Acception(fd,&sock,"",Port_Number);
> ++ if (result == STATUS_ERROR)
> ++ {
> ++ show_error("%s: accept failed (%s)", func, strerror(errno));
> ++ if (sock != -1)
> ++ close(sock);
> ++ return 1;
> ++ }
> ++
> ++ 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;
> ++ ReplicateHeader header_save_for_recovering;
> ++ char * query = NULL;
> ++
> ++ if (fork_wait_time > 0) {
> ++#ifdef PRINT_DEBUG
> ++ show_debug("wait fork(): pid = %d", getpid());
> ++#endif
> ++ sleep(fork_wait_time);
> ++ }
> ++
> ++ close(fd);
> ++
> ++ signal(SIGHUP, quick_exit);
> ++ signal(SIGINT, quick_exit);
> ++ signal(SIGQUIT, quick_exit);
> ++ signal(SIGTERM, quick_exit);
> ++ signal(SIGALRM, quick_exit);
> ++ signal(SIGPIPE, SIG_IGN);
> ++ setpgid(0,pgid);
> ++
> ++ if (PGRinit_transaction_table() != STATUS_OK)
> ++ {
> ++ show_error("transaction table memory allocate
> failed");
> ++ PGR_Close_Sock(&sock);
> ++ exit(1);
> ++ }
> ++
> ++ pthread_mutex_init(&transaction_table_mutex, NULL);
> ++
> ++ /* child loop */
> ++ for (;;)
> ++ {
> ++ fd_set rmask;
> ++ struct timeval timeout;
> ++
> ++ timeout.tv_sec = PGR_RECV_TIMEOUT;
> ++ 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 < 0)
> ++ {
> ++ if (errno == EINTR)
> ++ continue;
> ++ }
> ++
> ++ if (rtn && FD_ISSET(sock, &rmask))
> ++ {
> ++ query = NULL;
> ++ query = PGRread_packet(sock,&header);
>
> ++ if ((query == NULL) || (header.cmdSts == 0))
> ++ {
> ++
> ++ if (exist_sys_log)
> ++ {
> ++ show_error("%s:upper cascade
> closed? , errno=%d(%s)",func,errno,strerror(errno));
> ++ 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
> ++ {
> ++ int recovery_status =
> PGRget_recovery_status();
> ++#ifdef PRINT_DEBUG
> ++ show_debug("%s:session
> closed",func);
> ++#endif
> ++ if (recovery_status ==
> RECOVERY_START)
> ++ {
> ++
> header_save_for_recovering.cmdSts=CMD_TYPE_OTHER;
> ++
> header_save_for_recovering.cmdType=CMD_TYPE_CONNECTION_CLOSE;
> ++
> header_save_for_recovering.query_size = htonl(21);
> ++
> PGRdo_replicate(sock,&header_save_for_recovering,"PGR_CLOSE_CONNECTION");
> ++ }
> ++
> ++ if(exist_replicate)
> ++ {
> ++ int recovery_status =
> 0;
> ++
> ++
> PGRsem_lock(RecoverySemID,SEM_NUM_OF_RECOVERY);
> ++ if
> (Recovery_Status_Inf->transaction_count > 0)
> ++ {
> ++
> Recovery_Status_Inf->transaction_count --;
> ++ }
> ++
> PGRsem_unlock(RecoverySemID, SEM_NUM_OF_RECOVERY);
>
> ++#ifdef PRINT_DEBUG
> ++
> show_debug("transaction_status: %d",Recovery_Status_Inf->transaction_count);
> ++#endif
> ++
> recovery_status=PGRget_recovery_status();
> ++
> header_save_for_recovering.cmdSts=CMD_TYPE_OTHER;
> ++
> header_save_for_recovering.cmdType=CMD_TYPE_CONNECTION_CLOSE;
> ++
> header_save_for_recovering.query_size = htonl(21);
> ++
> PGRdo_replicate(sock,&header_save_for_recovering,"PGR_CLOSE_CONNECTION");
> ++ }
> ++ PGRsend_notice_quit();
> ++ }
> ++ break;
> ++ }
> ++ cnt = 0;
> ++ memcpy(&header_save_for_recovering,
> ++ &header,
> ++ sizeof(ReplicateHeader));
> ++ switch (header.cmdSys)
> ++ {
> ++ case CMD_SYS_PREREPLICATE:
> ++
> if(Cascade_Inf!=NULL ||
> ++
> Cascade_Inf->upper == NULL)
> ++ {
> ++
> /* 1 means "I am primary replicate server." */
> ++
> PGRreturn_result(sock,"1", PGR_NOWAIT_ANSWER);
> ++ }
> ++ else
> ++ {
> ++
> /* 1 means "I am not primary replicate server." */
> ++
> PGRreturn_result(sock,"0", PGR_NOWAIT_ANSWER);
> ++ }
> ++ break;
> ++ case CMD_SYS_REPLICATE:
> ++ status =
> PGRdo_replicate(sock,&header,query);
> ++ if
> (header.cmdSts == CMD_STS_TRANSACTION )
> ++ {
> ++
> switch(header.cmdType)
> ++
> {
> ++
> case CMD_TYPE_BEGIN:
> ++
> exist_replicate=true;
> ++
> memcpy(&header_save_for_recovering,
> ++
> &header,
> ++
> sizeof(ReplicateHeader));
> ++
> break;
> ++
> case CMD_TYPE_COMMIT:
> ++
> case CMD_TYPE_ROLLBACK:
> ++
> exist_replicate=false;
> ++
> break;
> ++
> }
> ++ }
> ++ else
> ++ {
> ++
> if ( header.cmdType == CMD_TYPE_COPY )
> ++
> {
> ++
> exist_replicate=true;
> ++
> memcpy(&header_save_for_recovering,
> ++
> &header,
> ++
> sizeof(ReplicateHeader));
> ++
> }
> ++
> else if (header.cmdType == CMD_TYPE_COPY_DATA_END)
> ++
> {
> ++
> exist_replicate=false;
> ++
> }
> ++ }
> ++
> ++ break;
> ++ case CMD_SYS_LOG:
> ++ exist_sys_log
> = true;
> ++
> PGRsend_rlog_to_local(&header, query);
> ++ /* set own
> replicate id by rlog */
> ++
> PGRset_replication_id(ntohl(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)
> ++ {
> ++
> if (header.cmdType == CMD_TYPE_FRONTEND_CLOSED)
> ++
> {
> ++
> header_save_for_recovering.cmdSts=CMD_TYPE_OTHER;
> ++
> header_save_for_recovering.cmdType=CMD_TYPE_CONNECTION_CLOSE;
> ++
> header_save_for_recovering.query_size = htonl(21);
> ++
>
> PGRdo_replicate(sock,&header_save_for_recovering,"PGR_CLOSE_CONNECTION");
> ++
> }
> ++
> else
> ++
> {
> ++
> PGRreconfirm_commit(sock,&header);
> ++
> }
> ++ }
> ++ else if
> (header.cmdSts == CMD_STS_NOTICE)
> ++ {
> ++
> ++ }
> ++ else if
> (header.cmdSts == CMD_STS_RESPONSE)
> ++ {
> ++
> if (header.cmdType == CMD_TYPE_FRONTEND_CLOSED)
> ++
> {
> ++#ifdef PRINT_DEBUG
> ++
> show_debug("replicate_loop ends due to frontend_closed.");
> ++#endif
> ++
> PGRsend_notice_rlog_done(sock);
> ++
> status = LOOP_END;
> ++
> }
> ++ }
> ++ break;
> ++ default:
> ++#ifdef PRINT_DEBUG
> ++
> show_debug("WARNING: unknown Header->cmdSys %c",header.cmdSys);
> ++#endif
> ++ }
> ++ }
> ++ if (status == LOOP_END)
> ++ {
> ++ break;
> ++ }
> ++ }
> ++
> ++ pthread_mutex_destroy(&transaction_table_mutex);
> ++ PGR_Close_Sock(&sock);
> ++ if (query != NULL)
> ++ {
> ++ free(query);
> ++ query = NULL;
> ++ }
> ++ PGRclear_connections();
> ++#ifdef PRINT_DEBUG
> ++ show_debug("%s:replicate loop exit",func);
> ++#endif
> ++ exit(0);
> ++ }
> ++ else
> ++ {
> ++ PGR_Close_Sock(&sock);
> ++ return 0;
> ++ }
> ++}
> ++
> ++static void
> ++startup_replication_server(void)
> ++{
> ++ ReplicateHeader header;
> ++ char hostName[HOSTNAME_MAX_LENGTH];
> ++ char userName[USERNAME_MAX_LENGTH];
> ++ char query[256];
> ++
> ++ if (PGRuserName == NULL)
> ++ {
> ++ PGRuserName = getenv("LOGNAME");
> ++ if (PGRuserName == NULL)
> ++ {
> ++ PGRuserName = getenv("USER");
> ++ if (PGRuserName == NULL)
> ++ PGRuserName = "postgres";
> ++ }
> ++ }
> ++ memset(&header,0,sizeof(ReplicateHeader));
> ++ memset(query,0,sizeof(query));
> ++ memset(hostName,0,sizeof(hostName));
> ++ memset(userName,0,sizeof(userName));
> ++ gethostname(hostName,sizeof(hostName)-1);
> ++ strncpy(userName ,PGRuserName,sizeof(userName)-1);
> ++ snprintf(query,sizeof(query)-1,"SELECT %s(%d,'%s',%d,%d)",
> ++ PGR_SYSTEM_COMMAND_FUNC,
> ++ PGR_STARTUP_REPLICATION_SERVER_FUNC_NO,
> ++ hostName,
> ++ Port_Number,
> ++ Recovery_Port_Number);
> ++ header.cmdSts = CMD_STS_NOTICE;
> ++ header.query_id = htonl(PGRget_next_query_id());
> ++ header.query_size = htonl(strlen(query));
> ++ memcpy(header.from_host,hostName,sizeof(header.from_host));
> ++ memcpy(header.userName,userName,sizeof(header.userName));
> ++ strcpy(header.dbName,"template1");
> ++ replicate_packet_send_internal( &header,
> query,-1,PGRget_recovery_status(),true);
> ++}
> ++
> ++/*--------------------------------------------------------------------
> ++ * SYMBOL
> ++ * replicate_main()
> ++ * NOTES
> ++ * Replication main module
> ++ * ARGS
> ++ * void
> ++ * RETURN
> ++ * none
> ++ *--------------------------------------------------------------------
> ++ */
> ++static void
> ++replicate_main(void)
> ++{
> ++#ifdef PRINT_DEBUG
> ++ char * func = "replicate_main()";
> ++#endif
> ++ int status;
> ++ int rtn;
> ++
> ++ /* cascade start up notice */
> ++ if (Cascade_Inf->upper != NULL)
> ++ {
> ++#ifdef PRINT_DEBUG
> ++ show_debug("initialize cascade information");
> ++#endif
> ++ PGRstartup_cascade();
> ++ }
> ++
> ++ status = PGR_Create_Socket_Bind(&ReplicateSock, "", Port_Number);
> ++
> ++ if (status != STATUS_OK)
> ++ {
> ++#ifdef PRINT_DEBUG
> ++ show_debug("%s %d port bind failed. quit.",func,Port_Number);
> ++#endif
> ++ stop_pgreplicate();
> ++ PGRreplicate_exit(0);
> ++ }
> ++#ifdef PRINT_DEBUG
> ++ show_debug("%s %d port bind OK",func,Port_Number);
> ++#endif
> ++
> ++
> ++ /* replication start up notice */
> ++ startup_replication_server();
> ++
> ++ for (;;)
> ++ {
> ++ fd_set rmask;
> ++ struct timeval timeout;
> ++
> ++ if (exit_processing == true)
> ++ PGRreplicate_exit(0);
> ++
> ++ timeout.tv_sec = PGR_RECV_TIMEOUT;
> ++ timeout.tv_usec = 0;
> ++
> ++
> ++ /*
> ++ * Wait for something to happen.
> ++ */
> ++ FD_ZERO(&rmask);
> ++ FD_SET(ReplicateSock,&rmask);
> ++ rtn = select(ReplicateSock+1, &rmask, (fd_set *)NULL, (fd_set
> *)NULL, &timeout);
> ++ if (rtn < 0)
> ++ continue;
> ++
> ++ if (rtn && FD_ISSET(ReplicateSock, &rmask))
> ++ {
> ++ /*
> ++ * get recovery status.
> ++ */
> ++ PGRcheck_recovered_host();
> ++
> ++ if (exit_processing == true)
> ++ break;
> ++
> ++ /*
> ++ * call replication module
> ++ */
> ++ replicate_loop(ReplicateSock);
> ++ }
> ++ }
> ++}
> ++
> ++/*--------------------------------------------------------------------
> ++ * SYMBOL
> ++ * quick_exit()
> ++ * NOTES
> ++ * Exit child process
> ++ * ARGS
> ++ * SIGNAL_ARGS: receive signal number(I)
> ++ * RETURN
> ++ * none
> ++ *--------------------------------------------------------------------
> ++ */
> ++static void
> ++quick_exit(SIGNAL_ARGS)
> ++{
> ++#ifdef PRINT_DEBUG
> ++ show_debug("quick_exit:signo = %d", postgres_signal_arg);
> ++#endif
> ++ 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
> ++ * stop_pgreplicate()
> ++ * NOTES
> ++ * Stop the pgreplicate process
> ++ * ARGS
> ++ * void
> ++ * RETURN
> ++ * none
> ++ *--------------------------------------------------------------------
> ++ */
> ++static void
> ++stop_pgreplicate(void)
> ++{
> ++ char * func = "stop_pgreplicate()";
> ++ FILE *fd;
> ++ char fname[256];
> ++ char pidbuf[128];
> ++ pid_t pid;
> ++
> ++ 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,SIGTERM) == -1)
> ++ {
> ++ show_error("%s:could not stop pid: %d, reason:
> %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 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
> ++ *--------------------------------------------------------------------
> ++ */
> ++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]\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");
> ++}
> ++
> ++/*--------------------------------------------------------------------
> ++ * 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 rlog_pid;
> ++
> ++ r_path = getenv("PGDATA");
> ++ if (r_path == NULL)
> ++ r_path = ".";
> ++ while ((opt = getopt(argc, argv, "U:D:W:w: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 'w':
> ++ fork_wait_time = atoi(optarg);
> ++ break;
> ++ case 'l':
> ++ Log_Print = 1;
> ++ break;
> ++ case 'v':
> ++ 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) && !strncasecmp(argv[optind],"stop",4))
> ++ {
> ++ stop_pgreplicate();
> ++ exit(0);
> ++ }
> ++ 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();
> ++ pgreplicate_pid = getpid();
> ++
> ++ signal(SIGINT, set_exit_processing);
> ++ signal(SIGQUIT, set_exit_processing);
> ++ signal(SIGTERM, set_exit_processing);
> ++ signal(SIGCHLD, child_wait);
> ++ signal(SIGPIPE, SIG_IGN);
> ++
> ++ if (PGRget_Conf_Data(PGR_Data_Path) != STATUS_OK)
> ++ {
> ++ show_error("%s:PGRget_Conf_Data error",func);
> ++ PGRreplicate_exit(0);
> ++ }
> ++ if (PGRinit_recovery() != STATUS_OK)
> ++ {
> ++ show_error("%s:PGRinit_recovery error",func);
> ++ PGRreplicate_exit(0);
> ++ }
> ++ if (PGRload_replication_id() != STATUS_OK)
> ++ {
> ++ show_error("%s:PGRload_replication_id error",func);
> ++ PGRreplicate_exit(0);
> ++ }
> ++
> ++ pgid = getpgid(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);
> ++ }
> ++ }
> ++
> ++ pid = fork();
> ++ if (pid == (pid_t) -1)
> ++ {
> ++ show_error("%s:fork() failed. reason: %s",
> func,strerror(errno));
> ++ exit(1);
> ++ }
> ++ if (pid == 0)
> ++ {
> ++ signal(SIGCHLD, SIG_DFL);
> ++ signal(SIGHUP, quick_exit);
> ++ 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);
> ++
> ++ if (fork_wait_time > 0) {
> ++#ifdef PRINT_DEBUG
> ++ show_debug("recovery process: wait fork(): pid = %d",
> getpid());
> ++#endif
> ++ sleep(fork_wait_time);
> ++ }
> ++
> ++ PGRrecovery_main();
> ++ }
> ++ else
> ++ {
> ++ /*
> ++ * call replicate module
> ++ */
> ++ Replicateion_Log->r_log_sock =-1;
> ++
> ++ if (fork_wait_time > 0) {
> ++#ifdef PRINT_DEBUG
> ++ show_debug("replicate process: wait fork(): pid =
> %d", getpid());
> ++#endif
> ++ sleep(fork_wait_time);
> ++ }
> ++
> ++ replicate_main();
> ++ }
> ++
> ++ PGRreplicate_exit(0);
> ++ return STATUS_OK;
> ++}
> ++
> +diff -aruN postgresql-8.1.2/src/pgcluster/pgrp/pgreplicate.conf.sample
> pgcluster-1.5.0rc7/src/pgcluster/pgrp/pgreplicate.conf.sample
> +--- postgresql-8.1.2/src/pgcluster/pgrp/pgreplicate.conf.sample
> 1970-01-01 01:00:00.000000000 +0100
> ++++ pgcluster-1.5.0rc7/src/pgcluster/pgrp/pgreplicate.conf.sample
> 2006-02-09 17:55:02.000000000 +0100
> +@@ -0,0 +1,84 @@
> ++#=============================================================
> ++# 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
> ++#=============================================================
> ++#
> ++#-------------------------------------------------------------
> ++# 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 .
> ++#-------------------------------------------------------------
> ++#<Cluster_Server_Info>
> ++# <Host_Name> master.postgres.jp </Host_Name>
> ++# <Port> 5432 </Port>
> ++# <Recovery_Port> 7001 </Recovery_Port>
> ++#</Cluster_Server_Info>
> ++#<Cluster_Server_Info>
> ++# <Host_Name> cluster2.postgres.jp </Host_Name>
> ++# <Port> 5432 </Port>
> ++# <Recovery_Port> 7001 </Recovery_Port>
> ++#</Cluster_Server_Info>
> ++#<Cluster_Server_Info>
> ++# <Host_Name> cluster3.postgres.jp </Host_Name>
> ++# <Port> 5432 </Port>
> ++# <Recovery_Port> 7001 </Recovery_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 .
> ++#-------------------------------------------------------------
> ++#<LoadBalance_Server_Info>
> ++# <Host_Name> loadbalancer.postgres.jp </Host_Name>
> ++# <Recovery_Port> 6001 </Recovery_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 .
> ++#------------------------------------------------------------
> ++#<Replicate_Server_Info>
> ++# <Host_Name> upper_replicate.postgres.jp </Host_Name>
> ++# <Port> 8002 </Port>
> ++# <Recovery_Port> 8102 </Recovery_Port>
> ++#</Replicate_Server_Info>
> ++#
> ++#-------------------------------------------------------------
> ++# A setup of a replication server
> ++#
> ++# o Replicate_Port : connection for replication
> ++# o Recovery_Port : connection for recovery
> ++# 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 : use replication log
> ++# [yes/no]. default : no
> ++# o RLOG_Port : connection for replication log
> ++#-------------------------------------------------------------
> ++<Replication_Port> 8001 </Replication_Port>
> ++<Recovery_Port> 8101 </Recovery_Port>
> ++<Response_Mode> normal </Response_Mode>
> ++<Use_Replication_Log> no </Use_Replication_Log>
> ++<RLOG_Port> 8301 </RLOG_Port>
> +diff -aruN postgresql-8.1.2/src/pgcluster/pgrp/pgreplicate.h
> pgcluster-1.5.0rc7/src/pgcluster/pgrp/pgreplicate.h
> +--- postgresql-8.1.2/src/pgcluster/pgrp/pgreplicate.h 1970-01-01
> 01:00:00.000000000 +0100
> ++++ pgcluster-1.5.0rc7/src/pgcluster/pgrp/pgreplicate.h 2006-02-09
> 17:46:34.000000000 +0100
> +@@ -0,0 +1,414 @@
> ++/*--------------------------------------------------------------------
> ++ * FILE:
> ++ * pgreplicate.h
> ++ *
> ++ * Portions Copyright (c) 2003-2006, Atsushi Mitani
> ++ *--------------------------------------------------------------------
> ++ */
> ++#ifndef PGREPLICATE_H
> ++#define PGREPLICATE_H
> ++
> ++#define PGREPLICATE_VERSION "1.5.0rc7"
> ++
> ++#include "lib/dllist.h"
> ++#include "lib/stringinfo.h"
> ++#include "../libpgc/libpgc.h"
> ++
> ++/* 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 'A'
> ++
> ++/* 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 INIT_TRANSACTION_TBL_NUM (12)
> ++#define MAX_HOST_NAME_LEN (128)
> ++#define MAX_DB_SERVER (32)
> ++#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 DB_TBL_FREE (0)
> ++#define DB_TBL_INIT (1)
> ++#define DB_TBL_USE (2)
> ++#define DB_TBL_ERROR (-1)
> ++#define DB_TBL_TOP (10)
> ++#define DB_TBL_END (11)
> ++#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 PGREPLICATE_RID_FILE "pgreplicate.rid"
> ++#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 (6000)
> ++#define PGR_RECOVERY_WAIT_MSEC (500)
> ++#define PGR_CHECK_POINT (300)
> ++
> ++#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;
> ++ int lock;
> ++ int transaction_count;
> ++ 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];
> ++ bool in_transaction;
> ++ PGconn * conn;
> ++}TransactionTbl;
> ++
> ++/*
> ++ * cluster server table
> ++ */
> ++typedef struct {
> ++ int useFlag;
> ++ char hostName[HOSTNAME_MAX_LENGTH];
> ++ char resolvedName[21];
> ++ int port;
> ++ int recoveryPort;
> ++ int hostNum;
> ++ int transaction_count;
> ++}HostTbl;
> ++
> ++
> ++typedef struct {
> ++ FILE * queue_fp;
> ++ int current_queue_no;
> ++} RecoveryQueueInf;
> ++
> ++
> ++/*
> ++ * host table for recovery request
> ++ */
> ++typedef struct {
> ++ char hostName[HOSTNAME_MAX_LENGTH];
> ++ int port;
> ++ int recoveryPort;
> ++ int sock;
> ++ int recovery_sock;
> ++} RecoveryTbl;
> ++
> ++/*
> ++ * 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;
> ++ int check_point;
> ++} RecoveryStatusInf;
> ++
> ++typedef struct {
> ++ long mtype;
> ++ long query_mtype;
> ++ char mdata[1];
> ++} RecoveryQueueHeader;
> ++
> ++typedef struct {
> ++ long mtype;
> ++ unsigned int replicationId;
> ++ char mdata[1];
> ++} RecoveryQueueQuery;
> ++
> ++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;
> ++ int current_cluster;
> ++ int transaction_count;
> ++ TransactionTbl *transaction_tbl;
> ++} ThreadArgInf;
> ++
> ++
> ++/* replication server data */
> ++extern uint16_t Port_Number;
> ++extern uint16_t LifeCheck_Port_Number;
> ++extern uint16_t Recovery_Port_Number;
> ++extern int Reserved_Connections;
> ++extern bool PGR_Parse_Session_Started;
> ++
> ++/* global tables */
> ++extern HostTbl * Host_Tbl_Begin;
> ++extern Dllist * Transaction_Tbl_Begin;
> ++extern TransactionTbl * Transaction_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;
> ++extern int RecoveryShmid;
> ++extern int ReplicateSerializationShmid;
> ++extern int RecoveryMsgShmid;
> ++extern int *RecoveryMsgid;
> ++extern int HostTblShmid;
> ++extern int LockWaitTblShmid;
> ++extern int CascadeTblShmid;
> ++extern int CascadeInfShmid;
> ++extern int CommitLogShmid;
> ++extern int MaxBackends;
> ++extern char * PGR_Result;
> ++extern int SemID;
> ++extern int RecoverySemID;
> ++extern int CascadeSemID;
> ++extern int LockSemID;
> ++extern int VacuumSemID;
> ++extern char * PGR_Data_Path;
> ++extern char * PGR_Write_Path;
> ++extern FILE * LogFp;
> ++extern FILE * StatusFp;
> ++extern FILE * RidFp;
> ++extern int Log_Print;
> ++extern int Debug_Print;
> ++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_ReplicateSerializationID;
> ++extern unsigned int * PGR_Send_Query_ID;
> ++extern unsigned int PGR_Query_ID;
> ++extern bool exit_processing;
> ++extern RecoveryQueueInf RecoveryQueue;
> ++extern int pgreplicate_pid;
> ++
> ++extern int ReplicateSock;
> ++
> ++/* smart shutdown */
> ++extern int Idle_Flag;
> ++extern bool Exit_Request;
> ++
> ++/*
> ++ * external prototype in main.c
> ++ */
> ++extern void child_wait(SIGNAL_ARGS);
> ++
> ++/*
> ++ * external prototype in conf.c
> ++ */
> ++extern int PGRget_Conf_Data(char * path);
> ++
> ++/*
> ++ * external prototype in replicate.c
> ++ */
> ++extern int PGRset_replication_id(uint32_t rid);
> ++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 set_exit_processing(int signo);
> ++extern void PGRreplicate_exit(int exit_status);
> ++extern int PGRsend_replicate_packet_to_server( HostTbl * host_ptr,
> ReplicateHeader * header, char *query , char * result,unsigned int
> replicationId, bool recovery);
> ++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_connections(void);
> ++extern void PGRsem_unlock( int semid, short sem_num );
> ++extern void PGRsem_lock( int semid, short sem_num );
> ++extern int PGRdo_replicate(int sock,ReplicateHeader *header, char *
> query);
> ++extern int PGRreturn_result(int dest, char * result, int wait);
> ++extern int PGRreplicate_packet_send( ReplicateHeader * header, char *
> query,int dest,int recovery_status);
> ++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(HostTbl *host);
> ++extern int PGRsync_oid(ReplicateHeader *header);
> ++extern unsigned int PGRget_next_query_id(void);
> ++extern int PGRinit_transaction_table(void);
> ++extern int replicate_packet_send_internal(ReplicateHeader * header, char
> * query,int dest,int recovery_status,bool isHeldLock);
> ++extern int PGRsync_oid(ReplicateHeader *header);
> ++extern int PGRload_replication_id(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 void PGRinit_cascade_child() ;
> ++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);
> ++extern int PGRsend_notice_quit();
> ++
> ++/*
> ++ * external prototype in pqformat.c
> ++ */
> ++extern const char * pq_getmsgstring(StringInfo msg);
> ++extern unsigned int pq_getmsgint(StringInfo msg, int b);
> ++extern void pq_copymsgbytes(StringInfo msg, char *buf, int datalen);
> ++extern const char * pq_getmsgbytes(StringInfo msg, int datalen);
> ++extern int pq_getmsgbyte(StringInfo msg);
> ++
> ++#endif /* PGREPLICATE_H */
> +diff -aruN postgresql-8.1.2/src/pgcluster/pgrp/pqformat.c
> pgcluster-1.5.0rc7/src/pgcluster/pgrp/pqformat.c
> +--- postgresql-8.1.2/src/pgcluster/pgrp/pqformat.c 1970-01-01
> 01:00:00.000000000 +0100
> ++++ pgcluster-1.5.0rc7/src/pgcluster/pgrp/pqformat.c 2006-01-31
> 17:34:54.000000000 +0100
> +@@ -0,0 +1,176 @@
> ++/*-------------------------------------------------------------------------
> ++ * pqformat.c
> ++ * Routines for formatting and parsing frontend/backend messages
> ++ *
> ++ * These modules copyed from src/backend/libpq/pgformat.c.
> ++ * Original modules have some shared modules and macro,
> ++ * then it is difficult link to replication server directory.
> ++ * Therefore, these modules were custamized.
> ++ * (removed shared module and macro)
> ++ *
> ++ * Original source code is under the following copyright
> ++ *
> ++ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
> ++ * Portions Copyright (c) 1994, Regents of the University of California
> ++ *
> ++
> *-------------------------------------------------------------------------
> ++ */
> ++/*
> ++ * INTERFACE ROUTINES
> ++ * Message parsing after input:
> ++ * pq_getmsgbyte - get a raw byte from a message buffer
> ++ * pq_getmsgint - get a binary integer from a message buffer
> ++ * pq_getmsgbytes - get raw data from a message buffer
> ++ * pq_copymsgbytes - copy raw data from a message buffer
> ++ * pq_getmsgstring - get a null-terminated text string (with
> conversion)
> ++ */
> ++
> ++/* --------------------------------
> ++ * pq_getmsgstring - get a null-terminated text string (with
> conversion)
> ++ *
> ++ * May return a pointer directly into the message buffer, or a
> pointer
> ++ * to a palloc'd conversion result.
> ++ * --------------------------------
> ++ */
> ++
> ++#include "postgres.h"
> ++
> ++#include <errno.h>
> ++#include <sys/param.h>
> ++#include <netinet/in.h>
> ++#include <arpa/inet.h>
> ++#ifdef HAVE_ENDIAN_H
> ++#include <endian.h>
> ++#endif
> ++
> ++#if 0
> ++#include "libpq/libpq.h"
> ++#include "libpq/pqformat.h"
> ++#endif
> ++#include "mb/pg_wchar.h"
> ++
> ++#include "libpq-fe.h"
> ++#include "libpq-int.h"
> ++#include "fe-auth.h"
> ++#include "replicate_com.h"
> ++#include "pgreplicate.h"
> ++
> ++const char *
> ++pq_getmsgstring(StringInfo msg)
> ++{
> ++ char *str;
> ++ int slen;
> ++
> ++ if (msg == NULL)
> ++ {
> ++ return NULL;
> ++ }
> ++ str = &msg->data[msg->cursor];
> ++ /*
> ++ * It's safe to use strlen() here because a StringInfo is guaranteed
> to
> ++ * have a trailing null byte. But check we found a null inside the
> ++ * message.
> ++ */
> ++ slen = strlen(str);
> ++ if (msg->cursor + slen >= msg->len)
> ++ {
> ++ show_error("invalid string in message");
> ++ return NULL;
> ++ }
> ++ msg->cursor += slen + 1;
> ++
> ++ return str;
> ++}
> ++
> ++
> ++/* --------------------------------
> ++ * pq_getmsgint - get a binary integer from a message buffer
> ++ *
> ++ * Values are treated as unsigned.
> ++ * --------------------------------
> ++ */
> ++unsigned int
> ++pq_getmsgint(StringInfo msg, int b)
> ++{
> ++ unsigned int result;
> ++ unsigned char n8;
> ++ uint16 n16;
> ++ uint32 n32;
> ++
> ++ switch (b)
> ++ {
> ++ case 1:
> ++ pq_copymsgbytes(msg, (char *) &n8, 1);
> ++ result = n8;
> ++ break;
> ++ case 2:
> ++ pq_copymsgbytes(msg, (char *) &n16, 2);
> ++ result = ntohs(n16);
> ++ break;
> ++ case 4:
> ++ pq_copymsgbytes(msg, (char *) &n32, 4);
> ++ result = ntohl(n32);
> ++ break;
> ++ default:
> ++ show_error("unsupported integer size %d", b);
> ++ result = 0; /* keep compiler
> quiet */
> ++ break;
> ++ }
> ++ return result;
> ++}
> ++
> ++/* --------------------------------
> ++ * pq_copymsgbytes - copy raw data from a message buffer
> ++ *
> ++ * Same as above, except data is copied to caller's buffer.
> ++ * --------------------------------
> ++ */
> ++void
> ++pq_copymsgbytes(StringInfo msg, char *buf, int datalen)
> ++{
> ++ if (datalen < 0 || datalen > (msg->len - msg->cursor))
> ++ {
> ++ show_error("insufficient data left in message");
> ++ return;
> ++ }
> ++ memcpy(buf, &msg->data[msg->cursor], datalen);
> ++ msg->cursor += datalen;
> ++}
> ++
> ++
> ++/* --------------------------------
> ++ * pq_getmsgbytes - get raw data from a message buffer
> ++ *
> ++ * Returns a pointer directly into the message buffer; note this
> ++ * may not have any particular alignment.
> ++ * --------------------------------
> ++ */
> ++const char *
> ++pq_getmsgbytes(StringInfo msg, int datalen)
> ++{
> ++ const char *result;
> ++
> ++ if (datalen < 0 || datalen > (msg->len - msg->cursor))
> ++ {
> ++ show_error("insufficient data left in message");
> ++ return NULL;
> ++ }
> ++ result = &msg->data[msg->cursor];
> ++ msg->cursor += datalen;
> ++ return result;
> ++}
> ++
> ++/* --------------------------------
> ++ * pq_getmsgbyte - get a raw byte from a message buffer
> ++ * --------------------------------
> ++ */
> ++int
> ++pq_getmsgbyte(StringInfo msg)
> ++{
> ++ if (msg->cursor >= msg->len)
> ++ {
> ++ show_error("no data left in message");
> ++ return 0;
> ++ }
> ++ return (unsigned char) msg->data[msg->cursor++];
> ++}
> +diff -aruN postgresql-8.1.2/src/pgcluster/pgrp/recovery.c
> pgcluster-1.5.0rc7/src/pgcluster/pgrp/recovery.c
> +--- postgresql-8.1.2/src/pgcluster/pgrp/recovery.c 1970-01-01
> 01:00:00.000000000 +0100
> ++++ pgcluster-1.5.0rc7/src/pgcluster/pgrp/recovery.c 2006-01-31
> 23:44:12.000000000 +0100
> +@@ -0,0 +1,1050 @@
> ++/*--------------------------------------------------------------------
> ++ * 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-2006, Atsushi Mitani
> ++ *--------------------------------------------------------------------
> ++ */
> ++#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
> ++#include "pgreplicate.h"
> ++
> ++
> ++/*--------------------------------------
> ++ * 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 int PGRsend_queue(RecoveryTbl * master, RecoveryTbl * target);
> ++static int send_vacuum(HostTbl *host, char * userName, int stage);
> ++
> ++#ifdef PRINT_DEBUG
> ++static void show_recovery_packet(RecoveryPacket * packet);
> ++#endif
> ++
> ++int PGRsend_load_balance_packet(RecoveryPacket * packet);
> ++void PGRrecovery_main(void);
> ++
> ++/*-----------------------------------------------------------
> ++ * 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)
> ++{
> ++#ifdef PRINT_DEBUG
> ++ char * func = "read_packet()";
> ++#endif
> ++ int r = 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 || errno == EAGAIN)
> ++ continue;
> ++ else
> ++ {
> ++ show_error("%s:recv failed: %d(%s)",func,
> errno, strerror(errno));
> ++ return -1;
> ++ }
> ++ }
> ++ else if (r > 0)
> ++ {
> ++ read_size += r;
> ++ if (read_size == packet_size)
> ++ {
> ++#ifdef PRINT_DEBUG
> ++ show_debug("%s:receive packet",func);
> ++ show_recovery_packet(packet);
> ++#endif
> ++ return read_size;
> ++ }
> ++ }
> ++ else /* r == 0 */
> ++ {
> ++ show_error("%s:unexpected EOF", func);
> ++ return -1;
> ++ }
> ++ }
> ++ return -1;
> ++}
> ++
> ++static int
> ++read_packet_from_master( RecoveryTbl * host, RecoveryPacket * packet )
> ++{
> ++ int read_size = 0;
> ++ int rtn;
> ++ fd_set rmask;
> ++ struct timeval timeout;
> ++
> ++ for(;;)
> ++ {
> ++ timeout.tv_sec = PGR_RECV_TIMEOUT;
> ++ timeout.tv_usec = 0;
> ++
> ++ /*
> ++ * Wait for something to happen.
> ++ */
> ++ FD_ZERO(&rmask);
> ++ FD_SET(host->recovery_sock,&rmask);
> ++ rtn = select(host->recovery_sock+1, &rmask, (fd_set *)NULL,
> (fd_set *)NULL, &timeout);
> ++
> ++ if (rtn == 0) /* timeout */
> ++ {
> ++ return -1;
> ++ }
> ++
> ++ 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;
> ++
> ++ 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 || errno == EAGAIN)
> ++ continue;
> ++
> ++ show_error("%s:send error: %d(%s)", func, errno,
> strerror(errno));
> ++ return STATUS_ERROR;
> ++ }
> ++ else if (s == 0)
> ++ {
> ++ show_error("%s:unexpected EOF", func);
> ++ return STATUS_ERROR;
> ++ }
> ++
> ++ send_size += s;
> ++ if (send_size == buf_size)
> ++ return STATUS_OK;
> ++ }
> ++}
> ++
> ++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:host[%s]
> port[%d]PGR_Create_Socket_Connect failed",func,host->hostName,
> host->recoveryPort);
> ++ 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);
> ++#ifdef PRINT_DEBUG
> ++ show_debug("%s:PGR_Create_Socket_Connectsock[%d] host[%s]
> port[%d]",
> ++
> func,host->recovery_sock,host->hostName,host->recoveryPort);
> ++#endif
> ++ 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)
> ++ {
> ++ if (lbp->recovery_sock != -1)
> ++ {
> ++ close(lbp->recovery_sock);
> ++ lbp->recovery_sock = -1;
> ++ }
> ++#ifdef PRINT_DEBUG
> ++ show_debug("%s:host[%s]
> port[%d]",func,lbp->hostName,lbp->recoveryPort);
> ++#endif
> ++ 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();
> ++ header.isAutoCommit=1;
> ++ rtn =
> PGRsend_replicate_packet_to_server(host,&header,query,PGR_Result,0, true);
> ++ 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;
> ++
> ++ memcpy(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
> ++ */
> ++#ifdef PRINT_DEBUG
> ++ show_debug("%s:already recovery job runing",func);
> ++#endif
> ++ 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
> ++ */
> ++#ifdef PRINT_DEBUG
> ++ show_debug("%s:add recovery target to host table",func);
> ++#endif
> ++ memcpy(host_tbl.hostName,packet->hostName,sizeof(host_tbl.hostName));
> ++ host_tbl.port = ntohs(packet->port);
> ++ PGRset_recovered_host(&host_tbl,DB_TBL_INIT);
> ++ PGRadd_HostTbl(&host_tbl,DB_TBL_INIT);
> ++ /*
> ++ * send prepare recovery to load balancer
> ++ */
> ++ PGRsend_load_balance_packet(packet);
> ++ userName = strdup(packet->userName);
> ++
> ++ /*
> ++ * set RECOVERY_PGDATA_REQ packet data
> ++ */
> ++#ifdef PRINT_DEBUG
> ++ show_debug("%s:set RECOVERY_PGDATA_REQ packet data",func);
> ++#endif
> ++ 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_TARGET_ONLY);
> ++ 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)
> ++ {
> ++ PGRset_host_status(master, DB_TBL_ERROR);
> ++ goto retry_connect_master;
> ++ }
> ++
> ++ memcpy(Master.hostName,master->hostName,sizeof(Master.hostName));
> ++ Master.sock = -1;
> ++ Master.recovery_sock = -1;
> ++ Master.port = master->port;
> ++ Master.recoveryPort = master->recoveryPort;
> ++
> ++#ifdef PRINT_DEBUG
> ++ show_debug("%s:send packet to master %s recoveryPort %d",func,
> Master.hostName, Master.recoveryPort);
> ++#endif
> ++ 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,DB_TBL_ERROR);
> ++ 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
> ++ */
> ++#ifdef PRINT_DEBUG
> ++ show_debug("%s:wait answer from master server",func);
> ++#endif
> ++ memset(packet,0,sizeof(RecoveryPacket));
> ++ read_packet_from_master(&Master, packet);
> ++#ifdef PRINT_DEBUG
> ++ show_debug("%s:get answer from
> master:no[%d]",func,ntohs(packet->packet_no));
> ++#endif
> ++ 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 );
> ++
> memcpy(packet->hostName,Master.hostName,sizeof(packet->hostName));
> ++ status = send_packet(&Target, packet);
> ++ if (status != STATUS_OK)
> ++ {
> ++ show_error("%s:no[%d] send_packet to target
> error",func,ntohs(packet->packet_no));
> ++ PGRset_recovery_packet_no(packet,
> RECOVERY_ERROR_TARGET_ONLY);
> ++ 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();
> ++
> ++ /* send vauum command to master server */
> ++ while ((master = PGRget_master()) != NULL)
> ++ {
> ++ userName = strdup(packet->userName);
> ++ status = send_vacuum(master, userName, PGR_RECOVERY_2ND_STAGE
> );
> ++ if (status != STATUS_OK)
> ++ {
> ++ PGRset_host_status(master, DB_TBL_ERROR);
> ++ if (userName != NULL)
> ++ {
> ++ free(userName);
> ++ userName = NULL;
> ++ }
> ++ continue;
> ++ }
> ++ break;
> ++ }
> ++
> ++ if (master == NULL)
> ++ {
> ++ show_error("%s:vacuum error , master may be down",func);
> ++ PGRset_recovery_packet_no(packet, RECOVERY_ERROR_TARGET_ONLY);
> ++ status = send_packet(&Target,packet);
> ++ status = send_packet(&Master,packet);
> ++ reset_recovery_prepare();
> ++
> ++ return true;
> ++ }
> ++
> ++ /*
> ++ * wait until all started transactions are going to finish
> ++ */
> ++ status = PGRwait_transaction_count_clear(master);
> ++ if (status != STATUS_OK && PGRget_recovery_status() == RECOVERY_START)
> ++ {
> ++ show_error("%s:transaction is too busy, please try again
> after",func);
> ++ PGRset_recovery_packet_no(packet, RECOVERY_ERROR_TARGET_ONLY);
> ++ status = send_packet(&Target,packet);
> ++ status = send_packet(&Master,packet);
> ++ reset_recovery_prepare();
> ++ return true;
> ++ }
> ++
> ++ if (PGRget_recovery_status() != RECOVERY_START) {
> ++ show_error("%s:queue set failed. stop to recovery",func);
> ++ PGRset_recovery_packet_no(packet, RECOVERY_ERROR_CONNECTION);
> ++ status = send_packet(&Target,packet);
> ++ status = send_packet(&Master,packet);
> ++ reset_recovery_prepare();
> ++ if (userName != NULL)
> ++ free(userName);
> ++ return true;
> ++ }
> ++
> ++ /*
> ++ * 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();
> ++ if (userName != NULL)
> ++ free(userName);
> ++ return true;
> ++ }
> ++
> ++ if (PGRget_recovery_status() != RECOVERY_START) {
> ++ show_error("%s:queue set failed. stop to recovery",func);
> ++ PGRset_recovery_packet_no(packet, RECOVERY_ERROR_CONNECTION);
> ++ status = send_packet(&Target,packet);
> ++ status = send_packet(&Master,packet);
> ++ reset_recovery_prepare();
> ++ if (userName != NULL)
> ++ free(userName);
> ++ return true;
> ++ }
> ++
> ++ /*
> ++ * 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 );
> ++
> memcpy(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:failure 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;
> ++}
> ++/**
> ++ * send queries from queue.
> ++ *
> ++ * return
> ++ * STATUS_OK - success both
> ++ * STATUS_ERROR - fail both
> ++ */
> ++static int
> ++PGRsend_queue(RecoveryTbl * master, RecoveryTbl * target)
> ++{
> ++ char * func = "PGRsend_queue()";
> ++ HostTbl * master_ptr = NULL;
> ++ HostTbl * target_ptr = NULL;
> ++ RecoveryQueueHeader * msg_header = NULL;
> ++ RecoveryQueueQuery * msg_query = NULL;
> ++ ReplicateHeader * header = NULL;
> ++ char * query = NULL;
> ++ int size = 0;
> ++ int rcv_header_size = 0;
> ++ long mtype = 0;
> ++ int status = 0;
> ++ int query_size = 0;
> ++ int rtn=0;
> ++ if (master == (RecoveryTbl *)NULL)
> ++ {
> ++ show_error("%s:there is no master ",func);
> ++ return STATUS_ERROR;
> ++ }
> ++#ifdef PRINT_DEBUG
> ++ show_debug("%s:master %s - %d",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;
> ++ }
> ++ }
> ++
> ++ size = sizeof(RecoveryQueueHeader) + sizeof(ReplicateHeader);
> ++ msg_header = (RecoveryQueueHeader *)malloc(size+4);
> ++ if (msg_header == NULL)
> ++ {
> ++#ifdef PRINT_DEBUG
> ++ show_debug("%s:malloc() failed. reason: %s",func,
> strerror(errno));
> ++#endif
> ++ return STATUS_ERROR;
> ++ }
> ++ memset(msg_header,0,size+4);
> ++ rcv_header_size = sizeof(long)+sizeof(ReplicateHeader);
> ++ status = STATUS_OK;
> ++ while (msgrcv(*RecoveryMsgid , msg_header, rcv_header_size,
> RECOVERY_HEADER_MTYPE, IPC_NOWAIT) > 0 )
> ++ {
> ++ header = (ReplicateHeader *)(msg_header->mdata);
> ++ query_size = ntohl(header->query_size);
> ++ if (query_size < 0)
> ++ {
> ++ if (msg_query != NULL)
> ++ {
> ++ free(msg_query);
> ++ msg_query = NULL;
> ++ }
> ++ break;
> ++ }
> ++ size = sizeof(RecoveryQueueQuery) + query_size;
> ++ mtype = msg_header->query_mtype;
> ++ msg_query = (RecoveryQueueQuery *) malloc(size+4);
> ++ if (msg_query == NULL)
> ++ {
> ++#ifdef PRINT_DEBUG
> ++ show_debug("%s:malloc() failed. reason: %s",func,
> strerror(errno));
> ++#endif
> ++ free(msg_header);
> ++ msg_header = NULL;
> ++ return STATUS_ERROR;
> ++ }
> ++ memset(msg_query,0,size+4);
> ++ if (msgrcv(*RecoveryMsgid , msg_query, sizeof(unsigned
> int)+query_size, mtype, IPC_NOWAIT) < 0)
> ++ {
> ++ show_error("%s:msgrcv() failed.
> (%s)",func,strerror(errno) );
> ++ status = STATUS_ERROR;
> ++ if (msg_query != NULL)
> ++ {
> ++ free(msg_query);
> ++ msg_query = NULL;
> ++ }
> ++ break;
> ++ }
> ++ query = (char *)(msg_query->mdata);
> ++#ifdef PRINT_DEBUG
> ++ show_debug("%s:put query from queue :%s",func,query);
> ++#endif
> ++
> rtn=PGRsend_replicate_packet_to_server(master_ptr,header,query,PGR_Result,msg_query->replicationId,
> true);
> ++ if (rtn == STATUS_ERROR || rtn == STATUS_DEADLOCK_DETECT )
> ++ {
> ++ show_error("%s:PGRsend_replicate_packet_to_server to
> master error",func);
> ++ status = STATUS_ERROR ;
> ++ if (msg_query != NULL)
> ++ {
> ++ free(msg_query);
> ++ msg_query = NULL;
> ++ }
> ++ break;
> ++ }
> ++ if (target_ptr != NULL)
> ++ {
> ++
> rtn=PGRsend_replicate_packet_to_server(target_ptr,header,query,PGR_Result,msg_query->replicationId,
> true);
> ++ if (rtn == STATUS_ERROR || rtn ==
> STATUS_DEADLOCK_DETECT )
> ++ {
> ++
> show_error("%s:PGRsend_replicate_packet_to_server to target error",func);
> ++ status = STATUS_ERROR;
> ++ if (msg_query != NULL)
> ++ {
> ++ free(msg_query);
> ++ msg_query = NULL;
> ++ }
> ++ break;
> ++ }
> ++ }
> ++ if (msg_query != NULL)
> ++ {
> ++ free(msg_query);
> ++ msg_query = NULL;
> ++ }
> ++ }
> ++ if (msg_header != NULL)
> ++ {
> ++ free(msg_header);
> ++ msg_header = NULL;
> ++ }
> ++#ifdef PRINT_DEBUG
> ++ show_debug("%s:send_queue return status %d",func,status);
> ++#endif
> ++ return status;
> ++}
> ++
> ++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;
> ++ RecoveryTbl * lbp;
> ++
> ++ lbp = LoadBalanceTbl;
> ++ if (lbp == (RecoveryTbl *)NULL)
> ++ {
> ++ show_error("%s:recovery table is NULL",func);
> ++ return ;
> ++ }
> ++#ifdef PRINT_DEBUG
> ++ show_debug("%s:recovery accept port %d",func, Recovery_Port_Number);
> ++#endif
> ++ 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 ++;
> ++ }
> ++ if(sock==-1) {
> ++ show_error("can't create recovery socket.exit.");
> ++ PGRreplicate_exit(1);
> ++ }
> ++ 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 == 0) /* timeout */
> ++ {
> ++ return;
> ++ }
> ++
> ++ 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
> ++ */
> ++
> ++#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
> ++
> ++ loop_end = first_setup_recovery(&sock,
> &packet);
> ++#ifdef PRINT_DEBUG
> ++ show_debug("%s:first_setup_recovery end:%d
> ",func,loop_end);
> ++#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
> ++ */
> ++#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);
> ++#endif
> ++ loop_end = second_setup_recovery (&packet);
> ++#ifdef PRINT_DEBUG
> ++ 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)
> ++ {
> ++
> memcpy(new_host.hostName,Target.hostName,sizeof(new_host.hostName));
> ++ new_host.port = Target.port;
> ++ new_host.recoveryPort =
> Target.recoveryPort;
> ++
> PGRset_recovered_host(&new_host,DB_TBL_USE);
> ++ PGRadd_HostTbl(&new_host,DB_TBL_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 re-initialize recovery
> status
> ++ */
> ++ finish_recovery();
> ++ loop_end = true;
> ++ /*
> ++ * send finish recovery to load balancer
> ++ */
> ++ if (Master.recovery_sock != -1)
> ++ {
> ++ close(Master.recovery_sock);
> ++ Master.recovery_sock = -1;
> ++ }
> ++ if (Target.recovery_sock != -1)
> ++ {
> ++ close(Target.recovery_sock);
> ++ Target.recovery_sock = -1;
> ++ }
> ++ 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;
> ++ default:
> ++ show_error("%s:unknown packet. abort to parse");
> ++ loop_end=true;
> ++ break;
> ++ }
> ++ if (loop_end)
> ++ {
> ++ if (Master.sock != -1)
> ++ {
> ++ close (Master.sock);
> ++ }
> ++ if (Master.recovery_sock != -1)
> ++ {
> ++ close (Master.recovery_sock);
> ++ }
> ++ PGR_Close_Sock(&sock);
> ++ return;
> ++ }
> ++ }
> ++}
> ++
> ++void
> ++PGRrecovery_main(void)
> ++{
> ++ char * func = "PGRrecovery_main()";
> ++ int status;
> ++ int fd = -1;
> ++ int rtn;
> ++
> ++#ifdef PRINT_DEBUG
> ++ show_debug("%s:PGRrecovery_main bind port
> %d",func,Recovery_Port_Number);
> ++#endif
> ++ 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;
> ++
> ++ 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))
> ++ {
> ++ pgrecovery_loop(fd);
> ++ }
> ++ }
> ++}
> ++
> ++#ifdef PRINT_DEBUG
> ++static void
> ++show_recovery_packet(RecoveryPacket * packet)
> ++{
> ++ show_debug("no = %d",ntohs(packet->packet_no));
> ++ show_debug("max_connect = %d",ntohs(packet->max_connect));
> ++ show_debug("port = %d",ntohs(packet->port));
> ++ show_debug("recoveryPort = %d",ntohs(packet->recoveryPort));
> ++ if (packet->hostName != NULL)
> ++ show_debug("hostName = %s",packet->hostName);
> ++ if (packet->pg_data != NULL)
> ++ show_debug("pg_data = %s",packet->pg_data);
> ++}
> ++#endif
> +diff -aruN postgresql-8.1.2/src/pgcluster/pgrp/replicate.c
> pgcluster-1.5.0rc7/src/pgcluster/pgrp/replicate.c
> +--- postgresql-8.1.2/src/pgcluster/pgrp/replicate.c 1970-01-01
> 01:00:00.000000000 +0100
> ++++ pgcluster-1.5.0rc7/src/pgcluster/pgrp/replicate.c 2006-01-31
> 23:38:17.000000000 +0100
> +@@ -0,0 +1,3938 @@
> ++/*--------------------------------------------------------------------
> ++ * 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-2006, Atsushi Mitani
> ++ *--------------------------------------------------------------------
> ++ */
> ++#include "postgres.h"
> ++#include "postgres_fe.h"
> ++
> ++#include <pthread.h>
> ++#include <stdio.h>
> ++#include <stdarg.h>
> ++#include <sys/types.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 "lib/dllist.h"
> ++#include "libpq/pqformat.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 HostTbl * deleteHostTbl(HostTbl * ptr);
> ++static bool is_master_in_recovery(char * host, int port,int
> recovery_status);
> ++static void sem_quit(int semid);
> ++static int send_cluster_status_to_load_balance(HostTbl * host_ptr,int
> status);
> ++static void set_transaction_status(int status);
> ++static void check_transaction_status(ReplicateHeader * header,HostTbl
> *host, TransactionTbl *transaction);
> ++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 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 next_replication_id(void);
> ++static void check_replication_id(void);
> ++static bool is_need_use_rlog(ReplicateHeader * header);
> ++static bool is_need_queue_jump( ReplicateHeader * header,char * query);
> ++static int check_delete_transaction (HostTbl * host_ptr, ReplicateHeader
> * header);
> ++
> ++static bool is_executed_query_in_origin( ReplicateHeader *header );
> ++static bool is_executed_query( PGconn *conn,ReplicateHeader *header );
> ++
> ++static void * thread_send_source(void * arg);
> ++static void * thread_send_cluster(void * arg);
> ++
> ++static int send_replicate_packet_to_server( TransactionTbl *
> transaction_tbl, int current_cluster, HostTbl * host_ptr, ReplicateHeader *
> header, char *query , char * result,unsigned int replicationId, bool
> recovery);
> ++
> ++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, ReplicateHeader * header, LOArgs
> * query);
> ++static int notice_abort(HostTbl * host_ptr,ReplicateHeader * header);
> ++static int send_p_parse (PGconn * conn, StringInfo input_message);
> ++static int send_p_bind (PGconn * conn, StringInfo input_message);
> ++static int send_p_describe (PGconn * conn, StringInfo input_message);
> ++static int send_p_execute (PGconn * conn, StringInfo input_message);
> ++static int send_p_sync (PGconn * conn, StringInfo input_message);
> ++static int send_p_close (PGconn * conn, StringInfo input_message);
> ++static void set_string_info(StringInfo input_message, ReplicateHeader *
> header, char * query);
> ++
> ++int replicate_packet_send_internal(ReplicateHeader * header, char *
> query,int dest,int recovery_status,bool isHeldLock);
> ++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 exit_status);
> ++int PGRsend_replicate_packet_to_server( HostTbl * host_ptr,
> ReplicateHeader * header, char *query , char * result,unsigned int
> replicationId, bool recovery);
> ++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 PGRset_replication_id(uint32_t id);
> ++int PGRdo_replicate(int sock,ReplicateHeader *header, char * query);
> ++int PGRreturn_result(int dest, char * result,int wait);
> ++int PGRreplicate_packet_send( ReplicateHeader * header, char * query,int
> dest,int recovery_status);
> ++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(HostTbl *host);
> ++
> ++unsigned int PGRget_next_query_id(void);
> ++int PGRinit_transaction_table(void);
> ++int PGRsync_oid(ReplicateHeader *header);
> ++int PGRload_replication_id(void);
> ++
> ++extern pthread_mutex_t transaction_table_mutex;
> ++
> ++static int exit_signo = SIGTERM;
> ++
> ++bool
> ++PGRis_same_host(char * host1, unsigned short port1 , char * host2,
> unsigned short port2)
> ++{
> ++#ifdef PRINT_DEBUG
> ++ char * func = "PGRis_same_host()";
> ++#endif
> ++ unsigned int ip1, ip2;
> ++
> ++ if ((host1[0] == '\0' ) || (host2[0] == '\0') ||
> ++ ( port1 != port2 ))
> ++ {
> ++#ifdef PRINT_DEBUG
> ++ show_debug("%s:not same host",func);
> ++#endif
> ++ 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)
> ++ {
> ++ if (conn != NULL)
> ++ {
> ++ PQfinish(conn);
> ++ conn = NULL;
> ++ }
> ++ conn = PQsetdbLogin(host, port, NULL, NULL, database,
> userName, NULL);
> ++ if (cnt > PGR_CONNECT_RETRY_TIME )
> ++ {
> ++ if (conn != NULL)
> ++ {
> ++ PQfinish(conn);
> ++ conn = NULL;
> ++ }
> ++ return (PGconn *)NULL;
> ++ }
> ++
> ++ if(PQstatus(conn) == CONNECTION_BAD && h_errno==2)
> ++ {
> ++ sleep(3);
> ++ show_debug("gethostbyname() failed. sleep and
> retrying...");
> ++ }
> ++ else if(!strncasecmp(PQerrorMessage(conn),"FATAL: Sorry, too
> many clients already",30) ||
> ++ !strncasecmp(PQerrorMessage(conn),"FATAL:
> Non-superuser connection limit",30) )
> ++ {
> ++ sleep(3) ;
> ++ show_debug("Connection overflow. sleep and retrying...");
> ++ }
> ++ else if(!strncasecmp(PQerrorMessage(conn),"FATAL: The
> database system is starting up",40) )
> ++ {
> ++ show_debug("waiting for starting up...");
> ++ sleep(3) ;
> ++ }
> ++ else
> ++ {
> ++ show_debug("%s:Retry. h_errno is %d,reason is
> '%s'",func,h_errno,PQerrorMessage(conn));
> ++ sleep(3) ;
> ++ 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->resolvedName;
> ++
> ++ ptr = getTransactionTbl(host_ptr,header);
> ++ if (ptr != NULL)
> ++ {
> ++ ptr->transaction_count = 0;
> ++ 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,DB_TBL_ERROR);
> ++ 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));
> ++ 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 = DB_TBL_USE ;
> ++ work.in_transaction = false;
> ++ work.transaction_count = 0;
> ++ 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;
> ++
> ++ pthread_mutex_lock(&transaction_table_mutex);
> ++ if ((host_ptr == (HostTbl *)NULL) || (datap == (TransactionTbl*)NULL))
> ++ {
> ++ show_error("%s:host table or transaction table is NULL",func);
> ++ pthread_mutex_unlock(&transaction_table_mutex);
> ++
> ++ return (TransactionTbl *)NULL;
> ++ }
> ++ if (Transaction_Tbl_Begin == NULL)
> ++ {
> ++ if (PGRinit_transaction_table() != STATUS_OK)
> ++ {
> ++ pthread_mutex_unlock(&transaction_table_mutex);
> ++
> ++ return (TransactionTbl *)NULL;
> ++ }
> ++ }
> ++
> ++ workp = (TransactionTbl *)malloc(sizeof(TransactionTbl));
> ++ memset(workp,0,sizeof(TransactionTbl));
> ++ 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));
> ++ workp->conn = datap->conn;
> ++ workp->useFlag = DB_TBL_USE;
> ++ workp->lock = STATUS_OK;
> ++ workp->in_transaction =datap->in_transaction;
> ++ workp->transaction_count =datap->transaction_count;
> ++ DLAddTail(Transaction_Tbl_Begin, DLNewElem(workp));
> ++
> ++ pthread_mutex_unlock(&transaction_table_mutex);
> ++
> ++ return workp;
> ++}
> ++
> ++static TransactionTbl *
> ++getTransactionTbl( HostTbl * host_ptr, ReplicateHeader * header)
> ++{
> ++ Dlelem * ptr = NULL;
> ++ unsigned int host_ip,srcHost_ip;
> ++ unsigned short pid = 0;
> ++
> ++ if (Transaction_Tbl_Begin == (Dllist *) NULL)
> ++ {
> ++ return (TransactionTbl * )NULL;
> ++ }
> ++ if ((host_ptr == (HostTbl *)NULL) ||
> ++ (header == (ReplicateHeader *)NULL))
> ++ {
> ++ return (TransactionTbl * )NULL;
> ++ }
> ++ host_ip = get_host_ip_from_tbl(host_ptr->resolvedName);
> ++ if (host_ip == 0)
> ++ {
> ++ host_ip = PGRget_ip_by_name(host_ptr->resolvedName);
> ++ }
> ++ 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);
> ++
> ++ pthread_mutex_lock(&transaction_table_mutex);
> ++
> ++ ptr = DLGetHead(Transaction_Tbl_Begin);
> ++ while (ptr)
> ++ {
> ++ TransactionTbl *transaction = DLE_VAL(ptr);
> ++ if ((transaction->useFlag == DB_TBL_USE) &&
> ++ (transaction->hostIP == host_ip) &&
> ++ (transaction->port == host_ptr->port) &&
> ++ (transaction->srcHostIP == srcHost_ip) &&
> ++
> (!strncmp(transaction->dbName,header->dbName,sizeof(transaction->dbName)))
> &&
> ++ (transaction->pid == pid))
> ++ {
> ++ pthread_mutex_unlock(&transaction_table_mutex);
> ++ return transaction;
> ++ }
> ++ ptr = DLGetSucc(ptr);
> ++ }
> ++ pthread_mutex_unlock(&transaction_table_mutex);
> ++
> ++ return (TransactionTbl * )NULL;
> ++}
> ++
> ++static void
> ++deleteTransactionTbl(HostTbl * host_ptr,ReplicateHeader * header)
> ++{
> ++ char * func = "deleteTransactionTbl()";
> ++ TransactionTbl *ptr = NULL;
> ++ Dlelem *elem;
> ++#ifdef PRINT_DEBUG
> ++ show_debug("%s:",func);
> ++#endif
> ++
> ++ ptr = getTransactionTbl(host_ptr,header);
> ++
> ++ pthread_mutex_lock(&transaction_table_mutex);
> ++
> ++ if (ptr != NULL)
> ++ {
> ++ /*
> ++ if ( ptr->transaction_count > 0 )
> ++ {
> ++ pthread_mutex_unlock(&transaction_table_mutex);
> ++ return;
> ++ }
> ++ */
> ++ if (ptr->in_transaction)
> ++ {
> ++ host_ptr->transaction_count--;
> ++ }
> ++
> ++ if (ptr->conn != NULL)
> ++ {
> ++ PQfinish(ptr->conn);
> ++ }
> ++ elem = DLGetHead(Transaction_Tbl_Begin);
> ++ while (elem)
> ++ {
> ++ TransactionTbl *transaction = DLE_VAL(elem);
> ++ if (transaction == ptr) {
> ++ DLRemove(elem);
> ++ DLFreeElem(elem);
> ++ free(ptr);
> ++
> pthread_mutex_unlock(&transaction_table_mutex);
> ++ return;
> ++ }
> ++ elem = DLGetSucc(elem);
> ++ }
> ++ }
> ++ pthread_mutex_unlock(&transaction_table_mutex);
> ++}
> ++
> ++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 != DB_TBL_END)
> ++ {
> ++ if (ptr->useFlag == DB_TBL_FREE)
> ++ {
> ++ break;
> ++ }
> ++ ptr ++;
> ++ cnt ++;
> ++ }
> ++ if (cnt >= MAX_DB_SERVER)
> ++ {
> ++ return (HostTbl*)NULL;
> ++ }
> ++ if (ptr->useFlag == DB_TBL_END)
> ++ {
> ++ (ptr + 1) -> useFlag = DB_TBL_END;
> ++ }
> ++ memset(ptr,0,sizeof(HostTbl));
> ++ ptr->hostNum = cnt;
> ++ memcpy(ptr->hostName,conf_data->hostName,sizeof(ptr->hostName));
> ++
> memcpy(ptr->resolvedName,conf_data->resolvedName,sizeof(ptr->resolvedName));
> ++ ptr->port = conf_data->port;
> ++ ptr->recoveryPort = conf_data->recoveryPort;
> ++ ptr->transaction_count = 0;
> ++ PGRset_host_status(ptr,useFlag);
> ++
> ++ return ptr;
> ++}
> ++
> ++HostTbl *
> ++PGRget_master(void)
> ++{
> ++ HostTbl * host_tbl = NULL;
> ++
> ++ host_tbl = Host_Tbl_Begin;
> ++ while(host_tbl->useFlag != DB_TBL_END)
> ++ {
> ++ if (host_tbl->useFlag == DB_TBL_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 = -1;
> ++
> ++ 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;
> ++
> ++}
> ++
> ++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);
> ++}
> ++
> ++#if 0
> ++static int
> ++get_transaction_status(void)
> ++{
> ++ int status = 0;
> ++
> ++ if (RecoverySemID <= 0)
> ++ return 0;
> ++ 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 0;
> ++}
> ++#endif
> ++
> ++int
> ++PGRwait_transaction_count_clear(HostTbl *host)
> ++{
> ++ int cnt = 0;
> ++ int transaction=-1;
> ++
> ++ for(cnt=0 ;
> ++ cnt < PGR_RECOVERY_RETRY_CNT && transaction!=0;
> ++ cnt++)
> ++ {
> ++ PGRsem_lock(SemID, 1);
> ++ transaction = host->transaction_count;
> ++ PGRsem_unlock(SemID, 1);
> ++ usleep(PGR_RECOVERY_WAIT_MSEC);
> ++ }
> ++ show_debug("transaction count is %d",transaction);
> ++ return transaction==0
> ++ ? STATUS_OK
> ++ : 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 != DB_TBL_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 = DB_TBL_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 (RecoverySemID <= 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 recovery_status)
> ++{
> ++ HostTbl * master = NULL;
> ++
> ++ // status = PGRget_recovery_status();
> ++ if (recovery_status == RECOVERY_START)
> ++ {
> ++ master = PGRget_master();
> ++ if (master == (HostTbl *)NULL)
> ++ {
> ++ return false;
> ++ }
> ++ if
> ((!strncmp(host,master->hostName,sizeof(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,2,IPC_CREAT | IPC_EXCL |
> 0600)) < 0)
> ++ {
> ++ show_error("%s:semget() failed. (%s)",func,strerror(errno));
> ++ return STATUS_ERROR;
> ++ }
> ++ for ( i = 0 ; i < 2 ; 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,size);
> ++ Recovery_Status_Inf->check_point = PGR_CHECK_POINT ;
> ++
> ++ size = sizeof(unsigned int);
> ++ ReplicateSerializationShmid = shmget(IPC_PRIVATE,size,IPC_CREAT |
> IPC_EXCL | 0600);
> ++ if (ReplicateSerializationShmid < 0)
> ++ {
> ++ show_error("%s:shmget() failed. (%s)",func,strerror(errno));
> ++ return STATUS_ERROR;
> ++ }
> ++
> ++ PGR_ReplicateSerializationID = (unsigned int
> *)shmat(ReplicateSerializationShmid,0,0);
> ++ if( PGR_ReplicateSerializationID == (unsigned int *)-1) {
> ++ show_error("%s:shmat() failed. (%s)",func,strerror(errno));
> ++ return STATUS_ERROR;
> ++ }
> ++ memset(PGR_ReplicateSerializationID,0,size);
> ++ PGRset_recovery_status(RECOVERY_INIT);
> ++ PGRset_recovered_host((HostTbl *)NULL, DB_TBL_FREE);
> ++ set_transaction_status(0);
> ++
> ++ /*
> ++ * create message queue
> ++ */
> ++ RecoveryMsgShmid = shmget(IPC_PRIVATE,size,IPC_CREAT | IPC_EXCL |
> 0600);
> ++ if (RecoveryMsgShmid < 0)
> ++ {
> ++ show_error("%s:shmget() failed. (%s)",func,strerror(errno));
> ++ return STATUS_ERROR;
> ++ }
> ++
> ++ RecoveryMsgid = (int *)shmat(RecoveryMsgShmid,0,0);
> ++ if( RecoveryMsgid < 0) {
> ++ show_error("%s:shmat() failed. (%s)",func,strerror(errno));
> ++ return STATUS_ERROR;
> ++ }
> ++ *RecoveryMsgid = msgget (IPC_PRIVATE, 00666 | IPC_CREAT );
> ++ if (*RecoveryMsgid < 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 && ptr->useFlag != DB_TBL_END)
> ++ {
> ++ ptr = deleteHostTbl(ptr);
> ++ }
> ++}
> ++
> ++void
> ++set_exit_processing(int signo)
> ++{
> ++ exit_signo = signo;
> ++ exit_processing = true;
> ++ signal(signo, SIG_IGN);
> ++}
> ++
> ++void
> ++PGRreplicate_exit(int exit_status)
> ++{
> ++ char fname[256];
> ++ int rtn = 0;
> ++
> ++ signal(SIGCHLD, SIG_IGN);
> ++ kill (0, exit_signo);
> ++
> ++ child_wait(0);
> ++
> ++ if (RidFp != NULL)
> ++ {
> ++ rewind(RidFp);
> ++ if (Recovery_Status_Inf != NULL)
> ++ {
> ++
> PGRwrite_log_file(RidFp,"%u",Recovery_Status_Inf->replication_id);
> ++ }
> ++ fflush(RidFp);
> ++ fclose(RidFp);
> ++ RidFp = NULL;
> ++ }
> ++
> ++ if (ReplicateSock > 0)
> ++ close(ReplicateSock);
> ++
> ++ /* recovery status clear */
> ++ if (RecoverySemID > 0)
> ++ Recovery_Status_Inf->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);
> ++ }
> ++
> ++ if (Cascade_Tbl != (ReplicateServerInfo *)NULL)
> ++ {
> ++ rtn = shmdt((char *)Cascade_Tbl);
> ++ shmctl(CascadeTblShmid,IPC_RMID,(struct shmid_ds *)NULL);
> ++ }
> ++
> ++ if (Cascade_Inf != (CascadeInf *)NULL)
> ++ {
> ++ rtn = shmdt((char *)Cascade_Inf);
> ++ shmctl(CascadeInfShmid,IPC_RMID,(struct shmid_ds *)NULL);
> ++ }
> ++
> ++ if (Commit_Log_Tbl != (CommitLogInf *)NULL)
> ++ {
> ++ rtn = shmdt((char *)Commit_Log_Tbl);
> ++ shmctl(CommitLogShmid,IPC_RMID,(struct shmid_ds *)NULL);
> ++ }
> ++
> ++ if (Recovery_Status_Inf != (RecoveryStatusInf *)NULL)
> ++ {
> ++ rtn = shmdt((char *)Recovery_Status_Inf);
> ++ shmctl(RecoveryShmid,IPC_RMID,(struct shmid_ds *)NULL);
> ++ }
> ++ if (PGR_ReplicateSerializationID!=NULL)
> ++ {
> ++ shmdt(PGR_ReplicateSerializationID);
> ++ shmctl(ReplicateSerializationShmid,IPC_RMID,(struct shmid_ds
> *)NULL);
> ++ }
> ++
> ++ if (RecoveryMsgid)
> ++ {
> ++ if (*RecoveryMsgid >= 0)
> ++ msgctl(*RecoveryMsgid,IPC_RMID,(struct msqid_ds
> *)NULL);
> ++
> ++ shmdt(RecoveryMsgid);
> ++ shmctl(RecoveryMsgShmid, IPC_RMID, NULL);
> ++ }
> ++
> ++ if (StatusFp != NULL)
> ++ {
> ++ fflush(StatusFp);
> ++ fclose(StatusFp);
> ++ StatusFp = NULL;
> ++ }
> ++ if (LogFp != NULL)
> ++ {
> ++ fflush(LogFp);
> ++ fclose(LogFp);
> ++ 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 (CascadeSemID > 0)
> ++ {
> ++ sem_quit(CascadeSemID);
> ++ CascadeSemID = 0;
> ++ }
> ++ if (SemID > 0)
> ++ {
> ++ sem_quit(SemID);
> ++ SemID = 0;
> ++ }
> ++ if (RecoverySemID > 0)
> ++ {
> ++ sem_quit(RecoverySemID);
> ++ RecoverySemID = 0;
> ++ }
> ++ if (VacuumSemID > 0)
> ++ {
> ++ sem_quit(VacuumSemID);
> ++ }
> ++
> ++ 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;
> ++ }
> ++ exit(exit_status);
> ++}
> ++
> ++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 == DB_TBL_ERROR )
> ++ {
> ++ host_ptr->transaction_count = 0;
> ++
> 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 DB_TBL_FREE:
> ++ PGRwrite_log_file(StatusFp,"port(%d) host:%s free",
> ++ host_ptr->port,
> ++ host_ptr->hostName);
> ++ break;
> ++ case DB_TBL_INIT:
> ++ PGRwrite_log_file(StatusFp,"port(%d) host:%s
> initialize",
> ++ host_ptr->port,
> ++ host_ptr->hostName);
> ++ break;
> ++ case DB_TBL_USE:
> ++ PGRwrite_log_file(StatusFp,"port(%d) host:%s start
> use",
> ++ host_ptr->port,
> ++ host_ptr->hostName);
> ++ break;
> ++ case DB_TBL_ERROR:
> ++ PGRwrite_log_file(StatusFp,"port(%d) host:%s error",
> ++ host_ptr->port,
> ++ host_ptr->hostName);
> ++ break;
> ++ case DB_TBL_END:
> ++ PGRwrite_log_file(StatusFp,"port(%d) host:%s end",
> ++ host_ptr->port,
> ++ host_ptr->hostName);
> ++ break;
> ++ }
> ++}
> ++
> ++#if 0
> ++static int
> ++check_result( PGresult * res )
> ++{
> ++ int status = 0;
> ++
> ++ status = PQresultStatus(res);
> ++ if ((status == PGRES_NONFATAL_ERROR ) ||
> ++ (status == PGRES_FATAL_ERROR ))
> ++ {
> ++ return STATUS_ERROR;
> ++ }
> ++ return STATUS_OK;
> ++}
> ++#endif
> ++
> ++/*--------------------------------------------------
> ++ * 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,unsigned int replicationId, bool
> recovery)
> ++{
> ++ char * func = "PGRsend_replicate_packet_to_server()";
> ++ TransactionTbl * transaction_tbl = NULL;
> ++ char *database = NULL;
> ++ char port[8];
> ++ char *userName = NULL;
> ++ char * host = NULL;
> ++ int rtn = 0;
> ++ int current_cluster = 0;
> ++ int query_size = 0;
> ++
> ++ 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 size is broken",func);
> ++ return STATUS_ERROR;
> ++ }
> ++ if (host_ptr == NULL)
> ++ {
> ++ return STATUS_ERROR;
> ++ }
> ++
> ++ if (PGR_Response_Inf != NULL)
> ++ {
> ++ current_cluster = PGR_Response_Inf->current_cluster;
> ++ }
> ++
> ++ /*
> ++ * set up the connection
> ++ */
> ++ database = (char *)header->dbName;
> ++ snprintf(port,sizeof(port),"%d", host_ptr->port);
> ++ userName = (char *)header->userName;
> ++ host = host_ptr->resolvedName;
> ++#ifdef PRINT_DEBUG
> ++ show_debug("%s:host(%s) : port(%s)",func,host,port);
> ++#endif
> ++ /*
> ++ * 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)
> ++ {
> ++#ifdef PRINT_DEBUG
> ++ show_debug("%s:set new Transaction ",func);
> ++#endif
> ++ StartReplication[current_cluster] = true;
> ++ transaction_tbl = setTransactionTbl(host_ptr, header);
> ++ if (transaction_tbl == (TransactionTbl *)NULL)
> ++ {
> ++#ifdef PRINT_DEBUG
> ++ show_debug("%s:setTransactionTbl failed",func);
> ++#endif
> ++ if ( header->cmdSts != CMD_STS_NOTICE )
> ++ {
> ++ PGRset_host_status(host_ptr,DB_TBL_ERROR);
> ++ }
> ++ return STATUS_ERROR;
> ++ }
> ++ }
> ++ else
> ++ {
> ++ /*
> ++ * re-use the connection data
> ++ */
> ++ if ((transaction_tbl->conn != (PGconn *)NULL) &&
> ++ (transaction_tbl->conn->sock > 0))
> ++ {
> ++#ifdef PRINT_DEBUG
> ++ show_debug("%s:re-use Transaction ",func);
> ++#endif
> ++ StartReplication[current_cluster] = false;
> ++ }
> ++ else
> ++ {
> ++#ifdef PRINT_DEBUG
> ++ show_debug("%s:re-use failed. create new Transaction
> ",func);
> ++#endif
> ++ if (transaction_tbl->conn != (PGconn *)NULL)
> ++ {
> ++ PQfinish(transaction_tbl->conn);
> ++ transaction_tbl->conn = NULL;
> ++ }
> ++ transaction_tbl->conn =
> pgr_createConn(host,port,database,userName);
> ++ StartReplication[current_cluster] = true;
> ++ }
> ++ }
> ++#ifdef PRINT_DEBUG
> ++ show_debug("%s:connect db:%s port:%s user:%s host:%s ",
> ++ func, database,port,userName,host);
> ++#endif
> ++ rtn = send_replicate_packet_to_server( transaction_tbl,
> current_cluster, host_ptr, header, query ,result ,replicationId, recovery);
> ++ return rtn;
> ++}
> ++
> ++static int
> ++send_replicate_packet_to_server( TransactionTbl * transaction_tbl, int
> current_cluster, HostTbl * host_ptr, ReplicateHeader * header, char *query
> , char * result,unsigned int replicationId, bool recovery)
> ++{
> ++ char * func = "send_replicate_packet_to_server()";
> ++ PGconn * conn = (PGconn *)NULL;
> ++ PGresult * res = (PGresult *)NULL;
> ++ char sync_command[256];
> ++ bool sync_command_flg = false;
> ++ char * str = NULL;
> ++ int rtn = 0;
> ++ int query_size = 0;
> ++ int hostNum = 0;
> ++ StringInfoData input_message;
> ++
> ++ if (( transaction_tbl == (TransactionTbl *)NULL) ||
> ++ ( host_ptr == (HostTbl *) NULL) ||
> ++ (header == (ReplicateHeader *) NULL) ||
> ++ (query == NULL) ||
> ++ ( result == NULL))
> ++ {
> ++ show_debug("%s:unexpected NULL variable");
> ++ return STATUS_ERROR;
> ++ }
> ++
> ++ query_size = ntohl(header->query_size);
> ++ if (query_size < 0)
> ++ {
> ++ show_error("%s: query size is broken",func);
> ++
> ++ return STATUS_ERROR;
> ++ }
> ++
> ++ if(header->cmdSts == CMD_STS_OTHER &&
> ++ header->cmdType == CMD_TYPE_CONNECTION_CLOSE)
> ++ {
> ++ check_delete_transaction(host_ptr,header);
> ++ return STATUS_OK;
> ++ }
> ++
> ++ 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,DB_TBL_ERROR);
> ++ }
> ++ return STATUS_ERROR;
> ++ }
> ++ hostNum = host_ptr->hostNum;
> ++
> ++#if 0
> ++ /* check query id */
> ++ if (*(PGR_Send_Query_ID + hostNum ) == ntohl(header->query_id))
> ++ {
> ++ return STATUS_OK;
> ++ }
> ++#endif
> ++
> ++ /*
> ++ * When the query is transaction query...
> ++ */
> ++ if (is_need_sync_time(header) == true)
> ++ {
> ++ if (transaction_tbl->transaction_count >1 )
> ++ {
> ++ sync_command_flg = false;
> ++ }
> ++ else
> ++ {
> ++ 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) ||
> ++ (transaction_tbl->transaction_count >1 )))
> ++ {
> ++ sync_command_flg = false;
> ++ }
> ++ }
> ++ */
> ++
> ++ /*
> ++ * execute query
> ++ */
> ++
> ++ if (header->rlog > 0 )
> ++ {
> ++
> ++ if (is_executed_query( conn, header) == true)
> ++ {
> ++ return STATUS_OK;
> ++ }
> ++ else
> ++ {
> ++ show_debug("%s:check replication log issue ,
> id=%d,rlog=%d,query=%s
> status=not_replicated",func,ntohl(header->replicate_id),header->rlog,query);
> ++ }
> ++ }
> ++ if (( header->cmdSts != CMD_STS_NOTICE ) &&
> ++ ( header->cmdSts != CMD_STS_PREPARE ) &&
> ++ ((sync_command_flg == true) ||
> ++ (StartReplication[current_cluster] == true)))
> ++ {
> ++ snprintf(sync_command,sizeof(sync_command),
> ++ "SELECT %s(%d,%u,%u,%u,%d,%u) ",
> ++ 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,
> ++ *PGR_ReplicateSerializationID);
> ++#ifdef PRINT_DEBUG
> ++ show_debug("%s:sync_command(%s)",func,sync_command);
> ++#endif
> ++ res = PQexec(conn, sync_command);
> ++ if (res != NULL)
> ++ {
> ++#ifdef PRINT_DEBUG
> ++ show_debug("%s:sync_command returns
> %s",func,PQcmdStatus(res));
> ++#endif
> ++ PQclear(res);
> ++ }
> ++ StartReplication[current_cluster] = false;
> ++ }
> ++
> ++ res = NULL;
> ++ 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) /* failed */
> ++ {
> ++ if (transaction_tbl->conn != NULL)
> ++ {
> ++ PQfinish(transaction_tbl->conn);
> ++ transaction_tbl->conn = (PGconn
> *)NULL;
> ++ StartReplication[current_cluster] =
> true;
> ++ }
> ++ }
> ++ }
> ++ *(PGR_Send_Query_ID + hostNum ) == ntohl(header->query_id);
> ++ return STATUS_OK;
> ++ }
> ++ else if (header->cmdSts == CMD_STS_LARGE_OBJECT)
> ++ {
> ++ replicate_lo(conn, header,(LOArgs *)query);
> ++ return STATUS_OK;
> ++ }
> ++ else if (header->cmdSts == CMD_STS_PREPARE)
> ++ {
> ++
> ++ if ( !PGR_Parse_Session_Started)
> ++ {
> ++ snprintf(sync_command,sizeof(sync_command),
> ++ "SELECT %s(%d,%u,%u,%u,%d,%u) ",
> ++ 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,
> ++ *PGR_ReplicateSerializationID);
> ++#ifdef PRINT_DEBUG
> ++ show_debug("%s:sync_command [%s]",func,sync_command);
> ++#endif
> ++ res = PQexec(conn, sync_command);
> ++ if (res != NULL)
> ++ {
> ++#ifdef PRINT_DEBUG
> ++ show_debug("%s:sync_command returns
> %s",func,PQcmdStatus(res));
> ++#endif
> ++ PQclear(res);
> ++ res = NULL;
> ++ }
> ++ while ((res = PQgetResult(conn)) != NULL)
> ++ {
> ++ if (res->resultStatus == PGRES_COPY_IN)
> ++ {
> ++ PQclear(res);
> ++ return STATUS_ERROR;
> ++ }
> ++ else if (res->resultStatus == PGRES_COPY_OUT)
> ++ {
> ++ conn->asyncStatus = PGASYNC_BUSY;
> ++ }
> ++ else if (conn->status == CONNECTION_BAD)
> ++ {
> ++ PQclear(res);
> ++ return STATUS_ERROR;
> ++ }
> ++ PQclear(res);
> ++ }
> ++ }
> ++ set_string_info(&input_message,header,query);
> ++ switch (header->cmdType)
> ++ {
> ++ case CMD_TYPE_P_PARSE :
> ++ if (send_p_parse(conn, &input_message) !=
> STATUS_OK)
> ++ {
> ++ pqHandleSendFailure(conn);
> ++ PGR_Parse_Session_Started = false;
> ++ return STATUS_ERROR;
> ++ }
> ++ break;
> ++ case CMD_TYPE_P_BIND :
> ++ if (send_p_bind(conn, &input_message) !=
> STATUS_OK)
> ++ {
> ++ pqHandleSendFailure(conn);
> ++ PGR_Parse_Session_Started = false;
> ++ return STATUS_ERROR;
> ++ }
> ++ break;
> ++ case CMD_TYPE_P_DESCRIBE :
> ++ if (send_p_describe(conn, &input_message) !=
> STATUS_OK)
> ++ {
> ++ pqHandleSendFailure(conn);
> ++ PGR_Parse_Session_Started = false;
> ++ return STATUS_ERROR;
> ++ }
> ++ break;
> ++ case CMD_TYPE_P_EXECUTE :
> ++ if (send_p_execute(conn,&input_message) !=
> STATUS_OK)
> ++ {
> ++ pqHandleSendFailure(conn);
> ++ PGR_Parse_Session_Started = false;
> ++ return STATUS_ERROR;
> ++ }
> ++ break;
> ++ case CMD_TYPE_P_SYNC :
> ++ if (send_p_sync(conn, &input_message) !=
> STATUS_OK)
> ++ {
> ++ pqHandleSendFailure(conn);
> ++ PGR_Parse_Session_Started = false;
> ++ return STATUS_ERROR;
> ++ }
> ++ break;
> ++ case CMD_TYPE_P_CLOSE :
> ++ if (send_p_close(conn, &input_message) !=
> STATUS_OK)
> ++ {
> ++ pqHandleSendFailure(conn);
> ++ PGR_Parse_Session_Started = false;
> ++ return STATUS_ERROR;
> ++ }
> ++ break;
> ++ default :
> ++ break;
> ++ }
> ++ return STATUS_OK;
> ++ }
> ++ else
> ++ {
> ++ if (transaction_tbl->lock != STATUS_OK)
> ++ {
> ++#ifdef PRINT_DEBUG
> ++ show_debug("%s:[%d]transaction_tbl->lock is
> [%d]",func,current_cluster,transaction_tbl->lock );
> ++#endif
> ++ transaction_tbl->lock = STATUS_OK;
> ++ }
> ++ snprintf(sync_command,sizeof(sync_command),
> ++ "SELECT %s(%d,%u,%u,%d) ",
> ++ PGR_SYSTEM_COMMAND_FUNC,
> ++ PGR_SET_CURRENT_REPLICATION_QUERY_ID_NO,
> ++ replicationId,
> ++ 0,
> ++ 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)
> ++ {
> ++#ifdef PRINT_DEBUG
> ++ show_debug("%s:sync_command returns
> %s",func,PQcmdStatus(res));
> ++#endif
> ++ PQclear(res);
> ++ res = NULL;
> ++ }
> ++
> ++#ifdef PRINT_DEBUG
> ++ show_debug("%s:execute query(%s)",func,query);
> ++#endif
> ++ res = PQexec(conn, query);
> ++
> ++ }
> ++
> ++ if (res == NULL)
> ++ {
> ++ StartReplication[current_cluster] = true;
> ++ show_debug("%s:PQexec status error",func);
> ++ return STATUS_ERROR;
> ++ }
> ++
> ++ str = PQcmdStatus(res);
> ++#ifdef PRINT_DEBUG
> ++ show_debug("%s:PQexec returns :%s",func,str);
> ++#endif
> ++ 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);
> ++
> ++ transaction_tbl->lock = STATUS_LOCK_CONFLICT;
> ++ 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);
> ++ transaction_tbl->lock = STATUS_DEADLOCK_DETECT;
> ++ 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->query_id);
> ++
> ++ /*
> ++ * if the query is end transaction process...
> ++ */
> ++ check_delete_transaction(host_ptr,header);
> ++ return STATUS_OK;
> ++
> ++}
> ++
> ++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_OTHER &&
> ++ header->cmdType == CMD_TYPE_CONNECTION_CLOSE)
> ++ {
> ++ notice_abort(host_ptr, header);
> ++ deleteTransactionTbl(host_ptr,header);
> ++ }
> ++
> ++ delete_template(host_ptr, header);
> ++ return STATUS_OK;
> ++}
> ++
> ++static void
> ++check_transaction_status(ReplicateHeader * header,
> ++ HostTbl *host,
> ++ TransactionTbl *transaction)
> ++{
> ++ static bool exec_copy = false;
> ++ if (header == (ReplicateHeader *)NULL)
> ++ {
> ++ return;
> ++ }
> ++ if (header->cmdSts == CMD_STS_TRANSACTION )
> ++ {
> ++ if (header->cmdType == CMD_TYPE_BEGIN )
> ++ {
> ++ host->transaction_count++;
> ++ transaction->in_transaction = true;
> ++ transaction->transaction_count ++;
> ++ }
> ++ else if ((header->cmdType == CMD_TYPE_COMMIT) ||
> ++ (header->cmdType == CMD_TYPE_ROLLBACK))
> ++ {
> ++ host->transaction_count--;
> ++ transaction->transaction_count --;
> ++ if (transaction->transaction_count == 0)
> ++ {
> ++ transaction->in_transaction = false;
> ++ }
> ++ }
> ++ }
> ++ else
> ++ {
> ++ if ( header->cmdType == CMD_TYPE_COPY )
> ++ {
> ++ exec_copy = true;
> ++ host->transaction_count--;
> ++ }
> ++ else if (header->cmdType == CMD_TYPE_COPY_DATA_END)
> ++ {
> ++ if (exec_copy)
> ++ host->transaction_count--;
> ++ exec_copy = false;
>
> ++ }
> ++ }
> ++
> ++}
> ++/*
> ++ * set query in queue
> ++ */
> ++int
> ++PGRset_queue(ReplicateHeader * header,char * query)
> ++{
> ++ char * func = "PGRset_queue()";
> ++ RecoveryQueueHeader * msg_header = NULL;
> ++ RecoveryQueueQuery * msg_query = NULL;
> ++ int size = 0;
> ++ long mtype = 0;
> ++ int rtn = 0;
> ++ int query_size = 0;
> ++
> ++ if ((*RecoveryMsgid < 0) || (header == NULL))
> ++ {
> ++ return STATUS_ERROR;
> ++ }
> ++
> ++ query_size = ntohl(header->query_size);
> ++ if (query_size < 0)
> ++ {
> ++ return STATUS_ERROR;
> ++ }
> ++ /*
> ++ * set header data
> ++ */
> ++ size = sizeof(ReplicateHeader) + sizeof(RecoveryQueueHeader);
> ++ mtype = *PGR_ReplicateSerializationID;
> ++ msg_header = (RecoveryQueueHeader *)malloc(size+4);
> ++ if (msg_header == NULL)
> ++ {
> ++ show_error("%s:malloc() failed. reason: %s", func,
> strerror(errno));
> ++ return STATUS_ERROR;
> ++ }
> ++ memset(msg_header,0,size+4);
> ++ msg_header->mtype = RECOVERY_HEADER_MTYPE;
> ++ msg_header->query_mtype = mtype;
> ++ memcpy(msg_header->mdata,header,sizeof(ReplicateHeader));
> ++
> ++ /*
> ++ * set query data
> ++ */
> ++ size = query_size + sizeof(RecoveryQueueQuery);
> ++ msg_query = (RecoveryQueueQuery *) malloc(size+4);
> ++ if (msg_query == NULL)
> ++ {
> ++ show_error("%s:malloc() failed. reason: %s", func,
> strerror(errno));
> ++ free(msg_header);
> ++ msg_header = NULL;
> ++ return STATUS_ERROR;
> ++ }
> ++ memset(msg_query,0,size+4);
> ++ msg_query->mtype = mtype;
> ++ msg_query->replicationId=*PGR_ReplicateSerializationID;
> ++ memcpy(msg_query->mdata,query,query_size);
> ++
> ++
> ++
> ++ /*
> ++ * send header data to queue
> ++ */
> ++ rtn = msgsnd(*RecoveryMsgid, msg_header,
> sizeof(long)+sizeof(ReplicateHeader), IPC_NOWAIT);
> ++ if (rtn < 0)
> ++ {
> ++ show_error("%s:msgsnd failed. reason: %s", func,
> strerror(errno));
> ++ free(msg_header);
> ++ free(msg_query);
> ++ msgctl(*RecoveryMsgid, IPC_RMID, NULL);
> ++ *RecoveryMsgid = msgget (IPC_PRIVATE, 00666 | IPC_CREAT );
> ++ return STATUS_ERROR;
> ++ }
> ++ /*
> ++ * send query data to queue
> ++ */
> ++ rtn = msgsnd(*RecoveryMsgid, msg_query, sizeof(unsigned
> int)+query_size, IPC_NOWAIT);
> ++ if (rtn < 0)
> ++ {
> ++ show_error("%s:msgsnd failed. reason: %s", func,
> strerror(errno));
> ++ free(msg_header);
> ++ free(msg_query);
> ++ msgctl(*RecoveryMsgid, IPC_RMID, NULL);
> ++ *RecoveryMsgid = msgget (IPC_PRIVATE, 00666 | IPC_CREAT );
> ++ return STATUS_ERROR;
> ++ }
> ++
> ++ /*
> ++ * release memory
> ++ */
> ++ free(msg_header);
> ++ free(msg_query);
> ++ msg_header = NULL;
> ++ msg_query = NULL;
> ++
> ++ 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 != DB_TBL_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_connections(void)
> ++{
> ++ Dlelem *ptr = NULL, *next;
> ++
> ++ pthread_mutex_lock(&transaction_table_mutex);
> ++ ptr = DLGetHead(Transaction_Tbl_Begin);
> ++ while (ptr)
> ++ {
> ++ TransactionTbl *transaction = DLE_VAL(ptr);
> ++ if (transaction->conn != NULL)
> ++ {
> ++ PQfinish(transaction->conn);
> ++ }
> ++ next = DLGetSucc(ptr);
> ++ DLRemove(ptr);
> ++ DLFreeElem(ptr);
> ++ ptr = next;
> ++ }
> ++ DLFreeList(Transaction_Tbl_Begin);
> ++ Transaction_Tbl_Begin = NULL;
> ++ pthread_mutex_unlock(&transaction_table_mutex);
> ++}
> ++
> ++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_VACUUM) ||
> ++ (header->cmdType == CMD_TYPE_ANALYZE) ||
> ++ (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->cmdSts == CMD_STS_PREPARE)
> ++ {
> ++ rtn = false;
> ++ }
> ++ else 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_VACUUM) ||
> ++ (header->cmdType == CMD_TYPE_ANALYZE) ||
> ++ (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 ((! strncmp(header->dbName,"template1",9)) ||
> ++ (! strncmp(header->dbName,"template0",9)))
> ++ {
> ++ if ((header->cmdSts != CMD_STS_TRANSACTION ) &&
> ++ ( header->cmdSts != CMD_STS_SET_SESSION_AUTHORIZATION
> ) &&
> ++ ( header->cmdSts != CMD_STS_TEMP_TABLE ))
> ++ {
> ++ 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()";
> ++
> ++ if (Recovery_Status_Inf == (RecoveryStatusInf *)NULL)
> ++ {
> ++ show_error("%s: Recovery_Status_Inf is NULL",func);
> ++ return -1;
> ++ }
> ++ Recovery_Status_Inf->replication_id ++;
> ++ Recovery_Status_Inf->check_point --;
> ++ return (Recovery_Status_Inf->replication_id);
> ++}
> ++
> ++static void
> ++check_replication_id(void)
> ++{
> ++ char * func = "check_replication_id()";
> ++
> ++ if (Recovery_Status_Inf == (RecoveryStatusInf *)NULL)
> ++ {
> ++ show_error("%s: Recovery_Status_Inf is NULL",func);
> ++ return ;
> ++ }
> ++ if (Recovery_Status_Inf->check_point < 0)
> ++ {
> ++ Recovery_Status_Inf->check_point = PGR_CHECK_POINT ;
> ++ rewind(RidFp);
> ++
> PGRwrite_log_file(RidFp,"%u",Recovery_Status_Inf->replication_id +
> PGR_CHECK_POINT );
> ++ }
> ++}
> ++
> ++int
> ++PGRset_replication_id(uint32_t id)
> ++{
> ++ char * func = "set_replication_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;
> ++ char * query_string = NULL;
> ++
> ++ if (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;
> ++ }
> ++ }
> ++ }
> ++ header->isAutoCommit=PGR_AutoCommit ? 1 : 0;
> ++ gettimeofday(&tv,NULL);
> ++ header->tv.tv_sec = htonl(tv.tv_sec);
> ++ header->tv.tv_usec = htonl(tv.tv_usec);
> ++
> ++ /* set query id */
> ++ header->query_id = htonl(PGRget_next_query_id());
> ++
> ++ /* save header for logging */
> ++ if (is_need_sync_time(header) == 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();
> ++
> ++ /* send replication packet */
> ++ status = PGRreplicate_packet_send(
> header,query_string,sock,recovery_status);
> ++ show_debug("%s:PGRreplicate_packet_send returns %d",func,status);
> ++
> ++#if 0
> ++ if(recovery_status == RECOVERY_START &&
> ++ PGRset_queue(header,query_string)!= STATUS_OK)
> ++ {
> ++ /*
> ++ *Failed to set queue. abort.
> ++ */
> ++ show_error("%s:failed to put query to queue.abort to
> recovery",func);
> ++ PGRset_recovery_status(RECOVERY_INIT);
> ++ }
> ++#endif
> ++
> ++ if ((header->cmdType == CMD_TYPE_COPY) &&
> ++ (query_string != NULL))
> ++ {
> ++ free(query_string);
> ++ query_string = 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)
> ++ * char *result: result data(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, char * result, 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 flag = 0;
> ++
> ++ if (result == NULL)
> ++ {
> ++ show_error("%s:result is not initialize",func);
> ++ return STATUS_ERROR;
> ++ }
> ++ if (dest < 0)
> ++ {
> ++ return STATUS_ERROR;
> ++ }
> ++ send_ptr = result;
> ++ buf_size = PGR_MESSAGE_BUFSIZE;
> ++ if (buf_size < 1)
> ++ buf_size = 1;
> ++
> ++ /*
> ++ * Wait for something to happen.
> ++ */
> ++#ifdef MSG_DONTWAIT
> ++ flag |= MSG_DONTWAIT;
> ++#endif
> ++#ifdef MSG_NOSIGNAL
> ++ flag |= MSG_NOSIGNAL;
> ++#endif
> ++
> ++ for (;;)
> ++ {
> ++ timeout.tv_sec = PGR_SEND_TIMEOUT;
> ++ timeout.tv_usec = 0;
> ++
> ++ FD_ZERO(&wmask);
> ++ FD_SET(dest,&wmask);
> ++
> ++ rtn = select(dest+1, (fd_set *)NULL, &wmask, (fd_set *)NULL,
> &timeout);
> ++ if (rtn < 0)
> ++ {
> ++ if (errno == EINTR || errno == EAGAIN)
> ++ continue;
> ++
> ++ show_error("%s:select failed ,errno is %s",func ,
> strerror(errno));
> ++ return STATUS_ERROR;
> ++ }
> ++ else if (rtn && FD_ISSET(dest, &wmask))
> ++ {
> ++ s = send(dest,send_ptr + send_size,buf_size -
> send_size ,flag);
> ++ if (s < 0)
> ++ {
> ++ if (errno == EINTR || errno == EAGAIN)
> ++ continue;
> ++ else
> ++ {
> ++ show_error("%s:send error: %d(%s)",
> func, errno, strerror(errno));
> ++ memset(send_ptr, 0,
> PGR_MESSAGE_BUFSIZE);
> ++ return STATUS_ERROR;
> ++ }
> ++ }
> ++ else if (s > 0)
> ++ {
> ++ send_size += s;
> ++ if (send_size == buf_size)
> ++ {
> ++ status = STATUS_OK;
> ++ if (wait == PGR_WAIT_ANSWER)
> ++ {
> ++ status = read_answer(dest);
> ++ }
> ++ return status;
> ++ }
> ++ }
> ++ else /* s == 0 */
> ++ {
> ++ show_error("%s:unexpected EOF", func);
> ++ 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 < 0)
> ++ {
> ++ if (errno == EINTR || errno == EAGAIN)
> ++ continue;
> ++
> ++ show_error("%s:select failed ,errno is %s",func ,
> strerror(errno));
> ++ return STATUS_ERROR;
> ++ }
> ++ else 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:[%c]none response packet
> received",func,header.cmdSts);
> ++ free(answer);
> ++ answer = NULL;
> ++ status = STATUS_ERROR;
> ++ break;
> ++ }
> ++ 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,int recovery_status) {
> ++ return
> replicate_packet_send_internal(header,query,dest,recovery_status,false);
> ++}
> ++
> ++
> ++int
> ++replicate_packet_send_internal(ReplicateHeader * header, char * query,int
> dest,int recovery_status,bool isHeldLock)
> ++{
> ++ char * func = "PGRreplicate_packet_send()";
> ++ HostTbl * host_ptr = (HostTbl*)NULL;
> ++ HostTbl * source_host_ptr = (HostTbl*)NULL;
> ++ int status = STATUS_OK;
> ++ int sem_cnt = 0;
> ++ int sem_id = 0;
> ++ char *database = NULL;
> ++ char port[8];
> ++ char *userName = NULL;
> ++ char * host = NULL;
> ++ char result[PGR_MESSAGE_BUFSIZE];
> ++
> ++ pthread_attr_t attr;
> ++ int rc = 0;
> ++ int t = 0;
> ++ int t_cnt = 0;
> ++ int source_t_cnt = -1;
> ++ int transaction_count = 0;
> ++
> ++
> ++ pthread_t thread[MAX_DB_SERVER];
> ++ ThreadArgInf thread_arg[MAX_DB_SERVER];
> ++
> ++
> ++#ifdef PRINT_DEBUG
> ++ show_debug("cmdSts=%c",header->cmdSts);
> ++ if(header->cmdType!='\0')
> ++ show_debug("cmdType=%c",header->cmdType);
> ++ show_debug("rlog=%d",header->rlog);
> ++ show_debug("port=%d",ntohs(header->port));
> ++ show_debug("pid=%d",ntohs(header->pid));
> ++ show_debug("from_host=%s",header->from_host);
> ++ show_debug("dbName=%s",header->dbName);
> ++ show_debug("userName=%s",header->userName);
> ++ show_debug("recieve sec=%u",ntohl(header->tv.tv_sec));
> ++ show_debug("recieve usec=%u",ntohl(header->tv.tv_usec));
> ++ show_debug("query_size=%d",ntohl(header->query_size));
> ++ show_debug("request_id=%d",ntohl(header->request_id));
> ++ show_debug("replicate_id=%d",ntohl(header->replicate_id));
> ++ if (header->cmdSts != CMD_STS_PREPARE)
> ++ {
> ++ show_debug("query=%s",query);
> ++ }
> ++#endif
> ++
> ++ /* check rlog type */
> ++ 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(result,0,sizeof(result));
> ++ sem_cnt = 1;
> ++
> ++ if (is_need_queue_jump(header,query) == false)
> ++ {
> ++ sem_id = SemID;
> ++ }
> ++ else
> ++ {
> ++ sem_id = VacuumSemID;
> ++ }
> ++ if(!isHeldLock) {
> ++#ifdef PRINT_DEBUG
> ++
> ++ show_debug("sem_lock [%d] req",sem_cnt);
> ++#endif
> ++
> ++ PGRsem_lock(sem_id,sem_cnt);
> ++#ifdef PRINT_DEBUG
> ++ show_debug("sem_lock [%d] got it",sem_cnt);
> ++#endif
> ++ }
> ++ ++*PGR_ReplicateSerializationID;
> ++
> ++ /* 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 != DB_TBL_END)
> ++ {
> ++ show_debug("%s:checking host %s for creating
> threads",func,host_ptr->hostName);
> ++ /*
> ++ * check the status of the cluster DB
> ++ */
> ++ if (host_ptr->useFlag != DB_TBL_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,recovery_status) == true)
> ++ {
> ++ TransactionTbl *transaction_tbl =
> getTransactionTbl(host_ptr,header);
> ++ if (host_ptr->transaction_count == 0 ||
> ++ transaction_tbl == NULL ||
> ++ transaction_tbl->in_transaction == false)
> ++ {
> ++ if (PGRset_queue(header,query) != STATUS_OK)
> ++ {
> ++ show_error("%s:failed to put query to
> queue.abort to recovery",func);
> ++ PGRset_recovery_status(RECOVERY_INIT);
> ++ }
> ++#ifdef PRINT_DEBUG
> ++ show_debug("%s master is using for
> recovery",func);
> ++#endif
> ++ host_ptr ++;
> ++ continue;
> ++ }
> ++ }
> ++ /*
> ++ * 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;
> ++ thread_arg[t_cnt].current_cluster = t_cnt;
> ++ thread_arg[t_cnt].transaction_tbl = (TransactionTbl *)NULL;
> ++
> ++ if
> (PGRis_same_host(header->from_host,ntohs(header->port),host_ptr->resolvedName,
> host_ptr->port) == true)
> ++ {
> ++ show_debug("[%d] is same host",t_cnt);
> ++ /* replication to source cluster db */
> ++ source_host_ptr = host_ptr;
> ++ source_t_cnt = t_cnt;
> ++
> ++ if (header->rlog == FROM_R_LOG_TYPE )
> ++ {
> ++#ifdef PRINT_DEBUG
> ++ show_debug("%s: This simple query was
> suspended. Therefore this query is not re-replicated to source cluster
> db.",func);
> ++#endif
> ++ }
> ++ t_cnt++;
> ++ }
> ++ /* replication to other cluster db */
> ++ else
> ++ {
> ++ show_debug("[%d] is not same host",t_cnt);
> ++ 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
> ++ {
> ++ /*
> ++ * get the transaction table data
> ++ * it has the connection data with each
> cluster DB
> ++ */
> ++ thread_arg[t_cnt].transaction_tbl =
> getTransactionTbl(host_ptr,header);
> ++ /*
> ++ * if the transaction process is new one,
> ++ * create connection data and add the
> transaction table
> ++ */
> ++ if (thread_arg[t_cnt].transaction_tbl ==
> (TransactionTbl *)NULL)
> ++ {
> ++ thread_arg[t_cnt].transaction_tbl =
> setTransactionTbl(host_ptr, header);
> ++ if (thread_arg[t_cnt].transaction_tbl
> == (TransactionTbl *)NULL)
> ++ {
> ++#ifdef PRINT_DEBUG
> ++
> show_debug("%s:setTransactionTbl failed",func);
> ++#endif
> ++ if ( header->cmdSts !=
> CMD_STS_NOTICE )
> ++ {
> ++
> PGRset_host_status(host_ptr,DB_TBL_ERROR);
> ++ }
> ++ host_ptr ++;
> ++ continue;
> ++ }
> ++ StartReplication[t_cnt] = true;
> ++ }
> ++ else
> ++ {
> ++ /*
> ++ * re-use the connection data
> ++ */
> ++ if
> ((thread_arg[t_cnt].transaction_tbl->conn != (PGconn *)NULL) &&
> ++
> (thread_arg[t_cnt].transaction_tbl->conn->sock > 0))
> ++ {
> ++ /*
> ++
> memset(thread_arg[t_cnt].transaction_tbl->conn->inBuffer,0,thread_arg[t_cnt].transaction_tbl->conn->inBufSize);
> ++
> memset(thread_arg[t_cnt].transaction_tbl->conn->outBuffer,0,thread_arg[t_cnt].transaction_tbl->conn->outBufSize);
> ++ */
> ++ StartReplication[t_cnt] =
> false;
> ++ }
> ++ else
> ++ {
> ++ if
> (thread_arg[t_cnt].transaction_tbl->conn != (PGconn *)NULL)
> ++ {
> ++
> PQfinish(thread_arg[t_cnt].transaction_tbl->conn);
> ++
> thread_arg[t_cnt].transaction_tbl->conn = NULL;
> ++ }
> ++
> ++ database = (char
> *)header->dbName;
> ++
> snprintf(port,sizeof(port),"%d", host_ptr->port);
> ++ userName = (char
> *)header->userName;
> ++ host = host_ptr->hostName;
> ++
> ++
> thread_arg[t_cnt].transaction_tbl->conn =
> pgr_createConn(host,port,database,userName);
> ++ StartReplication[t_cnt] =
> true;
> ++ }
> ++ }
> ++ check_transaction_status(header, host_ptr,
> thread_arg[t_cnt].transaction_tbl);
> ++ transaction_count =
> thread_arg[t_cnt].transaction_tbl->transaction_count;
> ++ rc = pthread_create(&thread[t_cnt], &attr,
> thread_send_cluster, (void*)&thread_arg[t_cnt]);
> ++
> ++ if (rc)
> ++ {
> ++ show_error("pthread_create error");
> ++ }
> ++ t_cnt++;
> ++ }
> ++ }
> ++ /*
> ++ * 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; )
> ++ {
> ++ if (t == source_t_cnt)
> ++ {
> ++ t++;
> ++ continue;
> ++ }
> ++ rc = pthread_join(thread[t], (void **)NULL);
> ++ if ((rc != 0) && (errno == EINTR))
> ++ {
> ++ usleep(100);
> ++ continue;
> ++ }
> ++ pthread_detach(thread[t]);
> ++ t++;
> ++ }
> ++
> ++ thread_arg[source_t_cnt].transaction_count = transaction_count;
> ++ /*
> ++ * send replication query to source cluster server.
> ++ */
> ++ if (source_t_cnt >= 0)
> ++ {
> ++ thread_send_source( (void*)&thread_arg[source_t_cnt]);
> ++ }
> ++ else
> ++ {
> ++ show_debug("thread_send_source was not executed");
> ++ }
> ++ /* unset replication log */
> ++ if (is_need_use_rlog(header) == true)
> ++ {
> ++ PGRunset_rlog(header,query);
> ++ }
> ++
> ++ check_replication_id();
> ++ if (header->cmdSts == CMD_STS_PREPARE)
> ++ {
> ++ if (header->cmdType != CMD_TYPE_P_SYNC)
> ++ {
> ++ if (PGR_Parse_Session_Started == false)
> ++ {
> ++ PGR_Parse_Session_Started = true;
> ++ }
> ++ }
> ++ }
> ++ else
> ++ {
> ++ PGR_Parse_Session_Started = false;
> ++ }
> ++
> ++ if(!isHeldLock) {
> ++#ifdef PRINT_DEBUG
> ++ show_debug("sem_unlock[%d]",sem_cnt);
> ++#endif
> ++ PGRsem_unlock(sem_id,sem_cnt);
> ++ }
> ++ 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;
> ++ int transaction_count = 0;
> ++ char result[PGR_MESSAGE_BUFSIZE];
> ++ bool sync_command_flg = false;
> ++
> ++ if (arg == NULL)
> ++ {
> ++ show_error("%s:arg is NULL",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;
> ++ transaction_count = thread_arg->transaction_count;
> ++
> ++ if(header->cmdSts==CMD_STS_OTHER &&
> ++ header->cmdType==CMD_TYPE_CONNECTION_CLOSE)
> ++ {
> ++ return (void *)0;
> ++ }
> ++
> ++ 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);
> ++ return (void *)status;
> ++ }
> ++
> ++ /**
> ++ * NOTE:
> ++ * We can use PGR_ReplicateSerializationID here , because
> ++ * all queries from cluster server isn't recovery query.
> ++ *
> ++ */
> ++ if (is_need_sync_time(header) == true)
> ++ {
> ++ if (transaction_count >1 )
> ++ {
> ++ sync_command_flg = false;
> ++ }
> ++ else
> ++ {
> ++ sync_command_flg = true;
> ++ }
> ++ }
> ++ if (sync_command_flg == true)
> ++ {
> ++ snprintf(result,PGR_MESSAGE_BUFSIZE,
> ++ "%d,%u,%u,%u,%d,%u",
> ++ 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,
> ++ *PGR_ReplicateSerializationID);
> ++ }
> ++ else
> ++ {
> ++ snprintf(result,PGR_MESSAGE_BUFSIZE,
> ++ "%d,%u,%u,%d",
> ++ PGR_SET_CURRENT_REPLICATION_QUERY_ID_NO,
> ++ *PGR_ReplicateSerializationID,
> ++ 0,
> ++ 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,result, PGR_WAIT_ANSWER);
> ++ }
> ++ else
> ++ {
> ++ status = PGRreturn_result(dest, result, 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,DB_TBL_ERROR);
> ++ }
> ++
> ++ /* delete server table when query use template db */
> ++ if (PGR_Response_Inf->response_mode != PGR_RELIABLE_MODE)
> ++ {
> ++ delete_template(host_ptr,header);
> ++ }
> ++#ifdef PRINT_DEBUG
> ++ show_debug("end thread_send_source()");
> ++#endif
> ++ return (void *)0;
> ++ // 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;
> ++ TransactionTbl * transaction_tbl = (TransactionTbl *)NULL;
> ++ int current_cluster = 0;
> ++ char result[PGR_MESSAGE_BUFSIZE];
> ++
> ++#ifdef PRINT_DEBUG
> ++ show_debug("start thread_send_cluster()");
> ++#endif
> ++ if (arg == NULL)
> ++ {
> ++ show_error("%s:arg is NULL",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;
> ++ transaction_tbl = thread_arg->transaction_tbl;
> ++ current_cluster = thread_arg->current_cluster;
> ++
> ++
> ++ if(header->cmdSts==CMD_STS_OTHER &&
> ++ header->cmdType==CMD_TYPE_CONNECTION_CLOSE)
> ++ {
> ++ check_delete_transaction(host_ptr, header);
> ++ return (void *)0;
> ++ }
> ++
> ++
> ++ rtn = send_replicate_packet_to_server( transaction_tbl,
> current_cluster, host_ptr, header, query ,
> result,*PGR_ReplicateSerializationID, false);
> ++ show_debug("%s:return value from send_replicate_packet_to_server() is
> %d",func,rtn);
> ++ if (rtn == STATUS_ABORTED)
> ++ {
> ++ snprintf(result,PGR_MESSAGE_BUFSIZE,"%d",
> PGR_NOTICE_ABORT_FUNC_NO);
> ++#ifdef PRINT_DEBUG
> ++ show_debug("%s:pthread abort[%d]",func,current_cluster );
> ++#endif
> ++ status = PGRreturn_result(dest, result, PGR_NOWAIT_ANSWER);
> ++ status = STATUS_ABORTED;
> ++ pthread_exit((void *) status);
> ++ }
> ++ /* delete server table when query use template db */
> ++ delete_template(host_ptr,header);
> ++#ifdef PRINT_DEBUG
> ++ show_debug("%s:pthread_exit[%d]",func,current_cluster );
> ++#endif
> ++
> ++ 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, false);
> ++
> ++ 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;
> ++ fd_set rmask;
> ++ struct timeval timeout;
> ++ int rtn;
> ++
> ++ if (header == NULL)
> ++ {
> ++ return NULL;
> ++ }
> ++ memset(header,0,sizeof(ReplicateHeader));
> ++ read_ptr = (char*)header;
> ++ header_size = sizeof(ReplicateHeader);
> ++ cnt = 0;
> ++
> ++ for (;;){
> ++ /*
> ++ * read header data
> ++ */
> ++
> ++ timeout.tv_sec = 1;
> ++ 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 < 0)
> ++ {
> ++ if (errno == EINTR || errno == EAGAIN)
> ++ continue;
> ++
> ++ show_error("%s:select failed ,errno is %s",func ,
> strerror(errno));
> ++ return NULL;
> ++ }
> ++
> ++ if (rtn && FD_ISSET(sock, &rmask))
> ++ {
> ++ 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)
> ++ {
> ++ show_debug("%s:recv failed:
> (%s)",func,strerror(errno));
> ++ if (errno == EINTR || errno == EAGAIN)
> ++ continue;
> ++ else
> ++ {
> ++ show_error("%s:recv failed:
> (%s)",func,strerror(errno));
> ++ return NULL;
> ++ }
> ++ }
> ++ else if (r > 0)
> ++ {
> ++ read_size += r;
> ++ if ( read_size == header_size)
> ++ {
> ++ query = PGRread_query(sock,header);
> ++ return query;
> ++ }
> ++ }
> ++ else if (r == 0)
> ++ {
> ++ return NULL;
> ++ }
> ++ }
> ++ }
> ++ 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 || errno == EAGAIN)
> ++ continue;
> ++ else
> ++ {
> ++ show_error("%s:recv failed:
> (%s)",func,strerror(errno));
> ++ free(query);
> ++ query = NULL;
> ++ return NULL;
> ++ }
> ++ }
> ++ else if (r > 0)
> ++ {
> ++ read_size += r;
> ++ if ( read_size == query_size)
> ++ {
> ++ return query;
> ++ }
> ++ }
> ++ else /* r == 0 */
> ++ {
> ++ show_error("%s:unexpected EOF", func);
> ++ free(query);
> ++ query = NULL;
> ++ return NULL;
> ++ }
> ++ }
> ++ free(query);
> ++ query = NULL;
> ++ return NULL;
> ++}
> ++
> ++static bool
> ++is_autocommit_off(char * query)
> ++{
> ++ int i;
> ++ char buf[256];
> ++ 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[256];
> ++ 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)
> ++{
> ++ Dlelem * ptr = NULL;
> ++
> ++ pthread_mutex_lock(&transaction_table_mutex);
> ++ if (Transaction_Tbl_Begin == NULL)
> ++ {
> ++ pthread_mutex_unlock(&transaction_table_mutex);
> ++ return 0;
> ++ }
> ++ ptr = DLGetHead(Transaction_Tbl_Begin);
> ++ while (ptr)
> ++ {
> ++ TransactionTbl *transaction = DLE_VAL(ptr);
> ++ if
> (!strncmp(transaction->host,host,sizeof(transaction->host)))
> ++ {
> ++ pthread_mutex_unlock(&transaction_table_mutex);
> ++ return transaction->hostIP;
> ++ }
> ++ ptr = DLGetSucc(ptr);
> ++ }
> ++ pthread_mutex_unlock(&transaction_table_mutex);
> ++
> ++ return 0;
> ++}
> ++
> ++static unsigned int
> ++get_srcHost_ip_from_tbl(char * srcHost)
> ++{
> ++ Dlelem * ptr = NULL;
> ++
> ++ pthread_mutex_lock(&transaction_table_mutex);
> ++
> ++ if (Transaction_Tbl_Begin == NULL)
> ++ {
> ++ pthread_mutex_unlock(&transaction_table_mutex);
> ++
> ++ return 0;
> ++ }
> ++ ptr = DLGetHead(Transaction_Tbl_Begin);
> ++ while (ptr)
> ++ {
> ++ TransactionTbl *transaction = DLE_VAL(ptr);
> ++ if
> (!strncmp(transaction->srcHost,srcHost,sizeof(transaction->srcHost)))
> ++ {
> ++ pthread_mutex_unlock(&transaction_table_mutex);
> ++
> ++ return transaction->srcHostIP;
> ++ }
> ++ ptr = DLGetSucc(ptr);
> ++ }
> ++ pthread_mutex_unlock(&transaction_table_mutex);
> ++
> ++ 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;
> ++}
> ++
> ++
> ++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][%s][%d][%d]",func,hostName,userName,portNumber,recoveryPortNumber);
> ++#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
> ,RECOVERY_INIT);
> ++}
> ++
> ++static bool
> ++is_need_use_rlog(ReplicateHeader * header)
> ++{
> ++ bool rtn = false;
> ++ if ((Cascade_Inf->useFlag != DB_TBL_USE) ||
> ++ (PGR_Use_Replication_Log != true) ||
> ++ (header->rlog > 0))
> ++ {
> ++ 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->cmdType == CMD_TYPE_COMMIT))
> ++ {
> ++ rtn = true;
> ++ }
> ++ }
> ++ return rtn;
> ++}
> ++
> ++
> ++
> ++int
> ++PGRinit_transaction_table(void)
> ++{
> ++ if (Transaction_Tbl_Begin != NULL)
> ++ {
> ++ DLFreeList(Transaction_Tbl_Begin);
> ++ }
> ++
> ++ Transaction_Tbl_Begin = DLNewList();
> ++
> ++ return STATUS_OK;
> ++}
> ++
> ++
> ++static bool
> ++is_need_queue_jump( ReplicateHeader * header,char *query)
> ++{
> ++ if (header == NULL)
> ++ {
> ++ return true;
> ++ }
> ++
> ++ if (header->cmdSts == CMD_STS_QUERY)
> ++ {
> ++ if ((header->cmdType == CMD_TYPE_VACUUM ) ||
> ++ (header->cmdType == CMD_TYPE_ANALYZE ))
> ++ {
> ++ if ((strstr(query,"full") == NULL) &&
> ++ (strstr(query,"FULL") == NULL))
> ++ {
> ++ return true;
> ++ }
> ++ }
> ++ }
> ++ return false;
> ++}
> ++
> ++
> ++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 != DB_TBL_END)
> ++ {
> ++ /*
> ++ * check the status of the cluster DB
> ++ */
> ++ if (host_ptr->useFlag != DB_TBL_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 == DB_TBL_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, ReplicateHeader * header, LOArgs * query)
> ++{
> ++ int status = STATUS_OK;
> ++ int mode = 0;
> ++ Oid lobjId = 0;
> ++ int fd = 0;
> ++ char * buf = NULL;
> ++ char * filename = NULL;
> ++ size_t len = 0;
> ++ int offset = 0;
> ++ int whence = 0;
> ++
> ++ if ((conn == (PGconn *)NULL) || (query == (LOArgs *)NULL) || (header
> == (ReplicateHeader *)NULL))
> ++ {
> ++ return STATUS_ERROR;
> ++ }
> ++ switch (header->cmdType)
> ++ {
> ++ case CMD_TYPE_LO_IMPORT :
> ++ filename = query->buf;
> ++ if (lo_import(conn, filename) > 0 )
> ++ {
> ++ status = STATUS_OK;
> ++ }
> ++ else
> ++ {
> ++ status = STATUS_ERROR;
> ++ }
> ++ break;
> ++ 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
> ++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)
> ++ {
> ++ StartReplication[current_cluster] = true;
> ++ show_error("%s:setTransactionTbl failed",f);
> ++ if ( header->cmdSts != CMD_STS_NOTICE )
> ++ {
> ++ PGRset_host_status(host_ptr,DB_TBL_ERROR);
> ++ }
> ++ return STATUS_ERROR;
> ++ }
> ++ }
> ++ else
> ++ {
> ++ /*
> ++ * re-use the connection data
> ++ */
> ++ if ((transaction_tbl->conn != (PGconn *)NULL) &&
> ++ (transaction_tbl->conn->sock > 0))
> ++ {
> ++ StartReplication[current_cluster] = false;
> ++ }
> ++ else
> ++ {
> ++ if (transaction_tbl->conn != (PGconn *)NULL)
> ++ {
> ++ 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 )
> ++ {
> ++ StartReplication[current_cluster] = true;
> ++ PGRset_host_status(host_ptr,DB_TBL_ERROR);
> ++ }
> ++ 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) );
> ++}
> ++
> ++/*
> ++ * 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;
> ++ int recovery_status = 0;
> ++
> ++ /* get current oid of all cluster db's */
> ++ host_ptr = Host_Tbl_Begin;
> ++ if (host_ptr == (HostTbl *)NULL)
> ++ {
> ++ return STATUS_ERROR;
> ++ }
> ++ recovery_status = PGRget_recovery_status();
> ++ 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,recovery_status) == 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,recovery_status) == true)
> ++ {
> ++ host_ptr ++;
> ++ continue;
> ++ }
> ++ set_oid(host_ptr,header,max_oid);
> ++ host_ptr ++;
> ++ }
> ++
> ++ return STATUS_OK;
> ++}
> ++
> ++int
> ++PGRload_replication_id(void)
> ++{
> ++ char * func = "PGRload_replication_id()";
> ++ char buf[256];
> ++ char *p;
> ++
> ++ if (Recovery_Status_Inf == (RecoveryStatusInf *)NULL)
> ++ {
> ++ show_error("%s: Recovery_Status_Inf is NULL",func);
> ++ return STATUS_ERROR;
> ++ }
> ++ if (RidFp == (FILE *)NULL)
> ++ {
> ++ show_error("%s: replication id file is not open",func);
> ++ return STATUS_ERROR;
> ++ }
> ++ rewind(RidFp);
> ++ if (fgets(buf,sizeof(buf),RidFp) == NULL)
> ++ {
> ++ show_debug(" replication id file is empty");
> ++ Recovery_Status_Inf->replication_id = 0;
> ++ }
> ++ else
> ++ {
> ++ p = strrchr(buf,' ');
> ++ if (p != NULL)
> ++ {
> ++ p++;
> ++ Recovery_Status_Inf->replication_id = (uint32_t)
> atol(p);
> ++ show_debug(" set replication id
> [%u]",Recovery_Status_Inf->replication_id);
> ++ }
> ++ else
> ++ {
> ++ Recovery_Status_Inf->replication_id = 0;
> ++ show_debug("no replicationid in this file");
> ++ }
> ++ }
> ++ return STATUS_OK;
> ++}
> ++
> ++static int
> ++notice_abort(HostTbl * host_ptr,ReplicateHeader * header)
> ++{
> ++ char * func = "PGR_Notice_Abort()";
> ++ 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_NOTICE_ABORT_FUNC_NO);
> ++#ifdef PRINT_DEBUG
> ++ show_debug("%s:sync_command(%s)",func,sync_command);
> ++#endif
> ++ return ( send_func(host_ptr, header, sync_command, result) );
> ++}
> ++
> ++static int
> ++send_p_parse (PGconn * conn, StringInfo input_message)
> ++{
> ++ const char *stmt_name;
> ++ const char *query_string;
> ++ int numParams;
> ++ Oid paramTypes;
> ++
> ++ /* get name,query */
> ++ stmt_name = pq_getmsgstring(input_message);
> ++ query_string = pq_getmsgstring(input_message);
> ++ /* send name,query */
> ++ if (pqPutMsgStart('P', false, conn) < 0 ||
> ++ pqPuts(stmt_name, conn) < 0 ||
> ++ pqPuts(query_string, conn) < 0)
> ++ {
> ++ return STATUS_ERROR;
> ++ }
> ++ /* get number of parameter */
> ++ numParams = pq_getmsgint(input_message, 2);
> ++ /* send number of parameter */
> ++ if (pqPutInt(numParams, 2, conn) < 0)
> ++ {
> ++ return STATUS_ERROR;
> ++ }
> ++ if (numParams > 0)
> ++ {
> ++ int i;
> ++ for (i = 0; i < numParams; i++)
> ++ {
> ++ paramTypes = pq_getmsgint(input_message, 4);
> ++ if (pqPutInt(paramTypes, 4, conn) < 0)
> ++ {
> ++ return STATUS_ERROR;
> ++ }
> ++ }
> ++ }
> ++ if (pqPutMsgEnd(conn) < 0)
> ++ {
> ++ return STATUS_ERROR;
> ++ }
> ++ return STATUS_OK;
> ++}
> ++
> ++static int
> ++send_p_bind (PGconn * conn, StringInfo input_message)
> ++{
> ++ const char *portal_name;
> ++ const char *stmt_name;
> ++ int numPFormats;
> ++ int16 pformats;
> ++ int numParams;
> ++ int numRFormats;
> ++ int16 rformats;
> ++ int i;
> ++
> ++ /* Get&Send the fixed part of the message */
> ++ portal_name = pq_getmsgstring(input_message);
> ++ stmt_name = pq_getmsgstring(input_message);
> ++ if (pqPutMsgStart('B', false, conn) < 0 ||
> ++ pqPuts(portal_name, conn) < 0 ||
> ++ pqPuts(stmt_name, conn) < 0)
> ++ {
> ++ return STATUS_ERROR;
> ++ }
> ++
> ++ /* Get&Send the parameter format codes */
> ++ numPFormats = pq_getmsgint(input_message, 2);
> ++ if (pqPutInt(numPFormats, 2, conn) < 0)
> ++ {
> ++ return STATUS_ERROR;
> ++ }
> ++ if (numPFormats > 0)
> ++ {
> ++ for (i = 0; i < numPFormats; i++)
> ++ {
> ++ pformats = pq_getmsgint(input_message, 2);
> ++ if (pqPutInt(pformats, 2, conn) < 0)
> ++ {
> ++ return STATUS_ERROR;
> ++ }
> ++ }
> ++ }
> ++
> ++ /* Get&Send the parameter value count */
> ++ numParams = pq_getmsgint(input_message, 2);
> ++ if (pqPutInt(numParams, 2, conn) < 0)
> ++ {
> ++ return STATUS_ERROR;
> ++ }
> ++ if (numParams > 0)
> ++ {
> ++ int32 plength;
> ++ for (i = 0 ; i < numParams ; i ++)
> ++ {
> ++ plength = pq_getmsgint(input_message, 4);
> ++ if (plength != -1)
> ++ {
> ++ const char *pvalue =
> pq_getmsgbytes(input_message, plength);
> ++ if (pqPutInt(plength, 4, conn) < 0 ||
> ++ pqPutnchar(pvalue, plength, conn) < 0)
> ++ {
> ++ return STATUS_ERROR;
> ++ }
> ++ }
> ++ else
> ++ {
> ++ if (pqPutInt(plength, 4, conn) < 0)
> ++ {
> ++ return STATUS_ERROR;
> ++ }
> ++ }
> ++ }
> ++ }
> ++
> ++ /* Get&Send the result format codes */
> ++ numRFormats = pq_getmsgint(input_message, 2);
> ++ if (pqPutInt(numRFormats, 2, conn) < 0 )
> ++ {
> ++ return STATUS_ERROR;
> ++ }
> ++ if (numRFormats > 0)
> ++ {
> ++ for (i = 0; i < numRFormats; i++)
> ++ {
> ++ rformats = pq_getmsgint(input_message, 2);
> ++ if (pqPutInt(rformats, 2, conn) < 0)
> ++ {
> ++ return STATUS_ERROR;
> ++ }
> ++ }
> ++ }
> ++ if (pqPutMsgEnd(conn) < 0)
> ++ {
> ++ return STATUS_ERROR;
> ++ }
> ++ return STATUS_OK;
> ++}
> ++
> ++static int
> ++send_p_describe (PGconn * conn, StringInfo input_message)
> ++{
> ++
> ++ int describe_type;
> ++ const char *describe_target;
> ++
> ++ describe_type = pq_getmsgbyte(input_message);
> ++ describe_target = pq_getmsgstring(input_message);
> ++
> ++ /* construct the Describe Portal message */
> ++ if (pqPutMsgStart('D', false, conn) < 0 ||
> ++ pqPutc(describe_type, conn) < 0 ||
> ++ pqPuts(describe_target, conn) < 0 ||
> ++ pqPutMsgEnd(conn) < 0)
> ++ {
> ++ return STATUS_ERROR;
> ++ }
> ++ return STATUS_OK;
> ++}
> ++
> ++static int
> ++send_p_execute (PGconn * conn, StringInfo input_message)
> ++{
> ++ const char *portal_name;
> ++ int max_rows;
> ++
> ++ portal_name = pq_getmsgstring(input_message);
> ++ max_rows = pq_getmsgint(input_message, 4);
> ++ /* construct the Execute message */
> ++ if (pqPutMsgStart('E', false, conn) < 0 ||
> ++ pqPuts(portal_name, conn) < 0 ||
> ++ pqPutInt(max_rows, 4, conn) < 0 ||
> ++ pqPutMsgEnd(conn) < 0)
> ++ {
> ++ return STATUS_ERROR;
> ++ }
> ++ return STATUS_OK;
> ++}
> ++
> ++static int
> ++send_p_sync (PGconn * conn, StringInfo input_message)
> ++{
> ++ PGresult *result;
> ++ PGresult *lastResult;
> ++
> ++ /* construct the Sync message */
> ++ if (pqPutMsgStart('S', false, conn) < 0 ||
> ++ pqPutMsgEnd(conn) < 0)
> ++ {
> ++ return STATUS_ERROR;
> ++ }
> ++ /* remember we are using extended query protocol */
> ++ conn->queryclass = PGQUERY_EXTENDED;
> ++
> ++ /*
> ++ * Give the data a push. In nonblock mode, don't complain if we're
> unable
> ++ * to send it all; PQgetResult() will do any additional flushing
> needed.
> ++ */
> ++ if (pqFlush(conn) < 0)
> ++ {
> ++ return STATUS_ERROR;
> ++ }
> ++
> ++ /* OK, it's launched! */
> ++ conn->asyncStatus = PGASYNC_BUSY;
> ++
> ++ lastResult = NULL;
> ++ while ((result = PQgetResult(conn)) != NULL)
> ++ {
> ++ if (lastResult)
> ++ {
> ++ if (lastResult->resultStatus == PGRES_FATAL_ERROR &&
> ++ result->resultStatus == PGRES_FATAL_ERROR)
> ++ {
> ++ PQclear(result);
> ++ result = lastResult;
> ++ }
> ++ else
> ++ PQclear(lastResult);
> ++ }
> ++ lastResult = result;
> ++ if (result->resultStatus == PGRES_COPY_IN ||
> ++ result->resultStatus == PGRES_COPY_OUT ||
> ++ conn->status == CONNECTION_BAD)
> ++ break;
> ++ }
> ++ if (lastResult != NULL)
> ++ {
> ++ PQclear(lastResult);
> ++ }
> ++ return STATUS_OK;
> ++}
> ++
> ++static int
> ++send_p_close (PGconn * conn, StringInfo input_message)
> ++{
> ++
> ++ int close_type;
> ++ const char *close_target;
> ++
> ++ close_type = pq_getmsgbyte(input_message);
> ++ close_target = pq_getmsgstring(input_message);
> ++ if (pqPutMsgStart('C', false, conn) < 0 ||
> ++ pqPutc(close_type, conn) < 0 ||
> ++ pqPuts(close_target, conn) < 0 ||
> ++ pqPutMsgEnd(conn) < 0)
> ++ {
> ++ return STATUS_ERROR;
> ++ }
> ++ return STATUS_OK;
> ++}
> ++static void
> ++set_string_info(StringInfo input_message, ReplicateHeader * header, char
> * query)
> ++{
> ++ int len;
> ++ len = ntohl(header->query_size);
> ++ input_message->data = query;
> ++ input_message->maxlen = len;
> ++ input_message->len = len -1;
> ++ input_message->cursor = 0;
> ++}
> +diff -aruN postgresql-8.1.2/src/pgcluster/pgrp/rlog.c
> pgcluster-1.5.0rc7/src/pgcluster/pgrp/rlog.c
> +--- postgresql-8.1.2/src/pgcluster/pgrp/rlog.c 1970-01-01
> 01:00:00.000000000 +0100
> ++++ pgcluster-1.5.0rc7/src/pgcluster/pgrp/rlog.c 2006-01-31
> 23:47:23.000000000 +0100
> +@@ -0,0 +1,1288 @@
> ++/*--------------------------------------------------------------------
> ++ * 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) 2003-2006, 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);
> ++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;
> ++ default:
> ++ show_error("%s:unknown status %c",func,header->cmdSts);
> ++ 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;
> ++#ifdef PRINT_DEBUG
> ++ show_debug("get_query_log_by_header:header is %d,%d,%d,%s",
> ++ header->request_id,
> ++ header->pid,
> ++ header->port,
> ++ header->from_host);
> ++#endif
> ++
> ++ while(query_log != (QueryLogType *)NULL)
> ++ {
> ++#ifdef PRINT_DEBUG
> ++ show_debug("get_query_log_by_header:comparing to %d,%d,%d,%s",
> ++ query_log->header->request_id,
> ++ query_log->header->pid,
> ++ query_log->header->port,
> ++ query_log->header->from_host);
> ++#endif
> ++ 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)
> ++ {
> ++#ifdef PRINT_DEBUG
> ++ show_debug("get_qurey_log: comparing in log is %d,header is
> %d",query_log->header->replicate_id,header->replicate_id);
> ++#endif
> ++ 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 != DB_TBL_END )
> ++ {
> ++ if (commit_log->inf.useFlag != DB_TBL_USE)
> ++ {
> ++ commit_log->inf.useFlag = DB_TBL_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 != DB_TBL_END )
> ++ {
> ++ if (commit_log->inf.useFlag == DB_TBL_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 = DB_TBL_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();
> ++ if (Replicateion_Log->r_log_sock == -1)
> ++ return;
> ++
> ++ header->query_size = 0;
> ++ PGRsend_rlog_packet(Replicateion_Log->r_log_sock,header,"");
> ++ 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_Result,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 == DB_TBL_USE)
> ++ {
> ++ /* save log data in remote server */
> ++#ifdef PRINT_DEBUG
> ++ show_debug("%s:set rlog %s",func,query);
> ++#endif
> ++ status =
> PGRsend_lower_cascade(PGR_Log_Header, query);
> ++ if (status == STATUS_OK) {
> ++
> status=PGRwait_notice_rlog_done();
> ++ }
> ++ 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 == DB_TBL_USE)
> ++ {
> ++ /* save log data in remote server */
> ++#ifdef PRINT_DEBUG
> ++ show_debug("unset rlog %s",query);
> ++#endif
> ++
> ++ status = PGRsend_lower_cascade(PGR_Log_Header, query);
> ++ if (status == STATUS_OK)
> ++ {
> ++ status=PGRwait_notice_rlog_done();
> ++ }
> ++ if (status != STATUS_OK)
> ++ {
> ++#ifdef PRINT_DEBUG
> ++ show_debug("PGRsend_lower_cascade recv failed");
> ++#endif
> ++ 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)
> ++{
> ++ char *func="PGRresend_rlog_to_db";
> ++ QueryLogType * query_log = NULL;
> ++ QueryLogType * next = NULL;
> ++ int status = STATUS_OK;
> ++ int dest = 0;
> ++
> ++#ifdef PRINT_DEBUG
> ++ show_debug("%s:enter.",func);
> ++#endif
> ++
> ++ query_log = Query_Log_Top;
> ++
> ++ while (query_log != NULL)
> ++ {
> ++
> ++
> ++#ifdef PRINT_DEBUG
> ++ show_debug("%s:processing qlog,query=%s",func,query_log->query);
> ++#endif
> ++ if (query_log->header->rlog != FROM_R_LOG_TYPE )
> ++ {
> ++ query_log = (QueryLogType *)query_log->next;
> ++ continue;
> ++ }
> ++ status =
> replicate_packet_send_internal(query_log->header,query_log->query,
> dest,RECOVERY_INIT,false);
> ++#ifdef PRINT_DEBUG
> ++ show_debug("%s:status=%d",func,status);
> ++#endif
> ++ if (status == STATUS_SKIP_REPLICATE )
> ++ {
> ++ Query_Log_Top = query_log;
> ++ query_log = (QueryLogType *)query_log->next;
> ++ }
> ++ else
> ++ {
> ++ 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;
> ++ }
> ++ }
> ++
> ++#ifdef PRINT_DEBUG
> ++ show_debug("%s:exit.",func);
> ++#endif
> ++
> ++ 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;
> ++
> ++ extern int fork_wait_time;
> ++
> ++ 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);
> ++
> ++ if (PGRinit_transaction_table() != STATUS_OK)
> ++ {
> ++ show_error("RLog process transaction table memory allocate
> failed");
> ++ return -1;
> ++ }
> ++
> ++ setpgid(0,pgid);
> ++ RLog_Recv_Sock = create_recv_rlog_socket();
> ++ if(RLog_Recv_Sock == -1)
> ++ {
> ++ show_error("rlog socket creation failure.quit all process.");
> ++ kill(pgreplicate_pid, SIGINT);
> ++ exit_rlog(0);
> ++ }
> ++
> ++ if (fork_wait_time > 0) {
> ++#ifdef PRINT_DEBUG
> ++ show_debug("rlog process: wait fork(): pid = %d", getpid());
> ++#endif
> ++ sleep(fork_wait_time);
> ++ }
> ++
> ++ 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, 1000000);
> ++ 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);
> ++#ifdef PRINT_DEBUG
> ++ show_debug("%s:got result:cmdSys='%c'",func,header.cmdSys);
> ++#endif
> ++ 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();
> ++ }
> ++#ifdef PRINT_DEBUG
> ++ show_debug("%s: SYS_CALL process done",func);
> ++#endif
> ++ send_message(fd,(char *)&status,sizeof(status));
> ++ break;
> ++ }
> ++#ifdef PRINT_DEBUG
> ++ show_debug("%s:process result done:cmdSys='%c'",func,header.cmdSys);
> ++#endif
> ++ 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();
> ++ if (Replicateion_Log->r_log_sock == -1)
> ++ return STATUS_ERROR;
> ++
> ++ 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)
> ++ {
> ++ close(Replicateion_Log->r_log_sock );
> ++ Replicateion_Log->r_log_sock = -1;
> ++ 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();
> ++ if (Replicateion_Log->r_log_sock == -1)
> ++ return STATUS_ERROR;
> ++
> ++ 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)
> ++{
> ++ char *func = "PGRrecv_rlog_result";
> ++ fd_set rmask;
> ++ struct timeval timeout;
> ++ int rtn;
> ++
> ++ if ((result == (void *)NULL) || (size <= 0))
> ++ {
> ++ return -1;
> ++ }
> ++
> ++ /*
> ++ * Wait for something to happen.
> ++ */
> ++ rtn = 1;
> ++ for (;;)
> ++ {
> ++ timeout.tv_sec = PGR_RECV_TIMEOUT;
> ++ timeout.tv_usec = 0;
> ++
> ++ FD_ZERO(&rmask);
> ++ FD_SET(sock,&rmask);
> ++ rtn = select(sock+1, &rmask, (fd_set *)NULL, (fd_set *)NULL,
> &timeout);
> ++ if (rtn < 0)
> ++ {
> ++ if (errno != EINTR || errno != EAGAIN)
> ++ {
> ++ show_error("%s: select() failed
> (%s)",func,strerror(errno));
> ++ return -1;
> ++ }
> ++ }
> ++ else if (rtn && FD_ISSET(sock, &rmask))
> ++ {
> ++ return (recv_message(sock, (char*)result, size));
> ++ }
> ++ }
> ++ return -1;
> ++}
> ++
> ++
> ++static int
> ++recv_message(int sock,char * buf, int len)
> ++{
> ++ char *func = "recv_message";
> ++ 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 || errno == EAGAIN)
> ++ continue;
> ++ else
> ++ {
> ++ show_error("%s:recv failed: %d(%s)",func,
> errno, strerror(errno));
> ++ return -1;
> ++ }
> ++ }
> ++ else if (r > 0)
> ++ {
> ++ read_size += r;
> ++ if (read_size == len)
> ++ return read_size;
> ++ }
> ++ else /* r == 0 */
> ++ {
> ++ show_error("%s:unexpected EOF", func);
> ++ return -1;
> ++ }
> ++ }
> ++ 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();
> ++ if (Replicateion_Log->r_log_sock == -1)
> ++ return STATUS_ERROR;
> ++
> ++#ifdef PRINT_DEBUG
> ++ show_debug("send_to_local %s",query);
> ++#endif
> ++ status =
> PGRsend_rlog_packet(Replicateion_Log->r_log_sock,header,query);
> ++#ifdef PRINT_DEBUG
> ++ show_debug("send_to_local result is %d,errno=%d(%s)",status,errno
> ,strerror(errno));
> ++#endif
> ++
> ++ 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();
> ++ if (Replicateion_Log->r_log_sock == -1)
> ++ return STATUS_ERROR;
> ++
> ++ 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,"");
> ++ 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 flag = 0;
> ++
> ++ if ((msg == NULL) || (len <= 0) || (sock <= 0))
> ++ {
> ++ return STATUS_ERROR;
> ++ }
> ++ send_ptr = msg;
> ++ buf_size = len;
> ++
> ++ /*
> ++ * Wait for something to happen.
> ++ */
> ++#ifdef MSG_DONTWAIT
> ++ flag |= MSG_DONTWAIT;
> ++#endif
> ++#ifdef MSG_NOSIGNAL
> ++ flag |= MSG_NOSIGNAL;
> ++#endif
> ++
> ++ for (;;)
> ++ {
> ++ timeout.tv_sec = PGR_SEND_TIMEOUT;
> ++ timeout.tv_usec = 0;
> ++
> ++ FD_ZERO(&wmask);
> ++ FD_SET(sock,&wmask);
> ++ rtn = select(sock+1, (fd_set *)NULL, &wmask, (fd_set *)NULL,
> &timeout);
> ++
> ++ if (rtn < 0 )
> ++ {
> ++ if (errno == EAGAIN || errno == EINTR)
> ++ continue;
> ++
> ++ show_error("%s:send-select error:
> %d(%s)",func,errno,strerror(errno));
> ++ return STATUS_ERROR;
> ++ }
> ++ else if (rtn & FD_ISSET(sock, &wmask))
> ++ {
> ++ s = send(sock,send_ptr + send_size,buf_size -
> send_size ,flag);
> ++ if (s < 0)
> ++ {
> ++ if (errno == EINTR || errno == EAGAIN)
> ++ continue;
> ++ else
> ++ {
> ++ show_error("%s:send error:
> %d(%s)",func,errno,strerror(errno));
> ++ memset(send_ptr, 0, len);
> ++ return STATUS_ERROR;
> ++ }
> ++ }
> ++ else if (s == 0)
> ++ {
> ++ show_error("%s:unexpected EOF");
> ++ memset(send_ptr, 0, len);
> ++ return STATUS_ERROR;
> ++ }
> ++ else /* s > 0 */
> ++ {
> ++ send_size += s;
> ++ if (send_size == buf_size)
> ++ {
> ++ return STATUS_OK;
> ++ }
> ++ }
> ++ }
> ++ }
> ++ show_error("%s:send-select unknown error: %d(%s)",
> ++ func,errno,strerror(errno));
> ++ return STATUS_ERROR;
> ++}
> ++
> ++static void
> ++exit_rlog(int sig)
> ++{
> ++ sigset_t mask;
> ++
> ++ Exit_Request = true;
> ++ if (sig == SIGTERM)
> ++ {
> ++ if (Idle_Flag == BUSY_MODE)
> ++ {
> ++ return;
> ++ }
> ++ }
> ++
> ++ sigemptyset(&mask);
> ++ sigaddset(&mask, SIGINT);
> ++ sigaddset(&mask, SIGTERM);
> ++ sigaddset(&mask, SIGQUIT);
> ++ sigprocmask(SIG_BLOCK, &mask, NULL);
> ++
> ++ 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 -aruN postgresql-8.1.2/src/pgcluster/tool/Makefile
> pgcluster-1.5.0rc7/src/pgcluster/tool/Makefile
> +--- postgresql-8.1.2/src/pgcluster/tool/Makefile 1970-01-01
> 01:00:00.000000000 +0100
> ++++ pgcluster-1.5.0rc7/src/pgcluster/tool/Makefile 2006-01-10
> 17:39:44.000000000 +0100
> +@@ -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 -aruN postgresql-8.1.2/src/pgcluster/tool/README
> pgcluster-1.5.0rc7/src/pgcluster/tool/README
> +--- postgresql-8.1.2/src/pgcluster/tool/README 1970-01-01
> 01:00:00.000000000 +0100
> ++++ pgcluster-1.5.0rc7/src/pgcluster/tool/README 2006-01-10
> 17:39:44.000000000 +0100
> +@@ -0,0 +1,127 @@
> ++-----------------------------------------------------
> ++About pgcbench
> ++-----------------------------------------------------
> ++
> ++The pgcbench is the program which performs the benchmark test of
> PGCluster.
> ++Of course, it can use for benchmark not only PGCluster but PostgreSQL.
> ++
> ++The pgcbench displays the number of executed transaction per second (tps)
> which performed transaction containing SELECT, UPDATE, and INSERT.
> ++The table set as the object of transaction contains data of 100,000 lines
> by a default.
> ++
> ++A display is actually as follows.
> ++ number of clients: 4
> ++ number of transactions actually processed: 100
> ++ run time (sec) = 4.416423
> ++ tps = 22.642759 (including connections establishing)
> ++
> ++
> ++The pgcbench is calculating tps not based on the actually completed
> number of transactions but based on the number that is specified at
> beginning.
> ++So, the tps displayed may not be right when the benchmark has been
> suspended.
> ++
> ++The pgcbench was created based on pgbench which is the benchmark program
> for PostgreSQL written by Tatsuo Ishii.
> ++
> ++
> ++-----------------------------------------------------
> ++Feature of pgcbench
> ++-----------------------------------------------------
> ++- Although the pgbench is simulating multi-user connections in the single
> process, pgcbench has made multi-user connections in the multi-process by
> fork.
> ++- There are some options which specifies the contents of transaction in
> pgcbench.
> ++
> ++
> ++-----------------------------------------------------
> ++Installation of pgcbench
> ++-----------------------------------------------------
> ++1. Install with the PGCluster
> ++Your installation of PGCluster also installs pgcbench automatically.
> ++
> ++2. Install only pgcbench
> ++If you want install only pgcbench, you do not need to compile all of the
> PGCluster.
> ++pgcbench is compiled as follow.
> ++
> ++ $ cd $TOP_PGCusters_Source
> ++ $ ./configure
> ++ $ cd src/interface/libpq
> ++ $ make all
> ++ $ cd $TOP_PGCusters_Source/src/pgcluster/tool
> ++ $ make
> ++
> ++-----------------------------------------------------
> ++Usage of pgcbench
> ++-----------------------------------------------------
> ++pgcbench [options] [DB name]
> ++pgcbench -i [options] [DB name] (for initialization of DB)
> ++
> ++[options]
> ++-h: host name
> ++-p: port number
> ++-c: number of clients connected simultaneously (default is 1)
> ++-t: number of transaction which each client executed
> ++-s: scaling factor of table size. 1 means 100,000 records. ( use with
> '-i' )
> ++-u: user name
> ++-P: password
> ++-n: it does not execute VACUUM and is not cleared history table.
> ++-v: execute VACUUM and clear history table
> ++-I: execute INSERT query only
> ++-U: execute UPDATE query only
> ++-S: execute SELECT query only
> ++-f: command script file name
> ++-T: transaction is performed in the transaction bloc surrounded by BEGIN
> and END.
> ++-C: each session is reconnected for every transaction
> ++-l: The execution time of each transaction is recorded. That log file is
> created under current directory as "pgcbench_log.xxx".
> ++-d: debug option
> ++
> ++-----------------------------------------------------
> ++Initialization of the database
> ++-----------------------------------------------------
> ++In order to execute a default benchmark test by pgcbench, the data base
> should be initialized and made test data.
> ++You can execute the following commands for initialization of the data
> base.
> ++
> ++ $ pgcbench -i [DB name ]
> ++
> ++Thereby, the following tables are created (when a scaling factor is 1) .
> ++
> ++ table name | row num
> ++ -----------+--------
> ++ branches | 1
> ++ tellers | 10
> ++ accounts | 100000
> ++ history | 0
> ++
> ++When a scaling factor is changed into 10, 100, 1000, etc., according to
> it, the number of table rows will increase 10 times, 100 times, and 1000
> times.
> ++For example, when the scaling factor is set to 100, the number of table
> rows is as follows.
> ++
> ++ table name | row num
> ++ -----------+----------
> ++ branches | 100
> ++ tellers | 1000
> ++ accounts | 10000000
> ++ history | 0
> ++
> ++
> ++-----------------------------------------------------
> ++Format of the command script file
> ++-----------------------------------------------------
> ++The pgcbench read the command script file that is specified with '-f'
> option, and executes the specified transaction.
> ++The specified command can be described one per one line.
> ++The null line is disregarded and the row which starts with double hyphen
> means a comment line.
> ++In addition to the SQL command, the meta-command which starts with a
> backslash can be described in this file.
> ++
> ++The following meta-commands can be used.
> ++
> ++\setrandom name min max
> ++ Random digits are set into variable 'name'.
> ++ The sphere of random digits is between 'min' and 'max'.
> ++ For example, when you want to execute the benchmark like TPC-B, you
> can describes as follows.
> ++
> ++
> ++ \setrandom aid 1 100000
> ++ \setrandom bid 1 1
> ++ \setrandom tid 1 10
> ++ \setrandom delta 1 1000
> ++ BEGIN
> ++ UPDATE accounts SET abalance = abalance + :delta WHERE aid = :aid
> ++ SELECT abalance FROM accounts WHERE aid = :aid
> ++ UPDATE tellers SET tbalance = tbalance + :delta WHERE tid = :tid
> ++ UPDATE branches SET bbalance = bbalance + :delta WHERE bid = :bid
> ++ INSERT INTO history (tid, bid, aid, delta, mtime) VALUES (:tid, :bid,
> :aid, :delta, 'now')
> ++ END
> +diff -aruN postgresql-8.1.2/src/pgcluster/tool/README.jp
> pgcluster-1.5.0rc7/src/pgcluster/tool/README.jp
> +--- postgresql-8.1.2/src/pgcluster/tool/README.jp 1970-01-01
> 01:00:00.000000000 +0100
> ++++ pgcluster-1.5.0rc7/src/pgcluster/tool/README.jp 2006-01-10
> 17:39:44.000000000 +0100
> +@@ -0,0 +1,296 @@
> ++$Id: README,v 1.2 2005/08/02 01:24:53 tom-sato Exp $
> ++
> ++$B"#(B pgcbench $B$H$O(B
> ++
> ++pgcbench $B$O(B PGCluster
> $B$N%Y%s%A%^!<%/%F%9%H$r9T$&%W%m%0%i%`$G$9!#$b$A$m(B
> ++$B$s!"(BPGCluster $B$@$1$G$O$J$/(B PostgreSQL
> $B$N%Y%s%A%^!<%/$r<B;\$9$k$3$H$b$G(B
> ++$B$-$^$9!#(B
> ++
> ++pgcbench $B$O(B SELECT$B!"(BUPDATE$B!"(BINSERT
> $B$r4^$`%H%i%s%6%/%7%g%s$r<B9T$7!"A4(B
> ++$BBN$N<B9T;~4V$H<B:]$K40N;$7$?$G$"$m$&%H%i%s%6%/%7%g%s$N?t$+$i(B 1
> $BIC4V$K(B
> ++$B<B9T$G$-$?%H%i%s%6%/%7%g%s?t(B (tps)
> $B$rI=<($7$^$9!#=hM}$NBP>]$H$J$k%F!<(B
> ++$B%V%k$O%G%U%)%k%H$G$O(B 10 $BK|9T$N%G!<%?$r4^$_$^$9!#(B
> ++
> ++$B<B:]$KI=<($O0J2<$N$h$&$K$J$j$^$9!#(B
> ++
> ++ number of clients: 4
> ++ number of transactions actually processed: 100
> ++ run time (sec) = 4.416423
> ++ tps = 22.642759 (including connections establishing)
> ++
> ++$B"((B $BCm0U(B
> ++
> ++ pgcbench
> $B$G$O!"%H%i%s%6%/%7%g%s$,<B:]$K40N;$7$?$+$I$&$+$K4X78$J$/!"(B
> ++ $B:G=i$K;XDj$5$l$?%H%i%s%6%/%7%g%s$N?t$r$b$H$K(B tps
> $B$r5a$a$F$$$k$?$a!"(B
> ++ $B%Y%s%A%^!<%/$,ESCf$G=*N;$7$F$7$^$C$?>l9g!"I=<($5$l$k(B tps
> $B$,?.MQ$G$-(B
> ++ $B$J$$2DG=@-$,$"$k$3$H$KCm0U$7$F$/$@$5$$!#(B
> ++
> ++$B$J$*!"(Bpgcbench $B$O(B pgbench $B$H$$$&(B PostgreSQL
> $BMQ$K=q$+$l$?%Y%s%A%^!<%/%F(B
> ++$B%9%H$r9T$J$&%W%m%0%i%`$r$b$H$K:n@.$5$l$^$7$?!#(B
> ++
> ++
> ++$B"#(B pgbench $B$H$N0c$$(B
> ++
> ++$B!&(B $B%^%k%A%f!<%64D6-$N<B8=J}K!(B
> ++
> ++ pgbench $B$,(B libpq
> $B$NHsF14|=hM}5!G=$r;H$C$?%7%s%0%k%W%m%;%9$K$h$C$F%7(B
> ++ $B%_%e%l!<%H$7$F$$$k$N$KBP$7$F!"(Bpgcbench $B$G$O(B fork
> $B$r;H$C$?%^%k%A%W%m(B
> ++
> $B%;%9$K$h$C$F<B8=$7$F$$$^$9!#$3$l$O!"%7%s%0%k%W%m%;%9$G$O%m%C%/$,H/(B
> ++ $B@8$9$k$H!"(BPGCluster $B$,;_$^$C$F$7$^$&$3$H$rHr$1$k$?$a$G$9!#(B
> ++
> ++$B!&(B $B%*%W%7%g%s$NJQ99(B
> ++
> ++ pgcbench $B$K$O!"(BPGCluster
> $B$N%Y%s%A%^!<%/%F%9%H$r9T$J$&$N$KJXMx$J!"%H(B
> ++
> $B%i%s%6%/%7%g%s$NFbMF$r;XDj$9$k%*%W%7%g%s$,!"$$$/$D$+DI2C$5$l$F$$$^(B
> ++ $B$9!%(B
> ++
> ++
> ++$B"#(B pgcbench $B$N%$%s%9%H!<%k(B
> ++
> ++1. PGCluster $B$r(B configure$B!"(Bmake $B$7$^$9!#(B
> ++
> ++ pgcbench $B$N%$%s%9%H!<%k$@$1$,L\E*$G$"$l$P!"(BPGCluster
> $B$N$9$Y$F$r%3%s(B
> ++ $B%Q%$%k$9$kI,MW$O$"$j$^$;$s!#(BPGCluster
> $B%=!<%9$N%H%C%W%G%#%l%/%H%j$G(B
> ++ configure $B$r$7$?8e!"(Bsrc/interface/libpq $B$G(B make all
> $B$r<B9T$9$l$P=`(B
> ++ $BHw40N;$G$9!#(B
> ++
> ++2. $B$3$N%G%#%l%/%H%j(B (src/pgcluster/tool) $B$G(B make
> $B$r<B9T$7$^$9!#(B
> ++
> ++ $B$=$&$9$k$H!"(Bpgcbench
> $B$H$$$&<B9T%W%m%0%i%`$,$G$-$^$9!#$=$N$^$^<B9T$7(B
> ++ $B$F$b9=$$$^$;$s$7!"(Bmake install $B$r<B9T$7$F(B PGCluster
> $B$NI8=`<B9T%W%m(B
> ++ $B%0%i%`%G%#%l%/%H%j(B ($B%G%U%)%k%H$G$O(B /usr/local/pgsql/bin)
> $B$K%$%s%9%H!<(B
> ++ $B%k$9$k$3$H$b$G$-$^$9!#(B
> ++
> ++
> ++$B"#(B pgcbench $B$N;H$$J}(B
> ++
> ++ pgcbench [$B%*%W%7%g%s(B] [$B%G!<%?%Y!<%9L>(B]
> ++
> ++$B%G!<%?%Y!<%9L>$r>JN,$9$k$H!"%m%0%$%sL>$HF1$8%G!<%?%Y!<%9L>$r;XDj$7$?$b(B
> ++$B$N$H8+$J$7$^$9!#$J$*!"(Bpgcbench
> $B$G%G%U%)%k%H$N%Y%s%A%^!<%/$r<B;\$9$k$?(B
> ++$B$a$K$O!"8e=R$N(B -i
> $B%*%W%7%g%s$r;HMQ$7$F%G!<%?%Y!<%9$r$"$i$+$8$a=i4|2=$7(B
> ++$B$F$*$/I,MW$,$"$j$^$9!#(B
> ++
> ++pgcbench $B$K$O$$$m$$$m$J%*%W%7%g%s$,$"$j$^$9!#(B
> ++
> ++-h $B%[%9%HL>(B
> ++
> ++ PostgreSQL$B$N(B $B%G!<%?%Y!<%9%G!<%b%s(B postmaster
> $B$NF0:n$7$F$$$k%[%9%HL>(B
> ++ $B$r;XDj$7$^$9!#>JN,$9$k$H4D6-JQ?t(B PGHOST
> $B$K@_Dj$7$?%[%9%HL>$,;XDj$5(B
> ++ $B$l$^$9!#(BPGHOST $B$b;XDj$5$l$F$$$J$$$H<+%[%9%H$K(B Unix
> $B%I%a%$%s%=%1%C%H(B
> ++ $B$G@\B3$7$^$9!#(B
> ++
> ++-p $B%]!<%HHV9f(B
> ++
> ++ postmaster $B$N;HMQ$9$k%]!<%HHV9f$r;XDj$7$^$9!#>JN,$9$k$H4D6-JQ?t(B
> ++ PGPORT $B$K@_Dj$7$?%]!<%HHV9f$,;XDj$5$l$^$9!#(BPGPORT
> $B$b;XDj$5$l$F$$$J(B
> ++ $B$$$H(B 5432 $B$,;XDj$5$l$?$b$N$H8+$J$7$^$9!#(B
> ++
> ++-c $B%/%i%$%"%s%H?t(B
> ++
> ++ $BF1;~<B9T%/%i%$%"%s%H?t$r;XDj$7$^$9!#>JN,;~$O(B 1
> $B$H$J$j$^$9!#(Bpgcbench
> ++
> $B$OF1;~<B9T%/%i%$%"%s%H$4$H$K%U%!%$%k%G%#%9%/%j%W%?$r;HMQ$9$k$N$G!"(B
> ++
> $B;HMQ2DG=%U%!%$%k%G%#%9%/%j%W%??t$r1[$($k%/%i%$%"%s%H?t$O;XDj$G$-$^(B
> ++ $B$;$s!#;HMQ2DG=%U%!%$%k%G%#%9%/%j%W%??t$O(B limit $B$d(B ulimit
> $B%3%^%s%I$G(B
> ++ $B3NG'$9$k$3$H$,$G$-$^$9!#(B
> ++
> ++-t $B%H%i%s%6%/%7%g%s?t(B
> ++
> ++
> $B%H%i%s%6%/%7%g%s?t$r;XDj$7$^$9!#3F%/%i%$%"%s%H$,<B9T$9$k%H%i%s%6%/(B
> ++ $B%7%g%s?t$O$3$l$r%/%i%$%"%s%H?t$G3d$C$??t$H$J$j$^$9!#>JN,;~$O(B 10
> $B$H(B
> ++ $B$J$j$^$9!#(B
> ++
> ++-s $B%9%1!<%j%s%0%U%!%/%?!<(B
> ++
> ++ -i $B%*%W%7%g%s$H$H$b$K;HMQ$7$^$9!#%9%1!<%j%s%0%U%!%/%?!<$O(B 1
> $B0J>e$N(B
> ++
> $B@0?t$G$9!#%9%1!<%j%s%0%U%!%/%?!<$rJQ$($k$3$H$K$h$j!"%F%9%H$NBP>]$H(B
> ++ $B$J$k%F!<%V%k$NBg$-$5$,(B 10 $BK|(B $B!_(B
> $B%9%1!<%j%s%0%U%!%/%?!<$K$J$j$^$9!#(B
> ++ $B%G%U%)%k%H$N%9%1!<%j%s%0%U%!%/%?!<$O(B 1 $B$G$9!#(B
> ++
> ++-u $B%m%0%$%sL>(B
> ++
> ++ DB $B%f!<%6$N%m%0%$%sL>$r;XDj$7$^$9!#>JN,$9$k$H4D6-JQ?t(B PGUSER
> $B$K@_Dj(B
> ++ $B$7$?%m%0%$%sL>$,;XDj$5$l$^$9!#(B
> ++
> ++-P $B%Q%9%o!<%I(B
> ++
> ++
> $B%Q%9%o!<%I$r;XDj$7$^$9!#$J$*!"$3$N%*%W%7%g%s$r;H$&$H!"%Q%9%o!<%I$r(B
> ++ ps
> $B%3%^%s%I$G8+$i$l$k$J$I!"%;%-%e%j%F%#%[!<%k$K$J$k2DG=@-$,$"$k$N$G!"(B
> ++ $B%F%9%HMQ$K$N$_$*;H$$2<$5$$!#(B
> ++
> ++-n
> ++
> ++ $B$3$N%*%W%7%g%s$r;XDj$9$k$H!"%Y%s%A%^!<%/3+;OA0$K(B VACUUM $B$H(B
> history
> ++ $B%F!<%V%k$N%/%j%"$r<B9T$7$^$;$s!#(B
> ++
> ++-v
> ++
> ++ $B$3$N%*%W%7%g%s$r;XDj$9$k$H!"%Y%s%A%^!<%/3+;OA0$K(B VACUUM $B$H(B
> history
> ++ $B%F!<%V%k$N%/%j%"$r<B9T$7$^$9!#(B-v $B$H(B -n
> $B$r>JN,$9$k$H!":G>.8B$N(B
> ++ VACUUM $B$J$I$r<B9T$7$^$9!#$9$J$o$A!"(Bhistory
> $B%F!<%V%k$N%/%j%"$H!"(B
> ++ branches$B!"(Btellers$B!"(Bhistory $B%F!<%V%k$N(B VACUUM
> $B$r<B9T$7$^$9!#$3$l$O!"(B
> ++ VACUUM
> $B$N;~4V$r:G>.8B$K$7$J$,$i!"%Q%U%)!<%^%s%9$K1F6A$9$k%4%_A]=|$r(B
> ++ $B8z2LE*$K<B9T$7$^$9!#DL>o$O(B -v $B$H(B -n
> $B$r>JN,$9$k$3$H$r?d>)$7$^$9!#(B
> ++
> ++-I
> ++
> ++
> $BA^F~$N$_$N%H%i%s%6%/%7%g%s$r<B9T$7$^$9!#A^F~%9%T!<%I$rB,Dj$7$?$$$H(B
> ++ $B$-$K;H$$$^$9!#(B
> ++
> ++-U
> ++
> ++
> $B99?7$N$_$N%H%i%s%6%/%7%g%s$r<B9T$7$^$9!#99?7%9%T!<%I$rB,Dj$7$?$$$H(B
> ++ $B$-$K;H$$$^$9!#(B
> ++
> ++-S
> ++
> ++
> $B8!:w$N$_$N%H%i%s%6%/%7%g%s$r<B9T$7$^$9!#8!:w%9%T!<%I$rB,Dj$7$?$$$H(B
> ++ $B$-$K;H$$$^$9!#(B
> ++
> ++-f $B%U%!%$%kL>(B
> ++
> ++
> $B%H%i%s%6%/%7%g%s$NFbMF$,5-=R$5$l$?%U%!%$%kL>$r;XDj$7$^$9!#$3$N%*%W(B
> ++
> $B%7%g%s$r;XDj$9$k$H!"%U%!%$%k$K5-=R$5$l$?FbMF$N%H%i%s%6%/%7%g%s$r<B(B
> ++
> $B9T$7$^$9!#%Y%s%A%^!<%/$G;HMQ$9$k%F!<%V%k$O$"$i$+$8$a=i4|2=$7$F$*$/(B
> ++ $BI,MW$,$"$j$^$9!#F~NO%U%!%$%k$N%U%)!<%^%C%H$O8e=R$7$^$9!#(B
> ++
> ++-T
> ++
> ++ BEGIN $B$H(B END
> $B$G0O$^$l$?%H%i%s%6%/%7%g%s%V%m%C%/Fb$G%H%i%s%6%/%7%g%s(B
> ++ $B$r<B9T$7$^$9!#(B
> ++
> ++-C
> ++
> ++
> $B$3$N%*%W%7%g%s$r;XDj$9$k$H!":G=i$K3NN)$7$?%3%M%/%7%g%s$r;H$$2s$9$N(B
> ++ $B$G$O$J$/!"3F%H%i%s%6%/%7%g%s$4$H$K(B DB
> $B$X$N@\B3$r9T$$$^$9!#%3%M%/%7%g(B
> ++ $B%s$N%*!<%P!<$X%C%I$rB,Dj$9$k$N$KM-8z$G$9!#(B
> ++
> ++-l
> ++
> ++
> $B8D!9$N%H%i%s%6%/%7%g%s$N<B9T;~4V$r5-O?$7$^$9!#5-O?@h$O%+%l%s%H%G%#(B
> ++ $B%l%/%H%j0J2<$N(B pgbench_log.xxx
> $B$H$$$&%U%!%$%k$G$9!#%U%!%$%k$N%U%)!<(B
> ++ $B%^%C%H$O0J2<$N$h$&$K$J$j$^$9!#;~4V$O%^%$%/%mICC10L$G$9!#(B
> ++
> ++ <$B%/%i%$%"%s%H(B ID> <$B%H%i%s%6%/%7%g%sHV9f(B> <$B;~4V(B>
> ++
> ++-d
> ++
> ++ $B%G%P%C%0%*%W%7%g%s!#MM!9$J>pJs$,I=<($5$l$^$9!#(B
> ++
> ++
> ++$B"#(B $B%G!<%?%Y!<%9$N=i4|2=(B
> ++
> ++pgcbench
> $B$G%G%U%)%k%H$N%Y%s%A%^!<%/%F%9%H$r<B;\$9$k$?$a$K$O!"$"$i$+$8(B
> ++$B$a%G!<%?%Y!<%9$r=i4|2=$7!"%F%9%H%G!<%?$r:n$kI,MW$,$"$j$^$9!#(B
> ++
> ++ pgcbench -i [$B%G!<%?%Y!<%9L>(B]
> ++
> ++$B$3$l$K$h$j0J2<$N%F!<%V%k$,:n@.$5$l$^$9(B
> ($B%9%1!<%j%s%0%U%!%/%?!<$,(B 1 $B$N(B
> ++$B>l9g(B)$B!#(B
> ++
> ++ $B%F!<%V%kL>(B | $B9T?t(B
> ++ ------------+--------
> ++ branches | 1
> ++ tellers | 10
> ++ accounts | 100000
> ++ history | 0
> ++
> ++$B"((B $BCm0U(B
> ++
> ++ $BF1$8L>A0$N%F!<%V%k$,$"$k$H:o=|$5$l$F$7$^$&$N$G$4Cm0U2<$5$$!#(B
> ++
> ++$B%9%1!<%j%s%0%U%!%/%?!<$r(B 10$B!"(B100$B!"(B1000
> $B$J$I$KJQ99$9$k$H!">e5-9T?t$O$=(B
> ++$B$l$K1~$8$F(B 10 $BG\!"(B100 $BG\!"(B1000
> $BG\$K$J$j$^$9!#Nc$($P!"%9%1!<%j%s%0%U%!(B
> ++$B%/%?!<$r(B 100 $B$H$9$k$H0J2<$N$h$&$K$J$j$^$9!#(B
> ++
> ++ $B%F!<%V%kL>(B | $B9T?t(B
> ++ ------------+----------
> ++ branches | 100
> ++ tellers | 1000
> ++ accounts | 10000000
> ++ history | 0
> ++
> ++
> ++$B"#(B $BF~NO%U%!%$%k$N%U%)!<%^%C%H(B
> ++
> ++pgcbench $B$G$O!"(B-f
> $B%*%W%7%g%s$r;XDj$7$F%H%i%s%6%/%7%g%s$K4^$^$l$k(B SQL
> ++$B%3%^%s%I$NFbMF$r5-=R$7$?%U%!%$%k$rFI$_9~$`$3$H$,$G$-$^$9!#F~NO%U%!%$%k(B
> ++$B$K$O(B 1 $B9T$K$D$-(B 1
> $B$D$N%3%^%s%I$r5-=R$7$^$9!#6u9T$OL5;k$5$l!"Fs=E%O%$%U(B
> ++$B%s$G;O$^$k9T$O%3%a%s%H$r0UL#$7$^$9!#(B
> ++
> ++$B%3%^%s%I$K$O!"(BSQL
> $B%3%^%s%I$K2C$(!"%P%C%/%9%i%C%7%e$G;O$^$k%a%?%3%^%s%I(B
> ++$B$r5-=R$9$k$3$H$,$G$-$^$9!#%a%?%3%^%s%I$O(B pgcbench
> $B<+?H$K$h$C$F<B9T$5$l(B
> ++$B$^$9!#%a%?%3%^%s%I$N7A<0$O%P%C%/%9%i%C%7%e!"$=$ND>8e$K%3%^%s%I$NF0;l!"(B
> ++$B$=$N<!$K0z?t$,B3$-$^$9!#F0;l%3%^%s%I$H0z?t!"$^$?$=$l$>$l$N0z?t$O6uGrJ8(B
> ++$B;z$K$h$C$F6hJL$5$l$^$9!#(B
> ++
> ++$B:#$N$H$3$m!"0J2<$N%a%?%3%^%s%I$,Dj5A$5$l$F$$$^$9!#(B
> ++
> ++\setrandom name min max
> ++
> ++ $B:G>.CM(B min $B$H:GBgCM(B max $B$N4V$NCM$r<h$kMp?t$r!"(Bname
> $BJQ?t$K@_Dj$7$^$9!#(B
> ++
> ++$BJQ?t$KMp?t$r@_Dj$9$k$K$O!"(B\setrandom
> $B%a%?%3%^%s%I$r;HMQ$7$F0J2<$N$h$&(B
> ++$B$K5-=R$7$^$9!#(B
> ++
> ++ \setrandom aid 1 100000
> ++
> ++$B$3$l$O!"JQ?t(B aid $B$K(B 1 $B$+$i(B 100000
> $B$N4V$NMp?t$r@_Dj$7$^$9!#$^$?!"JQ?t$N(B
> ++$BCM$r(B SQL
> $B%3%^%s%I$KKd$a9~$`$K$O!"0J2<$N$h$&$K$=$NL>A0$NA0$K%3%m%s$rIU(B
> ++$B$1$^$9!#(B
> ++
> ++ SELECT abalance FROM accounts WHERE aid = :aid
> ++
> ++$BNc$($P!"(BTPC-B
> $B$K;w$?%Y%s%A%^!<%/$r9T$&$K$O!"0J2<$N$h$&$K%H%i%s%6%/%7%g(B
> ++$B%s$NFbMF$r%U%!%$%k$K5-=R$7!"(B-f
> $B%*%W%7%g%s$K$h$C$F$=$N%U%!%$%k$r;XDj$7(B
> ++$B$F(B pgcbench $B$r<B9T$7$^$9!#(B
> ++
> ++ \setrandom aid 1 100000
> ++ \setrandom bid 1 1
> ++ \setrandom tid 1 10
> ++ \setrandom delta 1 1000
> ++ BEGIN
> ++ UPDATE accounts SET abalance = abalance + :delta WHERE aid = :aid
> ++ SELECT abalance FROM accounts WHERE aid = :aid
> ++ UPDATE tellers SET tbalance = tbalance + :delta WHERE tid = :tid
> ++ UPDATE branches SET bbalance = bbalance + :delta WHERE bid = :bid
> ++ INSERT INTO history (tid, bid, aid, delta, mtime) VALUES (:tid, :bid,
> :aid, :delta, 'now')
> ++
> ++$B$J$*!"$3$NNc$G$O!"(B-i $B%*%W%7%g%s$r;H$C$F=i4|2=$7$?%G!<%?%Y!<%9(B
> ($B%9%1!<(B
> ++$B%j%s%0%U%!%/%?!<$,(B 1 $B$N>l9g(B)
> $B$KBP$7$F%Y%s%A%^!<%/$r9T$&$3$H$r2>Dj$7$F(B
> ++$B$$$^$9!#(B
> ++
> ++
> ++$B"#(B $B%H%i%s%6%/%7%g%s$NDj5A(B
> ++
> ++pgcbench $B$N%G%U%)%k%H$N%Y%s%A%^!<%/$G$O!"0J2<$N(B SQL
> $B%3%^%s%I$rA4It40N;(B
> ++$B$7$F(B 1 $B%H%i%s%6%/%7%g%s$H?t$($F$$$^$9!#(B
> ++
> ++1. SELECT abalance FROM accounts WHERE aid = :aid
> ++
> ++ :aid $B$O(B 1 $B$+$i%9%1!<%j%s%0%U%!%/%?!<(B $B!_(B 10
> $BK|$^$G$NCM$r<h$kMp?t$G$9!#(B
> ++ $B$3$3$G$O(B 1
> $B7o$@$18!:w$5$l$^$9!#0J2<!"Mp?t$NCM$O$=$l$>$l$3$N%H%i%s%6(B
> ++ $B%/%7%g%s$NCf$G$OF1$8CM$r;H$$$^$9!#(B
> ++
> ++2. UPDATE accounts SET abalance = abalance + :delta WHERE aid = :aid
> ++
> ++ :delta $B$O(B 1 $B$+$i(B 1000 $B$^$G$NCM$r<h$kMp?t$G$9!#(B
> ++
> ++3. SELECT abalance FROM accounts WHERE aid = :aid
> ++
> ++4. INSERT INTO history (tid, bid, aid, delta, mtime) VALUES (:tid, :bid,
> :aid, :delta, 'now')
> ++
> ++ :tid $B$O(B 1 $B$+$i%9%1!<%j%s%0%U%!%/%?!<(B $B!_(B 10
> $B$^$G$NCM$r<h$kMp?t!"(B:bid
> ++ $B$O(B 1 $B$+$i%9%1!<%j%s%0%U%!%/%?!<$^$G$NCM$r<h$kMp?t$G$9!#(B
> ++
> ++5. INSERT INTO history (tid, bid, aid, delta, mtime) VALUES (:tid, :bid,
> :aid, :delta, 'now')
> ++
> ++6. INSERT INTO history (tid, bid, aid, delta, mtime) VALUES (:tid, :bid,
> :aid, :delta, 'now')
> ++
> ++7. SELECT abalance FROM accounts WHERE aid = :aid
> ++
> ++-T
> $B%*%W%7%g%s$r;XDj$7$F%H%i%s%6%/%7%g%s%V%m%C%/Fb$G%H%i%s%6%/%7%g%s$r(B
> ++$B<B9T$9$k>l9g!"(B1 $B$r(B BEGIN$B$K!"(B7 $B$r(B END
> $B$KCV$-49$($?(B SQL $B%3%^%s%I$,<B9T$5(B
> ++$B$l$^$9!#$^$?!"%H%i%s%6%/%7%g%s$H$7$F<B9T$5$l$k(B SQL
> $B%3%^%s%I$O!"(B-I $B%*%W(B
> ++$B%7%g%s(B ($BA^F~$N$_(B) $B$G$"$l$P(B 4$B!"(B-U ($B99?7$N$_(B)
> $B$G$"$l$P(B 2$B!"(B-S ($B8!:w$N$_(B)
> ++$B$G$"$l$P(B 1 $B$H$J$j$^$9!#(B
> +diff -aruN postgresql-8.1.2/src/pgcluster/tool/pgcbench.c
> pgcluster-1.5.0rc7/src/pgcluster/tool/pgcbench.c
> +--- postgresql-8.1.2/src/pgcluster/tool/pgcbench.c 1970-01-01
> 01:00:00.000000000 +0100
> ++++ pgcluster-1.5.0rc7/src/pgcluster/tool/pgcbench.c 2006-01-10
> 17:39:44.000000000 +0100
> +@@ -0,0 +1,1626 @@
> ++/*
> ++ * pgbench: a simple benchmark program for PGCluster
> ++ * This program was written based on pgbench by Tatsuo Ishii.
> ++ *
> ++ * Portions Copyright (c) 2003-2006, Atsushi Mitani
> ++ * Portions Copyright (c) 2000-2006, 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>
> ++
> ++#include <ctype.h>
> ++#include <search.h>
> ++
> ++extern char *optarg;
> ++extern int optind;
> ++
> ++#ifdef WIN32
> ++#undef select
> ++#endif
> ++
> ++
> ++/********************************************************************
> ++ * 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)
> ++#define CUSTOM_QUERY (6)
> ++
> ++#define SQL_COMMAND 1
> ++#define META_COMMAND 2
> ++
> ++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
> ++{
> ++ char *name;
> ++ char *value;
> ++} Variable;
> ++
> ++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;
> ++ void *variables;
> ++ struct timeval txn_begin; /* used for measuring latencies */
> ++} CState;
> ++
> ++typedef struct
> ++{
> ++ int type;
> ++ int argc;
> ++ char **argv;
> ++} Command;
> ++
> ++Command **commands = NULL;
> ++
> ++static void
> ++usage(void)
> ++{
> ++ fprintf(stderr, "usage: pgcbench [-h hostname][-p port][-c
> nclients][-t ntransactions][-s scaling_factor][-I(insert only)][-U(update
> only)][-S(select only)][-f filename][-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(void)
> ++{
> ++ 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);
> ++
> ++ 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 */
> ++}
> ++
> ++static int
> ++compareVariables(const void *v1, const void *v2)
> ++{
> ++ return strcmp(((Variable *)v1)->name, ((Variable *)v2)->name);
> ++}
> ++
> ++static char *
> ++getVariable(CState * st, char *name)
> ++{
> ++ Variable key = { name }, *var;
> ++
> ++ var = tfind(&key, &st->variables, compareVariables);
> ++ if (var != NULL)
> ++ return (*(Variable **)var)->value;
> ++ else
> ++ return NULL;
> ++}
> ++
> ++static int
> ++putVariable(CState * st, char *name, char *value)
> ++{
> ++ Variable key = { name }, *var;
> ++
> ++ var = tfind(&key, &st->variables, compareVariables);
> ++ if (var == NULL)
> ++ {
> ++ if ((var = malloc(sizeof(Variable))) == NULL)
> ++ return false;
> ++
> ++ var->name = NULL;
> ++ var->value = NULL;
> ++
> ++ if ((var->name = strdup(name)) == NULL
> ++ || (var->value = strdup(value)) == NULL
> ++ || tsearch(var, &st->variables, compareVariables) ==
> NULL)
> ++ {
> ++ free(var->name);
> ++ free(var->value);
> ++ free(var);
> ++ return false;
> ++ }
> ++ }
> ++ else
> ++ {
> ++ free((*(Variable **)var)->value);
> ++ if (((*(Variable **)var)->value = strdup(value)) == NULL)
> ++ return false;
> ++ }
> ++
> ++ return true;
> ++}
> ++
> ++static char *
> ++assignVariables(CState * st, char *sql)
> ++{
> ++ int i, j;
> ++ char *p, *name, *val;
> ++ void *tmp;
> ++
> ++ i = 0;
> ++ while ((p = strchr(&sql[i], ':')) != NULL)
> ++ {
> ++ i = j = p - sql;
> ++ do{
> ++ i++;
> ++ }while (isalnum((unsigned char) sql[i]) != 0 || sql[i] ==
> '_');
> ++ if (i == j + 1)
> ++ continue;
> ++
> ++ name = malloc(i - j);
> ++ if (name == NULL)
> ++ return NULL;
> ++ memcpy(name, &sql[j + 1], i-(j+1));
> ++ name[i-(j+1)] = '\0';
> ++ val = getVariable(st, name);
> ++ free(name);
> ++ if (val == NULL)
> ++ continue;
> ++
> ++ if (strlen(val) > i - j)
> ++ {
> ++ tmp = realloc(sql, strlen(sql) - (i - j) +
> strlen(val) + 1);
> ++ if (tmp == NULL)
> ++ {
> ++ free(sql);
> ++ return NULL;
> ++ }
> ++ sql = tmp;
> ++ }
> ++
> ++ if (strlen(val) != i - j)
> ++ memmove(&sql[j + strlen(val)], &sql[i],
> strlen(&sql[i]) + 1);
> ++
> ++ strncpy(&sql[j], val, strlen(val));
> ++
> ++ if (strlen(val) < i - j)
> ++ {
> ++ tmp = realloc(sql, strlen(sql) + 1);
> ++ if (tmp == NULL)
> ++ {
> ++ free(sql);
> ++ return NULL;
> ++ }
> ++ sql = tmp;
> ++ }
> ++
> ++ i = j + strlen(val);
> ++ }
> ++
> ++ return sql;
> ++}
> ++
> ++/* 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)
> ++ {
> ++ double diff;
> ++ struct timeval now;
> ++
> ++ gettimeofday(&now, NULL);
> ++ diff = (int) (now.tv_sec -
> st->txn_begin.tv_sec) * 1000000.0 +
> ++ (int) (now.tv_usec -
> st->txn_begin.tv_usec);
> ++
> ++ fprintf(LOGFILE, "%d %d %.0f\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), NULL);
> ++ 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 */
> ++ }
> ++}
> ++
> ++static void
> ++doCustom(CState * st, int debug, int ttype )
> ++{
> ++ PGresult *res;
> ++
> ++ if (st->listen)
> ++ { /* are we
> receiver? */
> ++ if (commands[st->state]->type == SQL_COMMAND)
> ++ {
> ++ 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 */
> ++ }
> ++
> ++ /*
> ++ * transaction finished: record the time it took in the
> ++ * log
> ++ */
> ++ if (use_log && commands[st->state + 1] == NULL)
> ++ {
> ++ double diff;
> ++ struct timeval now;
> ++
> ++ gettimeofday(&now, NULL);
> ++ diff = (int) (now.tv_sec - st->txn_begin.tv_sec) *
> 1000000.0 +
> ++ (int) (now.tv_usec - st->txn_begin.tv_usec);
> ++
> ++ fprintf(LOGFILE, "%d %d %.0f\n", st->id, st->cnt,
> diff);
> ++ }
> ++
> ++ if (commands[st->state]->type == SQL_COMMAND)
> ++ {
> ++ res = PQgetResult(st->con);
> ++ if (strncasecmp(commands[st->state]->argv[0],
> "select", 6) != 0)
> ++ {
> ++ if (check(st, res, PGRES_COMMAND_OK))
> ++ return;
> ++ }
> ++ else
> ++ {
> ++ if (check(st, res, PGRES_TUPLES_OK))
> ++ return;
> ++ }
> ++ PQclear(res);
> ++ discard_response(st);
> ++ }
> ++
> ++ if (commands[st->state + 1] == NULL)
> ++ {
> ++ 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;
> ++ }
> ++ }
> ++
> ++ /* increment state counter */
> ++ st->state++;
> ++ if (commands[st->state] == NULL)
> ++ {
> ++ 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;
> ++ }
> ++ }
> ++
> ++ if (use_log && st->state == 0)
> ++ gettimeofday(&(st->txn_begin), NULL);
> ++
> ++ if (commands[st->state]->type == SQL_COMMAND)
> ++ {
> ++ char *sql;
> ++
> ++ if ((sql = strdup(commands[st->state]->argv[0])) == NULL
> ++ || (sql = assignVariables(st, sql)) == NULL)
> ++ {
> ++ fprintf(stderr, "out of memory\n");
> ++ st->ecnt++;
> ++ return;
> ++ }
> ++
> ++ 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 */
> ++ }
> ++
> ++ free(sql);
> ++ }
> ++ else if (commands[st->state]->type == META_COMMAND)
> ++ {
> ++ int argc = commands[st->state]->argc, i;
> ++ char **argv = commands[st->state]->argv;
> ++
> ++ if (debug)
> ++ {
> ++ fprintf(stderr, "client executing \\%s", argv[0]);
> ++ for (i = 1; i < argc; i++)
> ++ fprintf(stderr, " %s", argv[i]);
> ++ fprintf(stderr, "\n");
> ++ }
> ++
> ++ if (strcasecmp(argv[0], "setrandom") == 0)
> ++ {
> ++ char *val;
> ++
> ++ if ((val = malloc(strlen(argv[3]) + 1)) == NULL)
> ++ {
> ++ fprintf(stderr, "%s: out of memory\n",
> argv[0]);
> ++ st->ecnt++;
> ++ return;
> ++ }
> ++
> ++ sprintf(val, "%d", getrand(atoi(argv[2]),
> atoi(argv[3])));
> ++
> ++ if (putVariable(st, argv[1], val) == false)
> ++ {
> ++ fprintf(stderr, "%s: out of memory\n",
> argv[0]);
> ++ free(val);
> ++ st->ecnt++;
> ++ return;
> ++ }
> ++
> ++ free(val);
> ++ st->listen++;
> ++ }
> ++ }
> ++}
> ++
> ++/* 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 not null,bbalance int,filler
> char(88))",
> ++ "drop table tellers",
> ++ "create table tellers(tid int not null,bid int,tbalance
> int,filler char(84))",
> ++ "drop table accounts",
> ++ "create table accounts(aid int not null,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))"};
> ++ static char *DDLAFTERs[] = {
> ++ "alter table branches add primary key (bid)",
> ++ "alter table tellers add primary key (tid)",
> ++ "alter table accounts add primary key (aid)"};
> ++
> ++
> ++ 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);
> ++ }
> ++ PQclear(res);
> ++
> ++ /*
> ++ * 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, i / naccounts + 1, 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 */
> ++ }
> ++ }
> ++ fprintf(stderr, "set primary key...\n");
> ++ for (i = 0; i < (sizeof(DDLAFTERs) / sizeof(char *)); i++)
> ++ {
> ++ res = PQexec(con, DDLAFTERs[i]);
> ++ if (PQresultStatus(res) != PGRES_COMMAND_OK)
> ++ {
> ++ fprintf(stderr, "%s", PQerrorMessage(con));
> ++ exit(1);
> ++ }
> ++ PQclear(res);
> ++ }
> ++
> ++ /* 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);
> ++}
> ++
> ++static int
> ++process_file(char *filename)
> ++{
> ++ const char delim[] = " \f\n\r\t\v";
> ++
> ++ FILE *fd;
> ++ int lineno, i, j;
> ++ char buf[BUFSIZ], *p, *tok;
> ++ void *tmp;
> ++
> ++ if (strcmp(filename, "-") == 0)
> ++ fd = stdin;
> ++ else if ((fd = fopen(filename, "r")) == NULL)
> ++ {
> ++ fprintf(stderr, "%s: %s\n", strerror(errno), filename);
> ++ return false;
> ++ }
> ++
> ++ fprintf(stderr, "processing file...\n");
> ++
> ++ lineno = 1;
> ++ i = 0;
> ++ while (fgets(buf, sizeof(buf), fd) != NULL)
> ++ {
> ++ if ((p = strchr(buf, '\n')) != NULL)
> ++ *p = '\0';
> ++ p = buf;
> ++ while (isspace((unsigned char)*p))
> ++ p++;
> ++ if (*p == '\0' || strncmp(p, "--", 2) == 0)
> ++ {
> ++ lineno++;
> ++ continue;
> ++ }
> ++
> ++ if ((tmp = realloc(commands, sizeof(Command *) * (i + 1))) ==
> NULL)
> ++ {
> ++ i--;
> ++ goto error;
> ++ }
> ++ commands = tmp;
> ++
> ++ if ((commands[i] = malloc(sizeof(Command))) == NULL)
> ++ goto error;
> ++
> ++ commands[i]->argv = NULL;
> ++ commands[i]->argc = 0;
> ++
> ++ if (*p == '\\')
> ++ {
> ++ commands[i]->type = META_COMMAND;
> ++
> ++ j = 0;
> ++ tok = strtok(++p, delim);
> ++ while (tok != NULL)
> ++ {
> ++ tmp = realloc(commands[i]->argv, sizeof(char
> *) * (j + 1));
> ++ if (tmp == NULL)
> ++ goto error;
> ++ commands[i]->argv = tmp;
> ++
> ++ if ((commands[i]->argv[j] = strdup(tok)) ==
> NULL)
> ++ goto error;
> ++
> ++ commands[i]->argc++;
> ++
> ++ j++;
> ++ tok = strtok(NULL, delim);
> ++ }
> ++
> ++ if (strcasecmp(commands[i]->argv[0], "setrandom") ==
> 0)
> ++ {
> ++ int min, max;
> ++
> ++ if (commands[i]->argc < 4)
> ++ {
> ++ fprintf(stderr, "%s: %d: \\%s:
> missing argument\n", filename, lineno, commands[i]->argv[0]);
> ++ goto error;
> ++ }
> ++
> ++ for (j = 4; j < commands[i]->argc; j++)
> ++ fprintf(stderr, "%s: %d: \\%s: extra
> argument \"%s\" ignored\n", filename, lineno, commands[i]->argv[0],
> commands[i]->argv[j]);
> ++
> ++ if ((min = atoi(commands[i]->argv[2])) < 0)
> ++ {
> ++ fprintf(stderr, "%s: %d: \\%s:
> invalid minimum number %s\n", filename, lineno, commands[i]->argv[0],
> commands[i]->argv[2]);
> ++ goto error;
> ++ }
> ++
> ++ if ((max = atoi(commands[i]->argv[3])) < min
> || max > RAND_MAX)
> ++ {
> ++ fprintf(stderr, "%s: %d: \\%s:
> invalid maximum number %s\n", filename, lineno, commands[i]->argv[0],
> commands[i]->argv[3]);
> ++ goto error;
> ++ }
> ++ }
> ++ else
> ++ {
> ++ fprintf(stderr, "%s: %d: invalid command
> \\%s\n", filename, lineno, commands[i]->argv[0]);
> ++ goto error;
> ++ }
> ++ }
> ++ else
> ++ {
> ++ commands[i]->type = SQL_COMMAND;
> ++
> ++ if ((commands[i]->argv = malloc(sizeof(char *))) ==
> NULL)
> ++ goto error;
> ++
> ++ if ((commands[i]->argv[0] = strdup(p)) == NULL)
> ++ goto error;
> ++
> ++ commands[i]->argc++;
> ++ }
> ++
> ++ i++;
> ++ lineno++;
> ++ }
> ++ fclose(fd);
> ++
> ++ if ((tmp = realloc(commands, sizeof(Command *) * (i + 1))) == NULL)
> ++ goto error;
> ++ commands = tmp;
> ++
> ++ commands[i] = NULL;
> ++
> ++ return true;
> ++
> ++error:
> ++ if (errno == ENOMEM)
> ++ fprintf(stderr, "%s: %d: out of memory\n", filename, lineno);
> ++
> ++ fclose(fd);
> ++
> ++ if (commands == NULL)
> ++ return false;
> ++
> ++ while (i >= 0)
> ++ {
> ++ if (commands[i] != NULL)
> ++ {
> ++ for (j = 0; j < commands[i]->argc; j++)
> ++ free(commands[i]->argv[j]);
> ++
> ++ free(commands[i]->argv);
> ++ free(commands[i]);
> ++ }
> ++
> ++ i--;
> ++ }
> ++ free(commands);
> ++
> ++ return false;
> ++}
> ++
> ++/* 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;
> ++ case CUSTOM_QUERY :
> ++ s = "Custom query";
> ++ 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, NULL);
> ++ srand((unsigned int) 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;
> ++ case CUSTOM_QUERY :
> ++ doCustom(&state, debug, ttype);
> ++ break;
> ++ default :
> ++ doOne(&state, debug, ttype);
> ++ break;
> ++ }
> ++
> ++ remains = max;
> ++ for (;;)
> ++ {
> ++ if (remains < min || !state.con)
> ++ {
> ++ break;
> ++ }
> ++
> ++ FD_ZERO(&input_mask);
> ++
> ++ if (ttype != CUSTOM_QUERY || commands[state.state]->type !=
> META_COMMAND)
> ++ {
> ++ 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)
> ++ || (ttype == CUSTOM_QUERY
> ++ &&
> commands[state.state]->type == META_COMMAND)))
> ++ {
> ++ switch (ttype)
> ++ {
> ++ case WITH_TRANSACTION :
> ++ case TPC_B_LIKE :
> ++ doMix(&state, debug, ttype);
> ++ break;
> ++ case CUSTOM_QUERY :
> ++ doCustom(&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)
> ++{
> ++ 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 */
> ++ char *filename = NULL;
> ++
> ++ struct timeval tv1; /* start up time */
> ++ struct timeval tv2; /* after establishing all
> connections to
> ++ * the
> backend */
> ++ struct timeval tv3; /* end time */
> ++
> ++#if !(defined(__CYGWIN__) || defined(__MINGW32__))
> ++ struct rlimit rlim;
> ++#endif
> ++
> ++ PGconn *con;
> ++ PGresult *res;
> ++ char *env;
> ++
> ++ if ((env = getenv("PGHOST")) != NULL && *env != '\0')
> ++ pghost = env;
> ++ if ((env = getenv("PGPORT")) != NULL && *env != '\0')
> ++ pgport = env;
> ++ else if ((env = getenv("PGUSER")) != NULL && *env != '\0')
> ++ login = env;
> ++
> ++ while ((c = getopt(argc, argv, "ih:nvp:dc:t:s:u:P:CNSlTUIf:")) != -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);
> ++ }
> ++#if !(defined(__CYGWIN__) || defined(__MINGW32__))
> ++#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 /* #if !(defined(__CYGWIN__) || defined(__MINGW32__)) */
> ++ 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;
> ++ case 'f':
> ++ ttype = CUSTOM_QUERY;
> ++ filename = optarg;
> ++ break;
> ++ default:
> ++ usage();
> ++ exit(1);
> ++ break;
> ++ }
> ++ }
> ++
> ++ if (argc > optind)
> ++ dbName = argv[optind];
> ++ else
> ++ {
> ++ if ((env = getenv("PGDATABASE")) != NULL && *env != '\0')
> ++ dbName = env;
> ++ else if (login != NULL && *login != '\0')
> ++ dbName = login;
> ++ else
> ++ 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);
> ++ }
> ++
> ++ if (ttype == CUSTOM_QUERY)
> ++ {
> ++ PQfinish(con);
> ++ if (process_file(filename) == false)
> ++ exit(1);
> ++ }
> ++ else
> ++ {
> ++ /*
> ++ * 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, NULL);
> ++ srand((unsigned int) tv1.tv_usec);
> ++ /* get start up time */
> ++ gettimeofday(&tv1, NULL);
> ++ /* time after connections set up */
> ++ gettimeofday(&tv2, NULL);
> ++
> ++ doClient(debug, ttype);
> ++
> ++ /* get end time */
> ++ gettimeofday(&tv3, NULL);
> ++ printResults(ttype, nxacts, &tv1, &tv2, &tv3);
> ++ if (LOGFILE)
> ++ fclose(LOGFILE);
> ++ return 1;
> ++}
> +diff -aruN postgresql-8.1.2/src/pgcluster/tool/pgcbench.sh
> pgcluster-1.5.0rc7/src/pgcluster/tool/pgcbench.sh
> +--- postgresql-8.1.2/src/pgcluster/tool/pgcbench.sh 1970-01-01
> 01:00:00.000000000 +0100
> ++++ pgcluster-1.5.0rc7/src/pgcluster/tool/pgcbench.sh 2006-01-10
> 17:39:44.000000000 +0100
> +@@ -0,0 +1,30 @@
> ++#! /bin/bash
> ++
> ++set -e
> ++
> ++while getopts ih:nvp:dc:t:s:u:P:CNSlTUIf: opt; do
> ++ case $opt in
> ++ f)
> ++ filename=$OPTARG
> ++ ;;
> ++ *)
> ++ opts=(${opts[@]} -$opt $OPTARG)
> ++ ;;
> ++ esac
> ++done
> ++shift $(($OPTIND - 1))
> ++dbname=$1
> ++
> ++tps=$(psql -At -c "SELECT count(*) FROM branches" $dbname)
> ++
> ++vacuumdb -t branches $dbname
> ++vacuumdb -t tellers $dbname
> ++psql -c "DELETE FROM history" $dbname
> ++vacuumdb -t history $dbname
> ++
> ++if [ -z $filename ]; then
> ++ pgcbench ${opts[@]} $@
> ++else
> ++ perl -pe "BEGIN { \$tps = $tps } s/\`([^\`]+)\`/eval \$1/eg"
> $filename \
> ++ | pgcbench ${opts[@]} -f - $@
> ++fi
> +diff -aruN postgresql-8.1.2/src/pgcluster/tool/tpc-b_like.sql
> pgcluster-1.5.0rc7/src/pgcluster/tool/tpc-b_like.sql
> +--- postgresql-8.1.2/src/pgcluster/tool/tpc-b_like.sql 1970-01-01
> 01:00:00.000000000 +0100
> ++++ pgcluster-1.5.0rc7/src/pgcluster/tool/tpc-b_like.sql 2006-01-10
> 17:39:44.000000000 +0100
> +@@ -0,0 +1,11 @@
> ++\setrandom aid 1 `100000 * $tps`
> ++\setrandom bid 1 `1 * $tps`
> ++\setrandom tid 1 `10 * $tps`
> ++\setrandom delta 1 1000
> ++BEGIN
> ++UPDATE accounts SET abalance = abalance + :delta WHERE aid = :aid
> ++SELECT abalance FROM accounts WHERE aid = :aid
> ++UPDATE tellers SET tbalance = tbalance + :delta WHERE tid = :tid
> ++UPDATE branches SET bbalance = bbalance + :delta WHERE bid = :bid
> ++INSERT INTO history (tid, bid, aid, delta, mtime) VALUES (:tid, :bid,
> :aid, :delta, current_timestamp)
> ++END
> _______________________________________________
> SM-Commit mailing list
> SM-Commit AT lists.ibiblio.org
> http://lists.ibiblio.org/mailman/listinfo/sm-commit




Archive powered by MHonArc 2.6.24.

Top of Page