diff options
author | jsdelfino <jsdelfino@13f79535-47bb-0310-9956-ffa450edef68> | 2012-05-28 04:39:28 +0000 |
---|---|---|
committer | jsdelfino <jsdelfino@13f79535-47bb-0310-9956-ffa450edef68> | 2012-05-28 04:39:28 +0000 |
commit | 4a28afdf7a6b193942f180862d443a7d818c5789 (patch) | |
tree | dd1afbf7757a075f768af1b4e588e5dabc2a5f71 /sca-cpp/trunk/components | |
parent | f278315081b24b59bf73e9613e552e3519200a71 (diff) |
Database support optimizations. Use PgBouncer to pool connections. Track and manage WAL archives to optimize space and speed up database replication setup.
git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@1343139 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'sca-cpp/trunk/components')
-rw-r--r-- | sca-cpp/trunk/components/sqldb/Makefile.am | 6 | ||||
-rwxr-xr-x | sca-cpp/trunk/components/sqldb/pgsql | 2 | ||||
-rwxr-xr-x | sca-cpp/trunk/components/sqldb/pgsql-archive | 59 | ||||
-rwxr-xr-x | sca-cpp/trunk/components/sqldb/pgsql-backup | 38 | ||||
-rwxr-xr-x | sca-cpp/trunk/components/sqldb/pgsql-clean-archive | 58 | ||||
-rwxr-xr-x | sca-cpp/trunk/components/sqldb/pgsql-conf | 60 | ||||
-rwxr-xr-x | sca-cpp/trunk/components/sqldb/pgsql-restore | 30 | ||||
-rwxr-xr-x | sca-cpp/trunk/components/sqldb/pgsql-standby-conf | 66 | ||||
-rw-r--r-- | sca-cpp/trunk/components/sqldb/pgsql-standby-test.cpp | 8 | ||||
-rwxr-xr-x | sca-cpp/trunk/components/sqldb/pgsql-start | 5 | ||||
-rwxr-xr-x | sca-cpp/trunk/components/sqldb/pgsql-stop | 7 | ||||
-rw-r--r-- | sca-cpp/trunk/components/sqldb/pgsql-test.cpp | 4 | ||||
-rw-r--r-- | sca-cpp/trunk/components/sqldb/pgsql.hpp | 103 | ||||
-rw-r--r-- | sca-cpp/trunk/components/sqldb/sqldb.componentType | 2 | ||||
-rw-r--r-- | sca-cpp/trunk/components/sqldb/sqldb.composite | 2 |
15 files changed, 348 insertions, 102 deletions
diff --git a/sca-cpp/trunk/components/sqldb/Makefile.am b/sca-cpp/trunk/components/sqldb/Makefile.am index 0443de07d9..9ce5f26713 100644 --- a/sca-cpp/trunk/components/sqldb/Makefile.am +++ b/sca-cpp/trunk/components/sqldb/Makefile.am @@ -22,12 +22,14 @@ INCLUDES = -I${PGSQL_INCLUDE} incl_HEADERS = *.hpp incldir = $(prefix)/include/components/sqldb -dist_comp_SCRIPTS = pgsql-conf pgsql-log-conf pgsql-start pgsql-stop pgsql pgsql-standby-conf pgsql-backup +dist_comp_SCRIPTS = pgsql-conf pgsql-log-conf pgsql-start pgsql-stop pgsql pgsql-standby-conf pgsql-archive pgsql-backup pgsql-restore pgsql-clean-archive compdir=$(prefix)/components/sqldb -comp_DATA = pgsql.prefix +comp_DATA = pgsql.prefix pgbouncer.prefix pgsql.prefix: $(top_builddir)/config.status echo ${PGSQL_PREFIX} >pgsql.prefix +pgbouncer.prefix: $(top_builddir)/config.status + echo ${PGBOUNCER_PREFIX} >pgbouncer.prefix EXTRA_DIST = sqldb.composite sqldb.componentType diff --git a/sca-cpp/trunk/components/sqldb/pgsql b/sca-cpp/trunk/components/sqldb/pgsql index 8079fde7b1..8a60068ab7 100755 --- a/sca-cpp/trunk/components/sqldb/pgsql +++ b/sca-cpp/trunk/components/sqldb/pgsql @@ -23,7 +23,7 @@ pgsql_prefix=`cat $here/pgsql.prefix` if [ "$2" = "" ]; then host="localhost" - port="5432" + port="6432" cmd="$1" else host="$1" diff --git a/sca-cpp/trunk/components/sqldb/pgsql-archive b/sca-cpp/trunk/components/sqldb/pgsql-archive new file mode 100755 index 0000000000..128e6eb539 --- /dev/null +++ b/sca-cpp/trunk/components/sqldb/pgsql-archive @@ -0,0 +1,59 @@ +#!/bin/sh + +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +# PostgreSQL archive command +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +root=`echo "import os; print os.path.realpath('$1')" | python` + +host=$2 +port=$3 +walp=$4 +walf=$5 + +# Copy WAL to archive directory +if [ ! -f $root/sqldb/archive/$walf ]; then + cp $walp $root/sqldb/archive/$walf + rc=$? + if [ "$rc" != "0" ]; then + exit $rc + fi +fi + +# Trigger a backup if we have 10 WAL files archived since the last backup +lastbak=`ls $root/sqldb/archive | sort -r | grep "\.backup$" | head -1` +if [ "$lastbak" = "" ]; then + exit 0 +fi +wals=`ls $root/sqldb/archive | sort -r | grep -v "\.backup\.tar\.gz$"` + +w=0 +for f in $wals; do + if [ "$f" = "$lastbak" ]; then + break + fi + w=$((w+1)) + + if [ "$w" = "10" ]; then + nohup /bin/sh -c "$here/pgsql-backup $root $host $port" 1>/dev/null 2>/dev/null & + break + fi +done + +exit 0 + diff --git a/sca-cpp/trunk/components/sqldb/pgsql-backup b/sca-cpp/trunk/components/sqldb/pgsql-backup index c0b1c4b2aa..ff660ad20d 100755 --- a/sca-cpp/trunk/components/sqldb/pgsql-backup +++ b/sca-cpp/trunk/components/sqldb/pgsql-backup @@ -23,7 +23,7 @@ root=`echo "import os; print os.path.realpath('$1')" | python` if [ "$2" = "" ]; then host="localhost" - port="5432" + port="6432" else host="$2" port="$3" @@ -40,12 +40,40 @@ fi mkdir -p $root/sqldb echo $pgsql_log >$root/sqldb/logger -$pgsql_prefix/bin/psql -h $host -p $port -c "SELECT pg_start_backup('backup', true)" db 2>&1 | sh $root/sqldb/logger +mkdir -p $root/sqldb/backup +mkdir -p $root/sqldb/archive -echo "Content-type: application/x-compressed" -echo +# Make sure that only one backup is in progress at a time +if [ -f $root/sqldb/backup/inprogress ]; then + exit 0 +fi +touch $root/sqldb/backup/inprogress + +# Backup +stamp=`date +%Y%m%d%H%M%S` +$pgsql_prefix/bin/psql -h $host -p $port -c "SELECT pg_start_backup('$stamp', true)" db 2>&1 | sh $root/sqldb/logger -tar -C $root/sqldb -cz data +uname=`uname -s` +if [ $uname = "Darwin" ]; then + tar=gnutar +else + tar=tar +fi +$tar -C $root/sqldb --exclude data/postmaster.pid --exclude data/postmaster.opts --exclude data/pg_xlog --ignore-failed-read -czf $root/sqldb/backup/$stamp.backup.tar.gz data +rc=$? +if [ "$rc" = "0" ]; then + mv $root/sqldb/backup/$stamp.backup.tar.gz $root/sqldb/archive/$stamp.backup.tar.gz +fi $pgsql_prefix/bin/psql -h $host -p $port -c "SELECT pg_stop_backup()" db 2>&1 | sh $root/sqldb/logger +if [ "$rc" != "0" ]; then + rm -f $root/sqldb/backup/inprogress + exit $rc +fi + +# Clean obsolete backup and WAL files +$here/pgsql-clean-archive $root + +rm -f $root/sqldb/backup/inprogress + diff --git a/sca-cpp/trunk/components/sqldb/pgsql-clean-archive b/sca-cpp/trunk/components/sqldb/pgsql-clean-archive new file mode 100755 index 0000000000..0e52fade89 --- /dev/null +++ b/sca-cpp/trunk/components/sqldb/pgsql-clean-archive @@ -0,0 +1,58 @@ +#!/bin/sh + +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +# Cleanup database archive. +# Keep the last two backups and corresponding WAL files. + +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +root=`echo "import os; print os.path.realpath('$1')" | python` + +baks=`ls $root/sqldb/archive | sort -r | grep "\.backup$" | head -2` +wals=`ls $root/sqldb/archive | sort -r | grep -v "\.backup\.tar\.gz$"` +tars=`ls $root/sqldb/archive | sort -r | grep "\.backup\.tar\.gz$"` + +for f in $baks; do + if [ "$lastbak" = "" ]; then + lastbak=$f + else + prevbak=$f + fi +done + +w=0 +for f in $wals; do + if [ "$w" = "2" ]; then + rm $root/sqldb/archive/$f + fi + if [ "$w" = "1" ]; then + w=2 + fi + if [ "$f" = "$prevbak" ]; then + w=1 + fi +done + +t=0 +for f in $tars; do + if [ "$t" = "2" ]; then + rm $root/sqldb/archive/$f + fi + t=$((t+1)) +done + diff --git a/sca-cpp/trunk/components/sqldb/pgsql-conf b/sca-cpp/trunk/components/sqldb/pgsql-conf index 58d38412ca..482048a295 100755 --- a/sca-cpp/trunk/components/sqldb/pgsql-conf +++ b/sca-cpp/trunk/components/sqldb/pgsql-conf @@ -33,11 +33,15 @@ else fi port=`$here/../../modules/http/httpd-addr port $addr` fi +bport=`expr $port + 1000` pgsql_prefix=`cat $here/pgsql.prefix` +pgbouncer_prefix=`cat $here/pgbouncer.prefix` + mkdir -p $root/sqldb/data chmod 700 $root/sqldb/data mkdir -p $root/sqldb/archive +mkdir -p $root/sqldb/backup if [ -f "$root/sqldb/log.conf" ]; then pgsql_log=`cat $root/sqldb/log.conf` @@ -48,6 +52,7 @@ fi mkdir -p $root/sqldb echo $pgsql_log >$root/sqldb/logger +# Initialize PostgreSQL if [ ! -f $root/sqldb/data/postgresql.conf ]; then $pgsql_prefix/bin/pg_ctl init -D $root/sqldb/data 2>&1 | sh $root/sqldb/logger cp $root/sqldb/data/postgresql.conf $root/sqldb/data/postgresql-init.conf @@ -77,7 +82,7 @@ port = $port # Setup archival archive_mode = on -archive_command = 'cp %p $root/sqldb/archive/%f' +archive_command = '$here/pgsql-archive $root localhost $bport %p %f' # Setup hot standby with streaming replication wal_level = hot_standby @@ -97,7 +102,7 @@ host replication all samenet trust EOF -# Create the db +# Create the db if it's not created yet nohup /bin/sh -c "($pgsql_prefix/bin/pg_ctl start -W -D $root/sqldb/data 2>&1 | sh $root/sqldb/logger)" 1>/dev/null 2>/dev/null & sti=0 while [ $sti -ne 30 ]; do @@ -110,15 +115,22 @@ while [ $sti -ne 30 ]; do done $pgsql_prefix/bin/createdb -h localhost -p $port db 2>&1 | sh $root/sqldb/logger + +# Backup the db if there's no backup for it yet +baks=`ls $root/sqldb/archive | sort -r | grep "\.backup\.tar\.gz$"` +if [ "$baks" = "" ]; then + $here/pgsql-backup $root localhost $port +fi + $pgsql_prefix/bin/pg_ctl stop -w -D $root/sqldb/data 2>&1 | sh $root/sqldb/logger -# Generate database backup script +# Generate database restore script mkdir -p $root/sqldb/scripts -cat >$root/sqldb/scripts/backup <<EOF +cat >$root/sqldb/scripts/restore <<EOF #!/bin/sh -$here/pgsql-backup $root localhost $port +$here/pgsql-restore $root EOF -chmod 700 $root/sqldb/scripts/backup +chmod 700 $root/sqldb/scripts/restore # Configure HTTPD to serve backup and archive files if [ -f "$root/conf/httpd.conf" ]; then @@ -126,10 +138,44 @@ if [ -f "$root/conf/httpd.conf" ]; then # Generated by: pgsql-conf $* # Serve PostgreSQL backup and WAL archive files -ScriptAlias /pgsql-backup "$root/sqldb/scripts/backup" +ScriptAlias /pgsql-restore "$root/sqldb/scripts/restore" Alias /pgsql-archive "$root/sqldb/archive" EOF fi +# Configure PgBouncer +mkdir -p $root/logs +id=`id -un` +cat >$root/sqldb/data/pgbouncer.conf <<EOF + +[databases] +db = host=localhost dbname=db + +[pgbouncer] +pool_mode = session +listen_port = $bport +listen_addr = $ip +auth_type = trust +auth_file=$root/sqldb/data/pgbouncer-auth.conf +logfile = $root/logs/pgbouncer +pidfile = $root/logs/pgbouncer.pid +max_client_conn = 1000 +pool_mode = transaction +server_reset_query = +default_pool_size = 500 +min_pool_size = 5 +reserve_pool_size = 50 +log_connections = 0 +log_disconnections = 0 +stats_period = 3600 +admin_users = $id + +EOF + +cat >$root/sqldb/data/pgbouncer-auth.conf <<EOF +"$id" "password" + +EOF + diff --git a/sca-cpp/trunk/components/sqldb/pgsql-restore b/sca-cpp/trunk/components/sqldb/pgsql-restore new file mode 100755 index 0000000000..e91eba2a6b --- /dev/null +++ b/sca-cpp/trunk/components/sqldb/pgsql-restore @@ -0,0 +1,30 @@ +#!/bin/sh + +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +# Backup postgresql data directory +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +root=`echo "import os; print os.path.realpath('$1')" | python` + +tar=`ls $root/sqldb/archive | sort -r | grep "\.backup\.tar\.gz$" | head -1` + +echo "Content-type: application/x-compressed" +echo "" + +cat $root/sqldb/archive/$tar + diff --git a/sca-cpp/trunk/components/sqldb/pgsql-standby-conf b/sca-cpp/trunk/components/sqldb/pgsql-standby-conf index bc0d4e9981..77d1dfa8e2 100755 --- a/sca-cpp/trunk/components/sqldb/pgsql-standby-conf +++ b/sca-cpp/trunk/components/sqldb/pgsql-standby-conf @@ -34,6 +34,7 @@ else fi port=`$here/../../modules/http/httpd-addr port $addr` fi +bport=`expr $port + 1000` # Master server address if [ "$3" = "" ]; then @@ -47,6 +48,12 @@ else fi pgsql_prefix=`cat $here/pgsql.prefix` +pgbouncer_prefix=`cat $here/pgbouncer.prefix` + +mkdir -p $root/sqldb/data +chmod 700 $root/sqldb/data +mkdir -p $root/sqldb/archive +mkdir -p $root/sqldb/backup if [ -f "$root/sqldb/log.conf" ]; then pgsql_log=`cat $root/sqldb/log.conf` @@ -57,14 +64,15 @@ fi mkdir -p $root/sqldb echo $pgsql_log >$root/sqldb/logger -mkdir -p $root/sqldb/data -chmod 700 $root/sqldb/data -mkdir -p $root/sqldb/archive - # Initialize from a backup of the master if [ ! -f $root/sqldb/data/postgresql.conf ]; then - (curl -L -# http://$mhost:$mhttpport/pgsql-backup | tar -C $root/sqldb -xz) 2>&1 | grep -v "100.0%" | sh $root/sqldb/logger - rm -rf $root/sqldb/data/postmaster.pid $root/sqldb/data/pg_xlog + uname=`uname -s` + if [ $uname = "Darwin" ]; then + tar=gnutar + else + tar=tar + fi + (curl -L -# http://$mhost:$mhttpport/pgsql-restore | $tar -C $root/sqldb -xz) 2>&1 | grep -v "100.0%" | sh $root/sqldb/logger mkdir -p $root/sqldb/data/pg_xlog/archive_status chmod 700 $root/sqldb/data/pg_xlog/archive_status fi @@ -92,7 +100,7 @@ port = $port # Setup archival archive_mode = on -archive_command = 'cp %p $root/sqldb/archive/%f' +archive_command = '$here/pgsql-archive $root localhost $bport %p %f' # Setup hot standby with streaming replication wal_level = hot_standby @@ -119,13 +127,13 @@ restore_command = 'curl -L -# http://$mhost:$mhttpport/pgsql-archive/%f -o "%p" EOF -# Generate database backup script +# Generate database restore script mkdir -p $root/sqldb/scripts -cat >$root/sqldb/scripts/backup <<EOF +cat >$root/sqldb/scripts/restore <<EOF #!/bin/sh -$here/pgsql-backup $root localhost $port +$here/pgsql-restore $root EOF -chmod 700 $root/sqldb/scripts/backup +chmod 700 $root/sqldb/scripts/restore # Configure HTTPD to serve backup and archive files if [ -f "$root/conf/httpd.conf" ]; then @@ -133,10 +141,44 @@ if [ -f "$root/conf/httpd.conf" ]; then # Generated by: pgsql-standby-conf $* # Serve PostgreSQL backup and WAL archive files -ScriptAlias /pgsql-backup "$root/sqldb/scripts/backup" +ScriptAlias /pgsql-restore "$root/sqldb/scripts/restore" Alias /pgsql-archive "$root/sqldb/archive" EOF fi +# Configure PgBouncer +mkdir -p $root/logs +id=`id -un` +cat >$root/sqldb/data/pgbouncer.conf <<EOF + +[databases] +db = host=localhost dbname=db + +[pgbouncer] +pool_mode = session +listen_port = $bport +listen_addr = $ip +auth_type = trust +auth_file=$root/sqldb/data/pgbouncer-auth.conf +logfile = $root/logs/pgbouncer +pidfile = $root/logs/pgbouncer.pid +max_client_conn = 1000 +pool_mode = transaction +server_reset_query = +default_pool_size = 500 +min_pool_size = 5 +reserve_pool_size = 50 +log_connections = 0 +log_disconnections = 0 +stats_period = 3600 +admin_users = $id + +EOF + +cat >$root/sqldb/data/pgbouncer-auth.conf <<EOF +"$id" "password" + +EOF + diff --git a/sca-cpp/trunk/components/sqldb/pgsql-standby-test.cpp b/sca-cpp/trunk/components/sqldb/pgsql-standby-test.cpp index 44f0a4a9e6..2cd25f874a 100644 --- a/sca-cpp/trunk/components/sqldb/pgsql-standby-test.cpp +++ b/sca-cpp/trunk/components/sqldb/pgsql-standby-test.cpp @@ -33,8 +33,8 @@ namespace tuscany { namespace pgsql { bool testPGSql() { - PGSql wpg("host=localhost port=5432 dbname=db", "test"); - PGSql rpg("host=localhost port=5433 dbname=db", "test"); + PGSql wpg("host=localhost port=6432 dbname=db", "test"); + PGSql rpg("host=localhost port=6433 dbname=db", "test"); const value k = mklist<value>("a"); assert(hasContent(post(k, string("AAA"), wpg))); @@ -63,8 +63,8 @@ struct getLoop { bool testGetPerf() { const value k = mklist<value>("c"); - PGSql wpg("host=localhost port=5432 dbname=db", "test"); - PGSql rpg("host=localhost port=5433 dbname=db", "test"); + PGSql wpg("host=localhost port=6432 dbname=db", "test"); + PGSql rpg("host=localhost port=6433 dbname=db", "test"); assert(hasContent(post(k, string("CCC"), wpg))); sleep(1); diff --git a/sca-cpp/trunk/components/sqldb/pgsql-start b/sca-cpp/trunk/components/sqldb/pgsql-start index 2955bec991..6b388d29f0 100755 --- a/sca-cpp/trunk/components/sqldb/pgsql-start +++ b/sca-cpp/trunk/components/sqldb/pgsql-start @@ -22,6 +22,7 @@ here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $h root=`echo "import os; print os.path.realpath('$1')" | python` pgsql_prefix=`cat $here/pgsql.prefix` +pgbouncer_prefix=`cat $here/pgbouncer.prefix` if [ -f "$root/sqldb/log.conf" ]; then pgsql_log=`cat $root/sqldb/log.conf` @@ -43,3 +44,7 @@ while [ $sti -ne 30 ]; do sti=$((sti+1)) done +# Start PgBouncer +mkdir -p $root/logs +$pgbouncer_prefix/bin/pgbouncer -q -d $root/sqldb/data/pgbouncer.conf + diff --git a/sca-cpp/trunk/components/sqldb/pgsql-stop b/sca-cpp/trunk/components/sqldb/pgsql-stop index fbb9997961..16b6506838 100755 --- a/sca-cpp/trunk/components/sqldb/pgsql-stop +++ b/sca-cpp/trunk/components/sqldb/pgsql-stop @@ -22,6 +22,7 @@ here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $h root=`echo "import os; print os.path.realpath('$1')" | python` pgsql_prefix=`cat $here/pgsql.prefix` +pgbouncer_prefix=`cat $here/pgbouncer.prefix` if [ -f "$root/sqldb/log.conf" ]; then pgsql_log=`cat $root/sqldb/log.conf` @@ -32,5 +33,11 @@ fi mkdir -p $root/sqldb echo $pgsql_log >$root/sqldb/logger +pgb="$pgbouncer_prefix/bin/pgbouncer -q -d $root/sqldb/data/pgbouncer.conf" +k=`ps -ef | grep -v grep | grep "${pgb}" | awk '{ print $2 }'` +if [ "$k" != "" ]; then + kill $k +fi + $pgsql_prefix/bin/pg_ctl stop -w -D $root/sqldb/data 2>&1 | sh $root/sqldb/logger diff --git a/sca-cpp/trunk/components/sqldb/pgsql-test.cpp b/sca-cpp/trunk/components/sqldb/pgsql-test.cpp index 1019667285..d10ab5f4c2 100644 --- a/sca-cpp/trunk/components/sqldb/pgsql-test.cpp +++ b/sca-cpp/trunk/components/sqldb/pgsql-test.cpp @@ -33,7 +33,7 @@ namespace tuscany { namespace pgsql { bool testPGSql() { - PGSql pg("host=localhost port=5432 dbname=db", "test"); + PGSql pg("host=localhost port=6432 dbname=db", "test"); const value k = mklist<value>("a"); assert(hasContent(post(k, string("AAA"), pg))); @@ -59,7 +59,7 @@ struct getLoop { bool testGetPerf() { const value k = mklist<value>("c"); - PGSql pg("host=localhost port=5432 dbname=db", "test"); + PGSql pg("host=localhost port=6432 dbname=db", "test"); assert(hasContent(post(k, string("CCC"), pg))); const lambda<bool()> gl = getLoop(k, pg); diff --git a/sca-cpp/trunk/components/sqldb/pgsql.hpp b/sca-cpp/trunk/components/sqldb/pgsql.hpp index 74d638f370..d38af54c97 100644 --- a/sca-cpp/trunk/components/sqldb/pgsql.hpp +++ b/sca-cpp/trunk/components/sqldb/pgsql.hpp @@ -61,12 +61,30 @@ public: PGSql(const string& conninfo, const string& table) : owner(true), conn(NULL), conninfo(conninfo), table(table) { debug(conninfo, "pgsql::pgsql::conninfo"); debug(table, "pgsql::pgsql::table"); + + // Connect to the database conn = PQconnectdb(c_str(conninfo)); if (PQstatus(conn) != CONNECTION_OK) { mkfailure<bool>(string("Couldn't connect to postgresql database: ") + PQerrorMessage(conn)); return; } - setup(true); + + // Find the name of the first column in the target table + // Assume that's the key we need to use + string ks = string("select a.attname from pg_attribute a, pg_class c where a.attrelid = c.relfilenode and c.relname = '") + table + string("' and a.attnum in (1, 2) order by a.attnum;"); + PGresult* kr = PQexec(conn, c_str(ks)); + if (PQresultStatus(kr) != PGRES_TUPLES_OK) { + mkfailure<bool>(string("Couldn't execute postgresql column select statement: ") + pgfailure(kr, conn)); + return; + } + if (PQntuples(kr) != 2) { + PQclear(kr); + mkfailure<bool>(string("Couldn't find postgresql table key and value column names")); + return; + } + kname = PQgetvalue(kr, 0, 0); + vname = PQgetvalue(kr, 1, 0); + PQclear(kr); } PGSql(const PGSql& c) : owner(false), conn(c.conn), conninfo(c.conninfo), table(c.table) { @@ -86,78 +104,29 @@ private: bool owner; PGconn *conn; string conninfo; - string table; + const string table; + string kname; + string vname; friend const failable<bool> setup(const PGSql& pgsql); friend const failable<bool> post(const value& key, const value& val, const PGSql& pgsql); friend const failable<bool> put(const value& key, const value& val, const PGSql& pgsql); friend const failable<value> get(const value& key, const PGSql& pgsql); friend const failable<bool> del(const value& key, const PGSql& pgsql); - - /** - * Setup the database connection. - */ - const failable<bool> setup(const bool init) const { - - // Check the status of the connection and reconnect if necessary - if (!init) { - if (PQstatus(conn) == CONNECTION_OK) - return true; - debug("pgsql::setup::reset"); - PQreset(conn); - if (PQstatus(conn) != CONNECTION_OK) - return mkfailure<bool>(string("Couldn't reconnect to postgresql database: ") + PQerrorMessage(conn)); - } - debug("pgsql::setup::init"); - - // Find the name of the first column in the target table - // Assume that's the key we need to use - string ks = string("select a.attname from pg_attribute a, pg_class c where a.attrelid = c.relfilenode and c.relname = '") + table + string("' and a.attnum in (1, 2) order by a.attnum;"); - PGresult* kr = PQexec(conn, c_str(ks)); - if (PQresultStatus(kr) != PGRES_TUPLES_OK) - return mkfailure<bool>(string("Couldn't execute postgresql column select statement: ") + pgfailure(kr, conn)); - if (PQntuples(kr) != 2) { - PQclear(kr); - return mkfailure<bool>(string("Couldn't find postgresql table key and value column names")); - } - const string kname = PQgetvalue(kr, 0, 0); - const string vname = PQgetvalue(kr, 1, 0); - PQclear(kr); - - // Prepare the post, put, get and delete statements - { - PGresult* r = PQprepare(conn, "post", c_str(string("insert into ") + table + string(" values($1, $2);")), 2, NULL); - if (PQresultStatus(r) != PGRES_COMMAND_OK) - return mkfailure<bool>(string("Couldn't prepare post postgresql SQL statement: ") + pgfailure(r, conn)); - PQclear(r); - } - { - PGresult* r = PQprepare(conn, "put", c_str(string("update ") + table + string(" set ") + vname + string(" = $2 where ") + kname + string(" = $1;")), 2, NULL); - if (PQresultStatus(r) != PGRES_COMMAND_OK) - return mkfailure<bool>(string("Couldn't prepare put postgresql SQL statement: ") + pgfailure(r, conn)); - PQclear(r); - } - { - PGresult* r = PQprepare(conn, "get", c_str(string("select * from ") + table + string(" where ") + kname + string(" = $1;")), 1, NULL); - if (PQresultStatus(r) != PGRES_COMMAND_OK) - return mkfailure<bool>(string("Couldn't prepare get postgresql SQL statement: ") + pgfailure(r, conn)); - PQclear(r); - } - { - PGresult* r = PQprepare(conn, "delete", c_str(string("delete from ") + table + string(" where ") + kname + string(" = $1;")), 1, NULL); - if (PQresultStatus(r) != PGRES_COMMAND_OK) - return mkfailure<bool>(string("Couldn't prepare delete postgresql SQL statement: ") + pgfailure(r, conn)); - PQclear(r); - } - return true; - } }; /** * Setup the database connection if necessary. */ const failable<bool> setup(const PGSql& pgsql) { - return pgsql.setup(false); + debug("pgsql::setup"); + if (PQstatus(pgsql.conn) == CONNECTION_OK) + return true; + debug("pgsql::setup::reset"); + PQreset(pgsql.conn); + if (PQstatus(pgsql.conn) != CONNECTION_OK) + return mkfailure<bool>(string("Couldn't reconnect to postgresql database: ") + PQerrorMessage(pgsql.conn)); + return true; } /** @@ -173,7 +142,7 @@ const failable<bool> post(const value& key, const value& val, const PGSql& pgsql const string ks(scheme::writeValue(key)); const string vs(scheme::writeValue(val)); const char* params[2] = { c_str(ks), c_str(vs) }; - PGresult* r = PQexecPrepared(pgsql.conn, "post", 2, params, NULL, NULL, 0); + PGresult* r = PQexecParams(pgsql.conn, c_str(string("insert into ") + pgsql.table + string(" values($1, $2);")), 2, NULL, params, NULL, NULL, 0); if (PQresultStatus(r) != PGRES_COMMAND_OK) return mkfailure<bool>(string("Couldn't execute insert postgresql SQL statement: ") + pgfailure(r, pgsql.conn)); PQclear(r); @@ -195,7 +164,7 @@ const failable<bool> put(const value& key, const value& val, const PGSql& pgsql) const string ks(scheme::writeValue(key)); const string vs(scheme::writeValue(val)); const char* params[2] = { c_str(ks), c_str(vs) }; - PGresult* r = PQexecPrepared(pgsql.conn, "put", 2, params, NULL, NULL, 0); + PGresult* r = PQexecParams(pgsql.conn, c_str(string("update ") + pgsql.table + string(" set ") + pgsql.vname + string(" = $2 where ") + pgsql.kname + string(" = $1;")), 2, NULL, params, NULL, NULL, 0); if (PQresultStatus(r) != PGRES_COMMAND_OK) return mkfailure<bool>(string("Couldn't execute update postgresql SQL statement: ") + pgfailure(r, pgsql.conn)); const string t = PQcmdTuples(r); @@ -206,7 +175,7 @@ const failable<bool> put(const value& key, const value& val, const PGSql& pgsql) } PQclear(r); - PGresult* pr = PQexecPrepared(pgsql.conn, "post", 2, params, NULL, NULL, 0); + PGresult* pr = PQexecParams(pgsql.conn, c_str(string("insert into ") + pgsql.table + string(" values($1, $2);")), 2, NULL, params, NULL, NULL, 0); if (PQresultStatus(pr) != PGRES_COMMAND_OK) return mkfailure<bool>(string("Couldn't execute insert postgresql SQL statement: ") + pgfailure(pr, pgsql.conn)); PQclear(pr); @@ -226,14 +195,14 @@ const failable<value> get(const value& key, const PGSql& pgsql) { const string ks(scheme::writeValue(key)); const char* params[1] = { c_str(ks) }; - PGresult* r = PQexecPrepared(pgsql.conn, "get", 1, params, NULL, NULL, 0); + PGresult* r = PQexecParams(pgsql.conn, c_str(string("select * from ") + pgsql.table + string(" where ") + pgsql.kname + string(" = $1;")), 1, NULL, params, NULL, NULL, 0); if (PQresultStatus(r) != PGRES_TUPLES_OK) return mkfailure<value>(string("Couldn't execute select postgresql SQL statement: ") + pgfailure(r, pgsql.conn)); if (PQntuples(r) < 1) { PQclear(r); ostringstream os; os << "Couldn't get postgresql entry: " << key; - return mkfailure<value>(str(os)); + return mkfailure<value>(str(os), 404, false); } const char* data = PQgetvalue(r, 0, 1); const value val(scheme::readValue(string(data))); @@ -254,7 +223,7 @@ const failable<bool> del(const value& key, const PGSql& pgsql) { const string ks(scheme::writeValue(key)); const char* params[1] = { c_str(ks) }; - PGresult* r = PQexecPrepared(pgsql.conn, "delete", 1, params, NULL, NULL, 0); + PGresult* r = PQexecParams(pgsql.conn, c_str(string("delete from ") + pgsql.table + string(" where ") + pgsql.kname + string(" = $1;")), 1, NULL, params, NULL, NULL, 0); if (PQresultStatus(r) != PGRES_COMMAND_OK) return mkfailure<bool>(string("Couldn't execute delete postgresql SQL statement: ") + pgfailure(r, pgsql.conn)); PQclear(r); diff --git a/sca-cpp/trunk/components/sqldb/sqldb.componentType b/sca-cpp/trunk/components/sqldb/sqldb.componentType index 5aa6d8e30f..bd024213bd 100644 --- a/sca-cpp/trunk/components/sqldb/sqldb.componentType +++ b/sca-cpp/trunk/components/sqldb/sqldb.componentType @@ -23,7 +23,7 @@ targetNamespace="http://tuscany.apache.org/xmlns/sca/components"> <service name="sqldb"/> - <property name="conninfo" type="xsd:string">host=localhost port=5432 dbname=db</property> + <property name="conninfo" type="xsd:string">host=localhost port=6432 dbname=db</property> <property name="table" type=xsd:string"/> </composite> diff --git a/sca-cpp/trunk/components/sqldb/sqldb.composite b/sca-cpp/trunk/components/sqldb/sqldb.composite index 19bafd8eca..9e102893b5 100644 --- a/sca-cpp/trunk/components/sqldb/sqldb.composite +++ b/sca-cpp/trunk/components/sqldb/sqldb.composite @@ -23,7 +23,7 @@ <component name="sqldb"> <implementation.cpp path="." library="libsqldb"/> - <property name="conninfo">host=localhost port=5432 dbname=db</property> + <property name="conninfo">host=localhost port=6432 dbname=db</property> <property name="table">test</property> <service name="sqldb"> <binding.http uri="sqldb"/> |