Skip to Content.
Please activate JavaScript in your web browser
List archive
Re: [SM-Commit] GIT changes to master grimoire by Arjan Bouter (3938db04ccd796caf6c0af01356e054cd355dc01)
Chronological
Thread
<
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
[SM-Commit] GIT changes to master grimoire by Arjan Bouter (3938db04ccd796caf6c0af01356e054cd355dc01)
,
Arjan Bouter, 11/09/2006
Re: [SM-Commit] GIT changes to master grimoire by Arjan Bouter (3938db04ccd796caf6c0af01356e054cd355dc01)
,
Andrew Stitt, 11/11/2006
Archive powered by
MHonArc 2.6.24
.