diff options
Diffstat (limited to 'sca-cpp/trunk/components/sqldb')
-rw-r--r-- | sca-cpp/trunk/components/sqldb/Makefile.am | 11 | ||||
-rwxr-xr-x | sca-cpp/trunk/components/sqldb/pgsql | 12 | ||||
-rwxr-xr-x | sca-cpp/trunk/components/sqldb/pgsql-backup | 41 | ||||
-rwxr-xr-x | sca-cpp/trunk/components/sqldb/pgsql-conf | 105 | ||||
-rwxr-xr-x | sca-cpp/trunk/components/sqldb/pgsql-standby-conf | 122 | ||||
-rwxr-xr-x | sca-cpp/trunk/components/sqldb/pgsql-standby-test | bin | 0 -> 526293 bytes | |||
-rw-r--r-- | sca-cpp/trunk/components/sqldb/pgsql-standby-test.cpp | 88 | ||||
-rwxr-xr-x | sca-cpp/trunk/components/sqldb/pgsql-start | 12 | ||||
-rwxr-xr-x | sca-cpp/trunk/components/sqldb/pgsql-stop | 3 | ||||
-rw-r--r-- | sca-cpp/trunk/components/sqldb/pgsql-test.cpp | 4 | ||||
-rw-r--r-- | sca-cpp/trunk/components/sqldb/pgsql.hpp | 79 | ||||
-rwxr-xr-x | sca-cpp/trunk/components/sqldb/server-test | 9 | ||||
-rwxr-xr-x | sca-cpp/trunk/components/sqldb/sqldb-test | 1 | ||||
-rw-r--r-- | sca-cpp/trunk/components/sqldb/sqldb.composite | 2 | ||||
-rw-r--r-- | sca-cpp/trunk/components/sqldb/sqldb.cpp | 13 | ||||
-rwxr-xr-x | sca-cpp/trunk/components/sqldb/standby-test | 39 |
16 files changed, 479 insertions, 62 deletions
diff --git a/sca-cpp/trunk/components/sqldb/Makefile.am b/sca-cpp/trunk/components/sqldb/Makefile.am index e5c03f5190..7ed24e712c 100644 --- a/sca-cpp/trunk/components/sqldb/Makefile.am +++ b/sca-cpp/trunk/components/sqldb/Makefile.am @@ -22,7 +22,7 @@ INCLUDES = -I${PGSQL_INCLUDE} incl_HEADERS = *.hpp incldir = $(prefix)/include/components/sqldb -dist_comp_SCRIPTS = pgsql-start pgsql-stop pgsql +dist_comp_SCRIPTS = pgsql-conf pgsql-start pgsql-stop pgsql pgsql-standby-conf compdir=$(prefix)/components/sqldb comp_DATA = pgsql.prefix @@ -42,11 +42,14 @@ libsqldb.so: pgsql_test_SOURCES = pgsql-test.cpp pgsql_test_LDFLAGS = -L${PGSQL_LIB} -R${PGSQL_LIB} -lpq +pgsql_standby_test_SOURCES = pgsql-standby-test.cpp +pgsql_standby_test_LDFLAGS = -L${PGSQL_LIB} -R${PGSQL_LIB} -lpq + client_test_SOURCES = client-test.cpp client_test_LDFLAGS = -lxml2 -lcurl -lmozjs -dist_noinst_SCRIPTS = sqldb-test server-test -noinst_PROGRAMS = pgsql-test client-test -TESTS = sqldb-test server-test +dist_noinst_SCRIPTS = sqldb-test standby-test server-test +noinst_PROGRAMS = pgsql-test pgsql-standby-test client-test +TESTS = sqldb-test standby-test server-test endif diff --git a/sca-cpp/trunk/components/sqldb/pgsql b/sca-cpp/trunk/components/sqldb/pgsql index 3cd1904e32..dab30e642b 100755 --- a/sca-cpp/trunk/components/sqldb/pgsql +++ b/sca-cpp/trunk/components/sqldb/pgsql @@ -21,5 +21,15 @@ here=`readlink -f $0`; here=`dirname $here` pgsql_prefix=`cat $here/pgsql.prefix` -$pgsql_prefix/bin/psql -c "$1" db +if [ "$2" = "" ]; then + host="localhost" + port="5432" + cmd="$1" +else + host="$1" + port="$2" + cmd="$3" +fi + +$pgsql_prefix/bin/psql -h $host -p $port -c "$cmd" db diff --git a/sca-cpp/trunk/components/sqldb/pgsql-backup b/sca-cpp/trunk/components/sqldb/pgsql-backup new file mode 100755 index 0000000000..fad59236bf --- /dev/null +++ b/sca-cpp/trunk/components/sqldb/pgsql-backup @@ -0,0 +1,41 @@ +#!/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=`readlink -f $0`; here=`dirname $here` +root=`readlink -f $1` + +if [ "$2" = "" ]; then + host="localhost" + port="5432" +else + host="$2" + port="$3" +fi + +pgsql_prefix=`cat $here/pgsql.prefix` +$pgsql_prefix/bin/psql -h $host -p $port -c "SELECT pg_start_backup('backup', true)" db 1>>$root/logs/postgresql 2>&1 + +echo "Content-type: application/x-compressed" +echo + +tar -C $root/sqldb -cz data + +$pgsql_prefix/bin/psql -h $host -p $port -c "SELECT pg_stop_backup()" db 1>>$root/logs/postgresql 2>&1 + diff --git a/sca-cpp/trunk/components/sqldb/pgsql-conf b/sca-cpp/trunk/components/sqldb/pgsql-conf new file mode 100755 index 0000000000..f5cc2d23e3 --- /dev/null +++ b/sca-cpp/trunk/components/sqldb/pgsql-conf @@ -0,0 +1,105 @@ +#!/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. + +# Configure a postgresql master server +here=`readlink -f $0`; here=`dirname $here` +mkdir -p $1 +root=`readlink -f $1` + +addr=$2 +if [ "$addr" = "" ]; then + ip="*" + port="5432" +else + ip=`$here/../../modules/http/httpd-addr ip $addr` + if [ "$ip" = "" ]; then + ip="*" + fi + port=`$here/../../modules/http/httpd-addr port $addr` +fi + +pgsql_prefix=`cat $here/pgsql.prefix` +mkdir -p $root/sqldb/data +chmod 700 $root/sqldb/data +mkdir -p $root/sqldb/archive +mkdir -p $root/logs +if [ ! -f $root/sqldb/data/postgresql.conf ]; then + $pgsql_prefix/bin/pg_ctl init -D $root/sqldb/data 1>>$root/logs/postgresql 2>&1 + cp $root/sqldb/data/postgresql.conf $root/sqldb/data/postgresql-init.conf + cp $root/sqldb/data/pg_hba.conf $root/sqldb/data/pg_hba-init.conf +fi + +# Generate server configuration +cp $root/sqldb/data/postgresql-init.conf $root/sqldb/data/postgresql.conf +cat >>$root/sqldb/data/postgresql.conf <<EOF + +# Generated by: pgsql-conf $* + +# Listen +listen_addresses = '$ip' +port = $port + +# Setup archival +archive_mode = on +archive_command = 'cp %p $root/sqldb/archive/%f' + +# Setup hot standby with streaming replication +wal_level = hot_standby +max_wal_senders = 5 +wal_keep_segments = 32 + +EOF + +# Generate client auth configuration +cp $root/sqldb/data/pg_hba-init.conf $root/sqldb/data/pg_hba.conf +cat >>$root/sqldb/data/pg_hba.conf <<EOF + +# Generated by: pgsql-conf $* +# TYPE DATABASE USER CIDR-ADDRESS METHOD +host all all samenet trust +host replication all samenet trust + +EOF + +# Create the db +$pgsql_prefix/bin/pg_ctl start -w -D $root/sqldb/data -l $root/logs/postgresql 1>>$root/logs/postgresql 2>&1 +$pgsql_prefix/bin/createdb -h localhost -p $port db 1>>$root/logs/postgresql 2>&1 +$pgsql_prefix/bin/pg_ctl stop -w -D $root/sqldb/data 1>>$root/logs/postgresql 2>&1 + +# Generate database backup script +mkdir -p $root/sqldb/scripts +cat >$root/sqldb/scripts/backup <<EOF +#!/bin/sh +$here/pgsql-backup $root localhost $port +EOF +chmod 700 $root/sqldb/scripts/backup + +# Configure HTTPD to serve backup and archive files +if [ -f "$root/conf/httpd.conf" ]; then + cat >>$root/conf/httpd.conf <<EOF +# Generated by: pgsql-conf $* + +# Serve PostgreSQL backup and WAL archive files +ScriptAlias /pgsql-backup "$root/sqldb/scripts/backup" +Alias /pgsql-archive "$root/sqldb/archive" + +EOF + +fi + diff --git a/sca-cpp/trunk/components/sqldb/pgsql-standby-conf b/sca-cpp/trunk/components/sqldb/pgsql-standby-conf new file mode 100755 index 0000000000..3b4aa6dff5 --- /dev/null +++ b/sca-cpp/trunk/components/sqldb/pgsql-standby-conf @@ -0,0 +1,122 @@ +#!/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. + +# Configure a postgresql hot standby server +here=`readlink -f $0`; here=`dirname $here` +mkdir -p $1 +root=`readlink -f $1` + +# Master server address +if [ "$2" = "" ]; then + mhost="localhost" + mport="5432" + mhttpport="80" +else + mhost="$2" + mport="$3" + mhttpport="$4" +fi + +# Server address +addr=$5 +if [ "$addr" = "" ]; then + ip="*" + port="5432" +else + ip=`$here/../../modules/http/httpd-addr ip $addr` + if [ "$ip" = "" ]; then + ip="*" + fi + port=`$here/../../modules/http/httpd-addr port $addr` +fi + +pgsql_prefix=`cat $here/pgsql.prefix` +mkdir -p $root/sqldb/data +chmod 700 $root/sqldb/data +mkdir -p $root/sqldb/archive +mkdir -p $root/logs + +# Initialize from a backup of the master +if [ ! -f $root/sqldb/data/postgresql.conf ]; then + (wget http://$mhost:$mhttpport/pgsql-backup -O - | tar -C $root/sqldb -xz) 1>>$root/logs/postgresql 2>&1 + rm -rf $root/sqldb/data/postmaster.pid $root/sqldb/data/pg_xlog + mkdir -p $root/sqldb/data/pg_xlog/archive_status + chmod 700 $root/sqldb/data/pg_xlog/archive_status +fi + +# Generate server configuration +cp $root/sqldb/data/postgresql-init.conf $root/sqldb/data/postgresql.conf +cat >>$root/sqldb/data/postgresql.conf <<EOF + +# Generated by: standby-conf $* + +# Listen +listen_addresses = '$ip' +port = $port + +# Setup archival +archive_mode = on +archive_command = 'cp %p $root/sqldb/archive/%f' + +# Setup hot standby with streaming replication +wal_level = hot_standby +max_wal_senders = 5 +wal_keep_segments = 32 + +# Enable hot standby +hot_standby = on + +EOF + +# Generate recovery configuration +cat >$root/sqldb/data/recovery.conf << EOF +# Generated by: pgsql-slave-conf $* + +# Start in standby mode +standby_mode = 'on' +primary_conninfo = 'host=$mhost port=$mport' + +# Failover +trigger_file = '$root/sqldb/failover' + +restore_command = 'wget http://$mhost:$mhttpport/pgsql-archive/%f -O "%p"' + +EOF + +# Generate database backup script +mkdir -p $root/sqldb/scripts +cat >$root/sqldb/scripts/backup <<EOF +#!/bin/sh +$here/pgsql-backup $root localhost $port +EOF +chmod 700 $root/sqldb/scripts/backup + +# Configure HTTPD to serve backup and archive files +if [ -f "$root/conf/httpd.conf" ]; then + cat >>$root/conf/httpd.conf <<EOF +# Generated by: pgsql-conf $* + +# Serve PostgreSQL backup and WAL archive files +ScriptAlias /pgsql-backup "$root/sqldb/scripts/backup" +Alias /pgsql-archive "$root/sqldb/archive" + +EOF + +fi + diff --git a/sca-cpp/trunk/components/sqldb/pgsql-standby-test b/sca-cpp/trunk/components/sqldb/pgsql-standby-test Binary files differnew file mode 100755 index 0000000000..bf6b643c50 --- /dev/null +++ b/sca-cpp/trunk/components/sqldb/pgsql-standby-test diff --git a/sca-cpp/trunk/components/sqldb/pgsql-standby-test.cpp b/sca-cpp/trunk/components/sqldb/pgsql-standby-test.cpp new file mode 100644 index 0000000000..44f0a4a9e6 --- /dev/null +++ b/sca-cpp/trunk/components/sqldb/pgsql-standby-test.cpp @@ -0,0 +1,88 @@ +/* + * 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. + */ + +/* $Rev$ $Date$ */ + +/** + * Test PostgreSQL hot standby support. + */ + +#include <assert.h> +#include "stream.hpp" +#include "string.hpp" +#include "perf.hpp" +#include "pgsql.hpp" + +namespace tuscany { +namespace pgsql { + +bool testPGSql() { + PGSql wpg("host=localhost port=5432 dbname=db", "test"); + PGSql rpg("host=localhost port=5433 dbname=db", "test"); + const value k = mklist<value>("a"); + + assert(hasContent(post(k, string("AAA"), wpg))); + sleep(1); + assert((get(k, rpg)) == value(string("AAA"))); + assert(hasContent(put(k, string("aaa"), wpg))); + sleep(1); + assert((get(k, rpg)) == value(string("aaa"))); + assert(hasContent(del(k, wpg))); + sleep(1); + assert(!hasContent(get(k, rpg))); + + return true; +} + +struct getLoop { + const value k; + PGSql& pg; + getLoop(const value& k, PGSql& pg) : k(k), pg(pg) { + } + const bool operator()() const { + assert((get(k, pg)) == value(string("CCC"))); + return true; + } +}; + +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"); + assert(hasContent(post(k, string("CCC"), wpg))); + sleep(1); + + const lambda<bool()> gl = getLoop(k, rpg); + cout << "PGSql get test " << time(gl, 5, 200) << " ms" << endl; + return true; +} + +} +} + +int main() { + tuscany::cout << "Testing..." << tuscany::endl; + + tuscany::pgsql::testPGSql(); + tuscany::pgsql::testGetPerf(); + + tuscany::cout << "OK" << tuscany::endl; + + return 0; +} diff --git a/sca-cpp/trunk/components/sqldb/pgsql-start b/sca-cpp/trunk/components/sqldb/pgsql-start index f5c0f87614..3f03d0b4dc 100755 --- a/sca-cpp/trunk/components/sqldb/pgsql-start +++ b/sca-cpp/trunk/components/sqldb/pgsql-start @@ -24,14 +24,6 @@ root=`readlink -f $1` pgsql_prefix=`cat $here/pgsql.prefix` mkdir -p $root/sqldb mkdir -p $root/logs -if [ ! -f $root/sqldb/postgresql.conf ]; then - $pgsql_prefix/bin/pg_ctl init -D $root/sqldb 1>/dev/null 2>&1 - createdb="true" -fi - -$pgsql_prefix/bin/pg_ctl start -D $root/sqldb -l $root/logs/postgresql 1>/dev/null 2>&1 -sleep 2 -if [ "$createdb" = "true" ]; then - $pgsql_prefix/bin/createdb db 1>/dev/null 2>&1 -fi +$pgsql_prefix/bin/pg_ctl start -w -D $root/sqldb/data -l $root/logs/postgresql 1>>$root/logs/postgresql 2>&1 +sleep 1 diff --git a/sca-cpp/trunk/components/sqldb/pgsql-stop b/sca-cpp/trunk/components/sqldb/pgsql-stop index d0cda096ba..eefade47d2 100755 --- a/sca-cpp/trunk/components/sqldb/pgsql-stop +++ b/sca-cpp/trunk/components/sqldb/pgsql-stop @@ -22,7 +22,6 @@ here=`readlink -f $0`; here=`dirname $here` root=`readlink -f $1` pgsql_prefix=`cat $here/pgsql.prefix` -mkdir -p $root/sqldb mkdir -p $root/logs -$pgsql_prefix/bin/pg_ctl stop -D $root/sqldb 1>/dev/null 2>&1 +$pgsql_prefix/bin/pg_ctl stop -w -D $root/sqldb/data 1>>$root/logs/postgresql 2>&1 diff --git a/sca-cpp/trunk/components/sqldb/pgsql-test.cpp b/sca-cpp/trunk/components/sqldb/pgsql-test.cpp index 7fb6b0c814..1019667285 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("dbname=db", "test"); + PGSql pg("host=localhost port=5432 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("dbname=db", "test"); + PGSql pg("host=localhost port=5432 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 bb37d125b8..f4da8db220 100644 --- a/sca-cpp/trunk/components/sqldb/pgsql.hpp +++ b/sca-cpp/trunk/components/sqldb/pgsql.hpp @@ -40,10 +40,13 @@ namespace pgsql { /** * Return and clear a Postgres result failure. */ -const string pgfailure(PGresult* r) { - const string e = PQresultErrorMessage(r); +const string pgfailure(PGresult* r, PGconn* conn) { + const string re = PQresultErrorMessage(r); PQclear(r); - return e; + if (length(re) != 0) + return re; + const string ce = PQerrorMessage(conn); + return ce; } /** @@ -54,19 +57,23 @@ public: PGSql() : owner(false) { } - PGSql(const string& conninfo, const string& table) : owner(true), conninfo(conninfo), table(table) { - init(); + PGSql(const string& conninfo, const string& table) : owner(true), conn(NULL), conninfo(conninfo), table(table) { + conn = PQconnectdb(c_str(conninfo)); + if (PQstatus(conn) != CONNECTION_OK) { + mkfailure<bool>(string("Could not connect to postgresql database: ") + PQerrorMessage(conn)); + return; + } + setup(true); } - PGSql(const PGSql& c) : owner(false) { - conninfo = c.conninfo; - conn = c.conn; - table = c.table; + PGSql(const PGSql& c) : owner(false), conn(c.conn), conninfo(c.conninfo), table(c.table) { } ~PGSql() { if (!owner) return; + if (conn == NULL) + return; PQfinish(conn); } @@ -76,28 +83,37 @@ private: string conninfo; string table; + 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); /** - * Initialize the database connection + * Setup the database connection. */ - const failable<bool> init() { - conn = PQconnectdb(c_str(conninfo)); - if (PQstatus(conn) != CONNECTION_OK) - return mkfailure<bool>(string("Could not connect to database: ") + PQerrorMessage(conn)); + 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("Could not 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("Could not execute column select statement: ") + pgfailure(kr)); + return mkfailure<bool>(string("Could not execute postgresql column select statement: ") + pgfailure(kr, conn)); if (PQntuples(kr) != 2) { PQclear(kr); - return mkfailure<bool>(string("Could not find table key and value column names")); + return mkfailure<bool>(string("Could not find postgresql table key and value column names")); } const string kname = PQgetvalue(kr, 0, 0); const string vname = PQgetvalue(kr, 1, 0); @@ -107,25 +123,25 @@ private: { 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("Could not prepare post SQL statement: ") + pgfailure(r)); + return mkfailure<bool>(string("Could not 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("Could not prepare put SQL statement: ") + pgfailure(r)); + return mkfailure<bool>(string("Could not 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("Could not prepare get SQL statement: ") + pgfailure(r)); + return mkfailure<bool>(string("Could not 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("Could not prepare delete SQL statement: ") + pgfailure(r)); + return mkfailure<bool>(string("Could not prepare delete postgresql SQL statement: ") + pgfailure(r, conn)); PQclear(r); } return true; @@ -133,6 +149,13 @@ private: }; /** + * Setup the database connection if necessary. + */ +const failable<bool> setup(const PGSql& pgsql) { + return pgsql.setup(false); +} + +/** * Post a new item to the database. */ const failable<bool> post(const value& key, const value& val, const PGSql& pgsql) { @@ -140,13 +163,14 @@ const failable<bool> post(const value& key, const value& val, const PGSql& pgsql debug(val, "pgsql::post::value"); debug(pgsql.conninfo, "pgsql::post::conninfo"); debug(pgsql.table, "pgsql::post::table"); + setup(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); if (PQresultStatus(r) != PGRES_COMMAND_OK) - return mkfailure<bool>(string("Could not execute post SQL statement: ") + pgfailure(r)); + return mkfailure<bool>(string("Could not execute insert postgresql SQL statement: ") + pgfailure(r, pgsql.conn)); PQclear(r); debug(true, "pgsql::post::result"); @@ -161,13 +185,14 @@ const failable<bool> put(const value& key, const value& val, const PGSql& pgsql) debug(val, "pgsql::put::value"); debug(pgsql.conninfo, "pgsql::put::conninfo"); debug(pgsql.table, "pgsql::put::table"); + setup(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); if (PQresultStatus(r) != PGRES_COMMAND_OK) - return mkfailure<bool>(string("Could not execute put SQL statement: ") + pgfailure(r)); + return mkfailure<bool>(string("Could not execute update postgresql SQL statement: ") + pgfailure(r, pgsql.conn)); const string t = PQcmdTuples(r); if (t != "0") { PQclear(r); @@ -178,7 +203,7 @@ const failable<bool> put(const value& key, const value& val, const PGSql& pgsql) PGresult* pr = PQexecPrepared(pgsql.conn, "post", 2, params, NULL, NULL, 0); if (PQresultStatus(pr) != PGRES_COMMAND_OK) - return mkfailure<bool>(string("Could not execute post SQL statement: ") + pgfailure(pr)); + return mkfailure<bool>(string("Could not execute insert postgresql SQL statement: ") + pgfailure(pr, pgsql.conn)); PQclear(pr); debug(true, "pgsql::put::result"); @@ -192,15 +217,16 @@ const failable<value> get(const value& key, const PGSql& pgsql) { debug(key, "pgsql::get::key"); debug(pgsql.conninfo, "pgsql::get::conninfo"); debug(pgsql.table, "pgsql::get::table"); + setup(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); if (PQresultStatus(r) != PGRES_TUPLES_OK) - return mkfailure<value>(string("Could not execute get SQL statement: ") + pgfailure(r)); + return mkfailure<value>(string("Could not execute select postgresql SQL statement: ") + pgfailure(r, pgsql.conn)); if (PQntuples(r) < 1) { PQclear(r); - return mkfailure<value>(string("Could not get entry: ") + PQerrorMessage(pgsql.conn)); + return mkfailure<value>(string("Could not get postgresql entry: ") + PQerrorMessage(pgsql.conn)); } const char* data = PQgetvalue(r, 0, 1); const value val(scheme::readValue(string(data))); @@ -217,12 +243,13 @@ const failable<bool> del(const value& key, const PGSql& pgsql) { debug(key, "pgsql::delete::key"); debug(pgsql.conninfo, "pgsql::delete::conninfo"); debug(pgsql.table, "pgsql::delete::table"); + setup(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); if (PQresultStatus(r) != PGRES_COMMAND_OK) - return mkfailure<bool>(string("Could not execute delete SQL statement: ") + pgfailure(r)); + return mkfailure<bool>(string("Could not execute delete postgresql SQL statement: ") + pgfailure(r, pgsql.conn)); PQclear(r); debug(true, "pgsql::delete::result"); diff --git a/sca-cpp/trunk/components/sqldb/server-test b/sca-cpp/trunk/components/sqldb/server-test index 784c7156c5..c07d3b0510 100755 --- a/sca-cpp/trunk/components/sqldb/server-test +++ b/sca-cpp/trunk/components/sqldb/server-test @@ -19,6 +19,11 @@ # Setup ../../modules/http/httpd-conf tmp localhost 8090 ../../modules/http/htdocs +./pgsql-conf tmp +./pgsql-start tmp +./pgsql "drop table test;" 1>/dev/null 2>&1 +./pgsql "create table test(key text, value text);" 1>/dev/null 2>&1 + ../../modules/server/server-conf tmp ../../modules/server/scheme-conf tmp cat >>tmp/conf/httpd.conf <<EOF @@ -26,9 +31,6 @@ SCAContribution `pwd`/ SCAComposite sqldb.composite EOF -./pgsql-start tmp -./pgsql "drop table test;" 1>/dev/null 2>&1 -./pgsql "create table test(key text, value text);" 1>/dev/null 2>&1 ../../modules/http/httpd-start tmp sleep 2 @@ -39,5 +41,4 @@ rc=$? # Cleanup ../../modules/http/httpd-stop tmp ./pgsql-stop tmp -sleep 2 return $rc diff --git a/sca-cpp/trunk/components/sqldb/sqldb-test b/sca-cpp/trunk/components/sqldb/sqldb-test index 05fe413d50..e910ae0059 100755 --- a/sca-cpp/trunk/components/sqldb/sqldb-test +++ b/sca-cpp/trunk/components/sqldb/sqldb-test @@ -18,6 +18,7 @@ # under the License. # Setup +./pgsql-conf tmp ./pgsql-start tmp ./pgsql "drop table test;" 1>/dev/null 2>&1 ./pgsql "create table test(key text, value text);" 1>/dev/null 2>&1 diff --git a/sca-cpp/trunk/components/sqldb/sqldb.composite b/sca-cpp/trunk/components/sqldb/sqldb.composite index a27332e649..1511e66024 100644 --- a/sca-cpp/trunk/components/sqldb/sqldb.composite +++ b/sca-cpp/trunk/components/sqldb/sqldb.composite @@ -24,7 +24,7 @@ <component name="sqldb"> <implementation.cpp path="." library="libsqldb"/> - <property name="conninfo">dbname=db</property> + <property name="conninfo">host=localhost port=5432 dbname=db</property> <property name="table">test</property> <service name="sqldb"> <t:binding.http uri="sqldb"/> diff --git a/sca-cpp/trunk/components/sqldb/sqldb.cpp b/sca-cpp/trunk/components/sqldb/sqldb.cpp index e84a732511..0524b00bd2 100644 --- a/sca-cpp/trunk/components/sqldb/sqldb.cpp +++ b/sca-cpp/trunk/components/sqldb/sqldb.cpp @@ -23,10 +23,7 @@ * PostgreSQL-based database component implementation. */ -#include <apr_uuid.h> - #include "string.hpp" - #include "function.hpp" #include "list.hpp" #include "value.hpp" @@ -46,16 +43,8 @@ const failable<value> get(const list<value>& params, pgsql::PGSql& pg) { /** * Post an item to the database. */ -const value uuidValue() { - apr_uuid_t uuid; - apr_uuid_get(&uuid); - char buf[APR_UUID_FORMATTED_LENGTH]; - apr_uuid_format(buf, &uuid); - return value(string(buf, APR_UUID_FORMATTED_LENGTH)); -} - const failable<value> post(const list<value>& params, pgsql::PGSql& pg) { - const value id = append<value>(car(params), mklist(uuidValue())); + const value id = append<value>(car(params), mklist(mkuuid())); const failable<bool> val = pgsql::post(id, cadr(params), pg); if (!hasContent(val)) return mkfailure<value>(reason(val)); diff --git a/sca-cpp/trunk/components/sqldb/standby-test b/sca-cpp/trunk/components/sqldb/standby-test new file mode 100755 index 0000000000..e572de6fe2 --- /dev/null +++ b/sca-cpp/trunk/components/sqldb/standby-test @@ -0,0 +1,39 @@ +#!/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. + +# Setup +../../modules/http/httpd-conf tmp/master localhost 8090 tmp/master/htdocs +./pgsql-conf tmp/master 5432 +./pgsql-start tmp/master +./pgsql localhost 5432 "drop table test;" 1>/dev/null 2>&1 +./pgsql localhost 5432 "create table test(key text, value text);" 1>/dev/null 2>&1 +../../modules/http/httpd-start tmp/master +sleep 2 +./pgsql-standby-conf tmp/standby localhost 5432 8090 5433 +./pgsql-start tmp/standby + +# Test +./pgsql-standby-test 2>/dev/null +rc=$? + +# Cleanup +../../modules/http/httpd-stop tmp/master +./pgsql-stop tmp/standby +./pgsql-stop tmp/master +return $rc |