From 16f96409b9ad2a1451c88b4e0074b57686f02269 Mon Sep 17 00:00:00 2001 From: jsdelfino Date: Mon, 16 Aug 2010 06:15:24 +0000 Subject: Test Postgresql hot standby + replication and integrated Postgresql database in store-cluster sample. Add a front cache component which can be used to wire a cache component and a database component. git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@985799 13f79535-47bb-0310-9956-ffa450edef68 --- sca-cpp/trunk/components/cache/Makefile.am | 8 +- sca-cpp/trunk/components/cache/client-test.cpp | 20 +++- sca-cpp/trunk/components/cache/frontcache.cpp | 125 +++++++++++++++++++++ sca-cpp/trunk/components/cache/memcache.composite | 21 +++- sca-cpp/trunk/components/cache/memcache.cpp | 13 +-- sca-cpp/trunk/components/cache/memcache.hpp | 15 ++- sca-cpp/trunk/components/cache/server-test | 6 + sca-cpp/trunk/components/chat/xmpp.hpp | 12 +- sca-cpp/trunk/components/nosqldb/nosqldb.cpp | 13 +-- sca-cpp/trunk/components/nosqldb/tinycdb.hpp | 38 +++---- sca-cpp/trunk/components/sqldb/Makefile.am | 11 +- sca-cpp/trunk/components/sqldb/pgsql | 12 +- sca-cpp/trunk/components/sqldb/pgsql-backup | 41 +++++++ sca-cpp/trunk/components/sqldb/pgsql-conf | 105 +++++++++++++++++ sca-cpp/trunk/components/sqldb/pgsql-standby-conf | 122 ++++++++++++++++++++ sca-cpp/trunk/components/sqldb/pgsql-standby-test | Bin 0 -> 526293 bytes .../trunk/components/sqldb/pgsql-standby-test.cpp | 88 +++++++++++++++ sca-cpp/trunk/components/sqldb/pgsql-start | 12 +- sca-cpp/trunk/components/sqldb/pgsql-stop | 3 +- sca-cpp/trunk/components/sqldb/pgsql-test.cpp | 4 +- sca-cpp/trunk/components/sqldb/pgsql.hpp | 79 ++++++++----- sca-cpp/trunk/components/sqldb/server-test | 9 +- sca-cpp/trunk/components/sqldb/sqldb-test | 1 + sca-cpp/trunk/components/sqldb/sqldb.composite | 2 +- sca-cpp/trunk/components/sqldb/sqldb.cpp | 13 +-- sca-cpp/trunk/components/sqldb/standby-test | 39 +++++++ sca-cpp/trunk/kernel/list.hpp | 34 +++++- sca-cpp/trunk/kernel/value.hpp | 12 ++ sca-cpp/trunk/modules/http/httpd-conf | 1 + sca-cpp/trunk/modules/java/eval.hpp | 9 +- sca-cpp/trunk/modules/scheme/primitive.hpp | 8 +- sca-cpp/trunk/samples/store-cluster/Makefile.am | 2 +- .../store-cluster/domains/jane/store.composite | 37 +++++- .../store-cluster/domains/joe/store.composite | 37 +++++- .../trunk/samples/store-cluster/sqldb-master-conf | 35 ++++++ .../trunk/samples/store-cluster/sqldb-standby-conf | 28 +++++ sca-cpp/trunk/samples/store-cluster/ssl-stop | 3 + sca-cpp/trunk/samples/store-cluster/start | 12 +- sca-cpp/trunk/samples/store-cluster/stop | 7 ++ sca-cpp/trunk/samples/store-cpp/shopping-cart.cpp | 20 +--- sca-cpp/trunk/samples/store-sql/ssl-start | 3 + sca-cpp/trunk/samples/store-sql/start | 2 + sca-cpp/trunk/samples/store-sql/stop | 1 + sca-cpp/trunk/samples/store-sql/store.composite | 23 +++- 44 files changed, 912 insertions(+), 174 deletions(-) create mode 100644 sca-cpp/trunk/components/cache/frontcache.cpp create mode 100755 sca-cpp/trunk/components/sqldb/pgsql-backup create mode 100755 sca-cpp/trunk/components/sqldb/pgsql-conf create mode 100755 sca-cpp/trunk/components/sqldb/pgsql-standby-conf create mode 100755 sca-cpp/trunk/components/sqldb/pgsql-standby-test create mode 100644 sca-cpp/trunk/components/sqldb/pgsql-standby-test.cpp create mode 100755 sca-cpp/trunk/components/sqldb/standby-test create mode 100755 sca-cpp/trunk/samples/store-cluster/sqldb-master-conf create mode 100755 sca-cpp/trunk/samples/store-cluster/sqldb-standby-conf (limited to 'sca-cpp/trunk') diff --git a/sca-cpp/trunk/components/cache/Makefile.am b/sca-cpp/trunk/components/cache/Makefile.am index 580a5e4d84..96fb476fef 100644 --- a/sca-cpp/trunk/components/cache/Makefile.am +++ b/sca-cpp/trunk/components/cache/Makefile.am @@ -27,12 +27,18 @@ memcached.prefix: $(top_builddir)/config.status EXTRA_DIST = memcache.composite -comp_LTLIBRARIES = libmemcache.la +comp_LTLIBRARIES = libmemcache.la libfrontcache.la + libmemcache_la_SOURCES = memcache.cpp noinst_DATA = libmemcache.so libmemcache.so: ln -s .libs/libmemcache.so +libfrontcache_la_SOURCES = frontcache.cpp +noinst_DATA = libfrontcache.so +libfrontcache.so: + ln -s .libs/libfrontcache.so + memcache_test_SOURCES = memcache-test.cpp memcache_test_LDFLAGS = -lxml2 diff --git a/sca-cpp/trunk/components/cache/client-test.cpp b/sca-cpp/trunk/components/cache/client-test.cpp index 25bdb722f3..4f655c3d98 100644 --- a/sca-cpp/trunk/components/cache/client-test.cpp +++ b/sca-cpp/trunk/components/cache/client-test.cpp @@ -36,9 +36,10 @@ namespace tuscany { namespace cache { -const string uri("http://localhost:8090/memcache"); +const string memcacheuri("http://localhost:8090/memcache"); +const string frontcacheuri("http://localhost:8090/frontcache"); -bool testCache() { +bool testCache(const string& uri) { http::CURLSession cs; const list i = list() @@ -84,6 +85,14 @@ bool testCache() { return true; } +bool testMemcache() { + return testCache(memcacheuri); +} + +bool testFrontcache() { + return testCache(frontcacheuri); +} + struct getLoop { const string path; const value entry; @@ -91,7 +100,7 @@ struct getLoop { getLoop(const string& path, const value& entry, http::CURLSession cs) : path(path), entry(entry), cs(cs) { } const bool operator()() const { - const failable val = http::get(uri + path, cs); + const failable val = http::get(memcacheuri + path, cs); assert(hasContent(val)); assert(content(val) == entry); return true; @@ -105,7 +114,7 @@ bool testGetPerf() { const value a = mklist(string("item"), string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"), i); http::CURLSession cs; - const failable id = http::post(a, uri, cs); + const failable id = http::post(a, memcacheuri, cs); assert(hasContent(id)); const string p = path(content(id)); @@ -121,7 +130,8 @@ bool testGetPerf() { int main() { tuscany::cout << "Testing..." << tuscany::endl; - tuscany::cache::testCache(); + tuscany::cache::testMemcache(); + tuscany::cache::testFrontcache(); tuscany::cache::testGetPerf(); tuscany::cout << "OK" << tuscany::endl; diff --git a/sca-cpp/trunk/components/cache/frontcache.cpp b/sca-cpp/trunk/components/cache/frontcache.cpp new file mode 100644 index 0000000000..a9b18f0792 --- /dev/null +++ b/sca-cpp/trunk/components/cache/frontcache.cpp @@ -0,0 +1,125 @@ +/* + * 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$ */ + +/** + * A front cache component implementation which coordinates access to two + * levels of backend read/write caches or stores. Each cache or store is + * accessed through two references: a writer reference and a reader reference. + * + * This is useful if your level2 store is made of a master and slave + * replicated databases, you can then wire the writer reference to the master + * database and the reader reference to one your slave databases (assuming + * that the updates eventually get replicated to the slave database,in the + * meantime the updates will be retrieved from the level1 cache). + */ + +#include "string.hpp" +#include "function.hpp" +#include "list.hpp" +#include "value.hpp" +#include "monad.hpp" + +namespace tuscany { +namespace frontcache { + +/** + * Get an item from the cache. + */ +const failable get(const value& key, const lambda&)> rcache1, const lambda&)> wcache1, const lambda&)> rcache2, unused const lambda&)> wcache2) { + + // Lookup level1 cache + const value val1 = rcache1(mklist("get", key)); + if (!isNil(val1)) + return val1; + + // Lookup level2 cache + const value val2 = rcache2(mklist("get", key)); + if (isNil(val2)) + return mkfailure("Couldn't get cache entry"); + + // Update level1 cache + wcache1(mklist("put", key, val2)); + + return val2; +} + +/** + * Post an item to the cache. + */ +const failable post(const value& key, const value& val, unused const lambda&)> rcache1, const lambda&)> wcache1, unused const lambda&)> rcache2, const lambda&)> wcache2) { + const value id = append(key, mklist(mkuuid())); + + // Update level1 cache + wcache1(mklist("put", id, val)); + + // Update level2 cache + wcache2(mklist("put", id, val)); + + return id; +} + +/** + * Put an item into the cache. + */ +const failable put(const value& key, const value& val, unused const lambda&)> rcache1, const lambda&)> wcache1, unused const lambda&)> rcache2, const lambda&)> wcache2) { + + // Update level1 cache + wcache1(mklist("put", key, val)); + + // Update level2 cache + wcache2(mklist("put", key, val)); + + return value(true); +} + +/** + * Delete an item from the cache. + */ +const failable del(const value& key, unused const lambda&)> rcache1, const lambda&)> wcache1, unused const lambda&)> rcache2, const lambda&)> wcache2) { + + // Delete from level1 cache + wcache1(mklist("delete", key)); + + // Delete from level2 cache + wcache2(mklist("delete", key)); + + return value(true); +} + +} +} + +extern "C" { + +const tuscany::value apply(const tuscany::list& params) { + const tuscany::value func(car(params)); + if (func == "get") + return tuscany::frontcache::get(cadr(params), caddr(params), cadddr(params), caddddr(params), cadddddr(params)); + if (func == "post") + return tuscany::frontcache::post(cadr(params), caddr(params), cadddr(params), caddddr(params), cadddddr(params), caddddddr(params)); + if (func == "put") + return tuscany::frontcache::put(cadr(params), caddr(params), cadddr(params), caddddr(params), cadddddr(params), caddddddr(params)); + if (func == "delete") + return tuscany::frontcache::del(cadr(params), caddr(params), cadddr(params), caddddr(params), cadddddr(params)); + return tuscany::mkfailure(); +} + +} diff --git a/sca-cpp/trunk/components/cache/memcache.composite b/sca-cpp/trunk/components/cache/memcache.composite index 7c160172f0..4d546db410 100644 --- a/sca-cpp/trunk/components/cache/memcache.composite +++ b/sca-cpp/trunk/components/cache/memcache.composite @@ -28,6 +28,25 @@ localhost,localhost:11212,localhost:11213 - + + + + + + + + localhost:11411,localhost:11412,localhost:11413 + + + + + + + + + + + + diff --git a/sca-cpp/trunk/components/cache/memcache.cpp b/sca-cpp/trunk/components/cache/memcache.cpp index ec61ae9a92..4b62ce2e4c 100644 --- a/sca-cpp/trunk/components/cache/memcache.cpp +++ b/sca-cpp/trunk/components/cache/memcache.cpp @@ -23,10 +23,7 @@ * Memcached-based cache component implementation. */ -#include - #include "string.hpp" - #include "function.hpp" #include "list.hpp" #include "value.hpp" @@ -46,16 +43,8 @@ const failable get(const list& params, memcache::MemCached& ch) { /** * Post an item to the cache. */ -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 post(const list& params, memcache::MemCached& ch) { - const value id = append(car(params), mklist(uuidValue())); + const value id = append(car(params), mklist(mkuuid())); const failable val = memcache::post(id, cadr(params), ch); if (!hasContent(val)) return mkfailure(reason(val)); diff --git a/sca-cpp/trunk/components/cache/memcache.hpp b/sca-cpp/trunk/components/cache/memcache.hpp index 8749f845bf..1c71b220c7 100644 --- a/sca-cpp/trunk/components/cache/memcache.hpp +++ b/sca-cpp/trunk/components/cache/memcache.hpp @@ -91,10 +91,10 @@ private: apr_memcache_server_t *server; const apr_status_t sc = apr_memcache_server_create(pool, c_str(host), (apr_port_t)port, 1, 1, 1, 600, &server); if (sc != APR_SUCCESS) - return mkfailure("Could not create server"); + return mkfailure("Could not create memcached server"); const apr_status_t as = apr_memcache_add_server(mc, server); if (as != APR_SUCCESS) - return mkfailure("Could not add server"); + return mkfailure("Could not add memcached server"); return true; } @@ -131,7 +131,7 @@ const failable post(const value& key, const value& val, const MemCached& c const string vs(scheme::writeValue(val)); const apr_status_t rc = apr_memcache_add(cache.mc, nospaces(c_str(ks)), const_cast(c_str(vs)), length(vs), 0, 27); if (rc != APR_SUCCESS) - return mkfailure("Could not add entry"); + return mkfailure("Could not add memcached entry"); debug(true, "memcache::post::result"); return true; @@ -148,7 +148,7 @@ const failable put(const value& key, const value& val, const MemCached& ca const string vs(scheme::writeValue(val)); const apr_status_t rc = apr_memcache_set(cache.mc, nospaces(c_str(ks)), const_cast(c_str(vs)), length(vs), 0, 27); if (rc != APR_SUCCESS) - return mkfailure("Could not set entry"); + return mkfailure("Could not set memcached entry"); debug(true, "memcache::put::result"); return true; @@ -164,9 +164,8 @@ const failable get(const value& key, const MemCached& cache) { char *data; apr_size_t size; const apr_status_t rc = apr_memcache_getp(cache.mc, cache.pool, nospaces(c_str(ks)), &data, &size, NULL); - if (rc != APR_SUCCESS) { - return mkfailure("Could not get entry"); - } + if (rc != APR_SUCCESS) + return mkfailure("Could not get memcached entry"); const value val(scheme::readValue(string(data, size))); debug(val, "memcache::get::result"); @@ -182,7 +181,7 @@ const failable del(const value& key, const MemCached& cache) { const string ks(scheme::writeValue(key)); const apr_status_t rc = apr_memcache_delete(cache.mc, nospaces(c_str(ks)), 0); if (rc != APR_SUCCESS) - return mkfailure("Could not delete entry"); + return mkfailure("Could not delete memcached entry"); debug(true, "memcache::delete::result"); return true; diff --git a/sca-cpp/trunk/components/cache/server-test b/sca-cpp/trunk/components/cache/server-test index 598d4bce5b..a93a7e73ac 100755 --- a/sca-cpp/trunk/components/cache/server-test +++ b/sca-cpp/trunk/components/cache/server-test @@ -29,6 +29,9 @@ EOF ./memcached-start 11211 ./memcached-start 11212 ./memcached-start 11213 +./memcached-start 11411 +./memcached-start 11412 +./memcached-start 11413 ../../modules/http/httpd-start tmp sleep 2 @@ -41,5 +44,8 @@ rc=$? ./memcached-stop 11211 ./memcached-stop 11212 ./memcached-stop 11213 +./memcached-stop 11411 +./memcached-stop 11412 +./memcached-stop 11413 sleep 2 return $rc diff --git a/sca-cpp/trunk/components/chat/xmpp.hpp b/sca-cpp/trunk/components/chat/xmpp.hpp index 34ab13ed98..a921b9806d 100644 --- a/sca-cpp/trunk/components/chat/xmpp.hpp +++ b/sca-cpp/trunk/components/chat/xmpp.hpp @@ -26,8 +26,6 @@ * XMPP support functions. */ -#include - #include "strophe.h" extern "C" { #include "common.h" @@ -64,18 +62,10 @@ private: /** * Represents an XMPP client. */ -const string resourceUUID() { - apr_uuid_t uuid; - apr_uuid_get(&uuid); - char buf[APR_UUID_FORMATTED_LENGTH]; - apr_uuid_format(buf, &uuid); - return string(buf, APR_UUID_FORMATTED_LENGTH); -} - class XMPPClient { public: XMPPClient(const string& jid, const string& pass, bool owner = true) : owner(owner), ctx(xmpp_ctx_new(NULL, xmppRuntime.log)), conn(xmpp_conn_new(ctx)), connecting(false), connected(false), disconnecting(false) { - xmpp_conn_set_jid(conn, c_str(jid + "/" + resourceUUID())); + xmpp_conn_set_jid(conn, c_str(jid + "/" + mkuuid())); xmpp_conn_set_pass(conn, c_str(pass)); } diff --git a/sca-cpp/trunk/components/nosqldb/nosqldb.cpp b/sca-cpp/trunk/components/nosqldb/nosqldb.cpp index 638434c26f..cda3ca44a9 100644 --- a/sca-cpp/trunk/components/nosqldb/nosqldb.cpp +++ b/sca-cpp/trunk/components/nosqldb/nosqldb.cpp @@ -23,10 +23,7 @@ * TinyCDB-based database component implementation. */ -#include - #include "string.hpp" - #include "function.hpp" #include "list.hpp" #include "value.hpp" @@ -46,16 +43,8 @@ const failable get(const list& params, tinycdb::TinyCDB& cdb) { /** * 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 post(const list& params, tinycdb::TinyCDB& cdb) { - const value id = append(car(params), mklist(uuidValue())); + const value id = append(car(params), mklist(mkuuid())); const failable val = tinycdb::post(id, cadr(params), cdb); if (!hasContent(val)) return mkfailure(reason(val)); diff --git a/sca-cpp/trunk/components/nosqldb/tinycdb.hpp b/sca-cpp/trunk/components/nosqldb/tinycdb.hpp index 143b3da308..c98f2c38da 100644 --- a/sca-cpp/trunk/components/nosqldb/tinycdb.hpp +++ b/sca-cpp/trunk/components/nosqldb/tinycdb.hpp @@ -141,13 +141,13 @@ const failable cdbopen(TinyCDB& cdb) { struct stat st; const int s = stat(c_str(cdb.name), &st); if (s == -1) - return mkfailure(string("Couldn't read database stat ") + cdb.name); + return mkfailure(string("Couldn't tinycdb read database stat ") + cdb.name); // Open database for the first time if (cdb.fd == -1) { cdb.fd = open(c_str(cdb.name), O_RDONLY); if (cdb.fd == -1) - return mkfailure(string("Couldn't open database file ") + cdb.name); + return mkfailure(string("Couldn't open tinycdb database file ") + cdb.name); debug(cdb.fd, "tinycdb::open::fd"); cdb.st = st; return cdb.fd; @@ -162,7 +162,7 @@ const failable cdbopen(TinyCDB& cdb) { // Reopen database const int newfd = open(c_str(cdb.name), O_RDONLY); if (newfd == -1) - return mkfailure(string("Couldn't open database file ") + cdb.name); + return mkfailure(string("Couldn't open tinycdb database file ") + cdb.name); if (newfd == cdb.fd) { debug(cdb.fd, "tinycdb::open::fd"); cdb.st = st; @@ -171,7 +171,7 @@ const failable cdbopen(TinyCDB& cdb) { // We got a different fd, dup it to the current fd then close it if (fcntl(newfd, F_DUPFD, cdb.fd) == -1) - return mkfailure(string("Couldn't dup database file handle ") + cdb.name); + return mkfailure(string("Couldn't dup tinycdb database file handle ") + cdb.name); close(newfd); debug(cdb.fd, "tinycdb::open::fd"); @@ -212,9 +212,9 @@ const failable rewrite(const lambda(buffer& buf, const unsi // Read the db header unsigned int pos = 0; if (lseek(fd, 0, SEEK_SET) != 0) - return mkfailure("Could not seek to database start"); + return mkfailure("Could not seek to tinycdb database start"); if (::read(fd, buf, 2048) != 2048) - return mkfailure("Could not read database header"); + return mkfailure("Could not read tinycdb database header"); pos += 2048; unsigned int eod = cdb_unpack(buf); debug(pos, "tinycdb::rewrite::eod"); @@ -222,9 +222,9 @@ const failable rewrite(const lambda(buffer& buf, const unsi // Read and add the existing entries while(pos < eod) { if (eod - pos < 8) - return mkfailure("Invalid database format, couldn't read entry header"); + return mkfailure("Invalid tinycdb database format, couldn't read entry header"); if (::read(fd, buf, 8) != 8) - return mkfailure("Couldn't read entry header"); + return mkfailure("Couldn't read tinycdb entry header"); pos += 8; unsigned int klen = cdb_unpack(buf); unsigned int vlen = cdb_unpack(((unsigned char*)buf) + 4); @@ -233,9 +233,9 @@ const failable rewrite(const lambda(buffer& buf, const unsi // Read existing entry buf = mkbuffer(buf, elen); if (eod - pos < elen) - return mkfailure("Invalid database format, couldn't read entry"); + return mkfailure("Invalid tinycdb database format, couldn't read entry"); if ((unsigned int)::read(fd, buf, elen) != elen) - return mkfailure("Couldn't read entry"); + return mkfailure("Couldn't read tinycdb entry"); pos += elen; // Apply the update function to the entry @@ -251,10 +251,10 @@ const failable rewrite(const lambda(buffer& buf, const unsi // Add the entry to the new db if (cdb_make_add(&cdbm, buf, klen, ((unsigned char*)buf)+klen, vlen) == -1) - return mkfailure("Could not add entry"); + return mkfailure("Could not add tinycdb entry"); } if (pos != eod) - return mkfailure("Invalid database format"); + return mkfailure("Invalid tinycdb database format"); // Call the finish function const failable f = finish(cdbm); @@ -263,7 +263,7 @@ const failable rewrite(const lambda(buffer& buf, const unsi // Save the new db if (cdb_make_finish(&cdbm) == -1) - return mkfailure("Could not save database"); + return mkfailure("Could not save tinycdb database"); return true; } @@ -274,7 +274,7 @@ const failable rewrite(const lambda(buffer& buf, const unsi string tmpname = dbname(cdb) + ".XXXXXX"; int tmpfd = mkstemp(const_cast(c_str(tmpname))); if (tmpfd == -1) - return mkfailure("Could not create temporary database"); + return mkfailure("Could not create temporary tinycdb database"); // Rewrite the db, apply the update function to each entry buffer buf = mkbuffer(2048); @@ -287,7 +287,7 @@ const failable rewrite(const lambda(buffer& buf, const unsi // Atomically replace the db and reopen it in read mode if (rename(c_str(tmpname), c_str(dbname(cdb))) == -1) - return mkfailure("Could not rename temporary database"); + return mkfailure("Could not rename temporary tinycdb database"); cdbclose(cdb); failable ffd = cdbopen(cdb); if (!hasContent(ffd)) @@ -305,7 +305,7 @@ struct postUpdate { } const failable operator()(buffer& buf, const unsigned int klen, unused const unsigned int vlen) const { if (ks == string((char*)buf, klen)) - return mkfailure("Key already exists"); + return mkfailure("Key already exists in tinycdb database"); return true; } }; @@ -317,7 +317,7 @@ struct postFinish { } const failable operator()(struct cdb_make& cdbm) const { if (cdb_make_add(&cdbm, c_str(ks), length(ks), c_str(vs), length(vs)) == -1) - return mkfailure("Could not add entry"); + return mkfailure("Could not add tinycdb entry"); return true; } }; @@ -363,7 +363,7 @@ struct putFinish { } const failable operator()(struct cdb_make& cdbm) const { if (cdb_make_add(&cdbm, c_str(ks), length(ks), c_str(vs), length(vs)) == -1) - return mkfailure("Could not add entry"); + return mkfailure("Could not add tinycdb entry"); return true; } }; @@ -404,7 +404,7 @@ const failable get(const value& key, TinyCDB& cdb) { cdbi_t vlen; if (cdb_seek(fd, c_str(ks), length(ks), &vlen) <= 0) - return mkfailure("Could not get entry"); + return mkfailure("Could not get tinycdb entry"); char* data = gc_cnew(vlen + 1); cdb_bread(fd, data, vlen); data[vlen] = '\0'; 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 <>$root/sqldb/data/pg_hba.conf <>$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 <>$root/conf/httpd.conf <>$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 <$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 <>$root/conf/httpd.conf < +#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("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("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 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("a"); assert(hasContent(post(k, string("AAA"), pg))); @@ -59,7 +59,7 @@ struct getLoop { bool testGetPerf() { const value k = mklist("c"); - PGSql pg("dbname=db", "test"); + PGSql pg("host=localhost port=5432 dbname=db", "test"); assert(hasContent(post(k, string("CCC"), pg))); const lambda 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(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 setup(const PGSql& pgsql); friend const failable post(const value& key, const value& val, const PGSql& pgsql); friend const failable put(const value& key, const value& val, const PGSql& pgsql); friend const failable get(const value& key, const PGSql& pgsql); friend const failable del(const value& key, const PGSql& pgsql); /** - * Initialize the database connection + * Setup the database connection. */ - const failable init() { - conn = PQconnectdb(c_str(conninfo)); - if (PQstatus(conn) != CONNECTION_OK) - return mkfailure(string("Could not connect to database: ") + PQerrorMessage(conn)); + const failable 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(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(string("Could not execute column select statement: ") + pgfailure(kr)); + return mkfailure(string("Could not execute postgresql column select statement: ") + pgfailure(kr, conn)); if (PQntuples(kr) != 2) { PQclear(kr); - return mkfailure(string("Could not find table key and value column names")); + return mkfailure(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,31 +123,38 @@ 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(string("Could not prepare post SQL statement: ") + pgfailure(r)); + return mkfailure(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(string("Could not prepare put SQL statement: ") + pgfailure(r)); + return mkfailure(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(string("Could not prepare get SQL statement: ") + pgfailure(r)); + return mkfailure(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(string("Could not prepare delete SQL statement: ") + pgfailure(r)); + return mkfailure(string("Could not prepare delete postgresql SQL statement: ") + pgfailure(r, conn)); PQclear(r); } return true; } }; +/** + * Setup the database connection if necessary. + */ +const failable setup(const PGSql& pgsql) { + return pgsql.setup(false); +} + /** * Post a new item to the database. */ @@ -140,13 +163,14 @@ const failable 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(string("Could not execute post SQL statement: ") + pgfailure(r)); + return mkfailure(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 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(string("Could not execute put SQL statement: ") + pgfailure(r)); + return mkfailure(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 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(string("Could not execute post SQL statement: ") + pgfailure(pr)); + return mkfailure(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 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(string("Could not execute get SQL statement: ") + pgfailure(r)); + return mkfailure(string("Could not execute select postgresql SQL statement: ") + pgfailure(r, pgsql.conn)); if (PQntuples(r) < 1) { PQclear(r); - return mkfailure(string("Could not get entry: ") + PQerrorMessage(pgsql.conn)); + return mkfailure(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 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(string("Could not execute delete SQL statement: ") + pgfailure(r)); + return mkfailure(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 </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 @@ - dbname=db + host=localhost port=5432 dbname=db test 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 - #include "string.hpp" - #include "function.hpp" #include "list.hpp" #include "value.hpp" @@ -46,16 +43,8 @@ const failable get(const list& 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 post(const list& params, pgsql::PGSql& pg) { - const value id = append(car(params), mklist(uuidValue())); + const value id = append(car(params), mklist(mkuuid())); const failable val = pgsql::post(id, cadr(params), pg); if (!hasContent(val)) return mkfailure(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 diff --git a/sca-cpp/trunk/kernel/list.hpp b/sca-cpp/trunk/kernel/list.hpp index 84eba6d82f..db2f457317 100644 --- a/sca-cpp/trunk/kernel/list.hpp +++ b/sca-cpp/trunk/kernel/list.hpp @@ -313,26 +313,54 @@ template const list cdr(const list& p) { } /** - * Returns the car of the cdr of a list. + * Returns the car of the cdr (the 2nd element) of a list. */ template const T cadr(const list& p) { return car(cdr(p)); } /** - * Returns the car of the cdr of the cdr of a list. + * Returns the 3rd element of a list. */ template const T caddr(const list& p) { return car(cdr(cdr(p))); } /** - * Returns the car of the cdr of the cdr of the cdr of a list. + * Returns the 4th element of a list. */ template const T cadddr(const list& p) { return car(cdr(cdr(cdr(p)))); } +/** + * Returns the 5th element of a list. + */ +template const T caddddr(const list& p) { + return car(cdr(cdr(cdr(cdr(p))))); +} + +/** + * Returns the 6th element of a list. + */ +template const T cadddddr(const list& p) { + return car(cdr(cdr(cdr(cdr(cdr(p)))))); +} + +/** + * Returns the 7th element of a list. + */ +template const T caddddddr(const list& p) { + return car(cdr(cdr(cdr(cdr(cdr(cdr(p))))))); +} + +/** + * Returns the 8th element of a list. + */ +template const T cadddddddr(const list& p) { + return car(cdr(cdr(cdr(cdr(cdr(cdr(cdr(p)))))))); +} + /** * Returns the cdr of a cdr of a list. */ diff --git a/sca-cpp/trunk/kernel/value.hpp b/sca-cpp/trunk/kernel/value.hpp index 87d80a3e2a..24688648d2 100644 --- a/sca-cpp/trunk/kernel/value.hpp +++ b/sca-cpp/trunk/kernel/value.hpp @@ -27,6 +27,7 @@ */ #include +#include #include "string.hpp" #include "sstream.hpp" #include "gc.hpp" @@ -589,5 +590,16 @@ const value path(const list& p) { return string("/") + car(p) + path(cdr(p)); } +/** + * Make a uuid value. + */ +const value mkuuid() { + apr_uuid_t id; + apr_uuid_get(&id); + char buf[APR_UUID_FORMATTED_LENGTH]; + apr_uuid_format(buf, &id); + return value(string(buf, APR_UUID_FORMATTED_LENGTH)); +} + } #endif /* tuscany_value_hpp */ diff --git a/sca-cpp/trunk/modules/http/httpd-conf b/sca-cpp/trunk/modules/http/httpd-conf index 09d78351ff..9f698688b1 100755 --- a/sca-cpp/trunk/modules/http/httpd-conf +++ b/sca-cpp/trunk/modules/http/httpd-conf @@ -76,6 +76,7 @@ LoadModule setenvif_module ${modules_prefix}/modules/mod_setenvif.so LoadModule log_config_module ${modules_prefix}/modules/mod_log_config.so LoadModule vhost_alias_module ${modules_prefix}/modules/mod_vhost_alias.so +LoadModule cgi_module ${modules_prefix}/modules/mod_cgi.so LoadModule mod_tuscany_ssltunnel $here/libmod_tuscany_ssltunnel.so diff --git a/sca-cpp/trunk/modules/java/eval.hpp b/sca-cpp/trunk/modules/java/eval.hpp index a1cf6ae576..daf30d891b 100644 --- a/sca-cpp/trunk/modules/java/eval.hpp +++ b/sca-cpp/trunk/modules/java/eval.hpp @@ -26,7 +26,6 @@ * Java component implementation evaluation logic. */ #include -#include #include "list.hpp" #include "value.hpp" @@ -292,12 +291,8 @@ jobject JNICALL nativeInvoke(JNIEnv* env, jobject self, unused jobject proxy, jo * of this function as java.util.UUID seems to behave differently with different JDKs. */ jobject JNICALL nativeUUID(JNIEnv* env) { - apr_uuid_t uuid; - apr_uuid_get(&uuid); - char buf[APR_UUID_FORMATTED_LENGTH]; - apr_uuid_format(buf, &uuid); - string s(buf, APR_UUID_FORMATTED_LENGTH); - return env->NewStringUTF(c_str(s)); + const value uuid = mkuuid(); + return env->NewStringUTF(c_str(uuid)); } /** diff --git a/sca-cpp/trunk/modules/scheme/primitive.hpp b/sca-cpp/trunk/modules/scheme/primitive.hpp index fd5f3e9755..6f3f71f4cd 100644 --- a/sca-cpp/trunk/modules/scheme/primitive.hpp +++ b/sca-cpp/trunk/modules/scheme/primitive.hpp @@ -26,8 +26,6 @@ * Script evaluator primitive functions. */ -#include -#include #include "stream.hpp" #include "function.hpp" #include "list.hpp" @@ -144,11 +142,7 @@ const value logProc(const list& args) { } const value uuidProc(unused const list& args) { - apr_uuid_t uuid; - apr_uuid_get(&uuid); - char buf[APR_UUID_FORMATTED_LENGTH]; - apr_uuid_format(buf, &uuid); - return string(buf, APR_UUID_FORMATTED_LENGTH); + return mkuuid(); } const value cadrProc(unused const list& args) { diff --git a/sca-cpp/trunk/samples/store-cluster/Makefile.am b/sca-cpp/trunk/samples/store-cluster/Makefile.am index 0f933b34f3..2f18d95983 100644 --- a/sca-cpp/trunk/samples/store-cluster/Makefile.am +++ b/sca-cpp/trunk/samples/store-cluster/Makefile.am @@ -21,7 +21,7 @@ if WANT_OPENID if WANT_LOG if WANT_QUEUE -dist_sample_SCRIPTS = start stop ssl-start ssl-stop proxy-conf proxy-ssl-conf server-conf server-ssl-conf tunnel-ssl-conf +dist_sample_SCRIPTS = start stop ssl-start ssl-stop proxy-conf proxy-ssl-conf server-conf server-ssl-conf tunnel-ssl-conf sqldb-master-conf sqldb-standby-conf sampledir = $(prefix)/samples/store-cluster nobase_dist_sample_DATA = htdocs/*.html htdocs/domains/*/*.html domains/*/*.py domains/*/*.composite diff --git a/sca-cpp/trunk/samples/store-cluster/domains/jane/store.composite b/sca-cpp/trunk/samples/store-cluster/domains/jane/store.composite index 396970a6e6..85d6aa3a9b 100644 --- a/sca-cpp/trunk/samples/store-cluster/domains/jane/store.composite +++ b/sca-cpp/trunk/samples/store-cluster/domains/jane/store.composite @@ -58,15 +58,44 @@ - - + + - + + + + + + + + + + + + localhost:11211,localhost:11212,localhost:11213 - + + + + + host=localhost port=5432 dbname=db + store + + + + + + + + host=localhost port=5433 dbname=db + store + + + + diff --git a/sca-cpp/trunk/samples/store-cluster/domains/joe/store.composite b/sca-cpp/trunk/samples/store-cluster/domains/joe/store.composite index 396970a6e6..ca7815d573 100644 --- a/sca-cpp/trunk/samples/store-cluster/domains/joe/store.composite +++ b/sca-cpp/trunk/samples/store-cluster/domains/joe/store.composite @@ -58,15 +58,44 @@ - - + + - + + + + + + + + + + + + localhost:11211,localhost:11212,localhost:11213 - + + + + + host=localhost port=5432 dbname=db + store + + + + + + + + host=localhost port=5434 dbname=db + store + + + + diff --git a/sca-cpp/trunk/samples/store-cluster/sqldb-master-conf b/sca-cpp/trunk/samples/store-cluster/sqldb-master-conf new file mode 100755 index 0000000000..cd85f1e328 --- /dev/null +++ b/sca-cpp/trunk/samples/store-cluster/sqldb-master-conf @@ -0,0 +1,35 @@ +#!/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. + +root=$1 +port=$2 + +# Configure a database server +if [ ! -f $root/sqldb/data/postgresql.conf ]; then + create="true" +else + create="false" +fi +../../components/sqldb/pgsql-conf $root $port +if [ "$create" = "true" ]; then + ../../components/sqldb/pgsql-start $root + ../../components/sqldb/pgsql localhost $port "create table store(key text, value text);" 1>/dev/null 2>&1 + ../../components/sqldb/pgsql-stop $root +fi + diff --git a/sca-cpp/trunk/samples/store-cluster/sqldb-standby-conf b/sca-cpp/trunk/samples/store-cluster/sqldb-standby-conf new file mode 100755 index 0000000000..d1dec9930b --- /dev/null +++ b/sca-cpp/trunk/samples/store-cluster/sqldb-standby-conf @@ -0,0 +1,28 @@ +#!/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. + +root=$1 +mhost=$2 +mport=$3 +mhttpport=$4 +port=$5 + +# Configure a standby database server +../../components/sqldb/pgsql-standby-conf $root $mhost $mport $mhttpport $port + diff --git a/sca-cpp/trunk/samples/store-cluster/ssl-stop b/sca-cpp/trunk/samples/store-cluster/ssl-stop index 97af3d7faa..3c52c60399 100755 --- a/sca-cpp/trunk/samples/store-cluster/ssl-stop +++ b/sca-cpp/trunk/samples/store-cluster/ssl-stop @@ -20,9 +20,12 @@ ../../modules/http/httpd-stop tmp/server1 ../../modules/http/httpd-stop tmp/server2 ../../modules/http/httpd-stop tmp/server3 + ../../modules/http/httpd-stop tmp/proxy1 ../../modules/http/httpd-stop tmp/proxy2 + ../../components/cache/memcached-stop 127.0.0.1:11411 ../../components/cache/memcached-stop 127.0.0.1:11412 ../../components/cache/memcached-stop 127.0.0.1:11413 + ../../modules/http/httpd-stop tmp/tunnel1 diff --git a/sca-cpp/trunk/samples/store-cluster/start b/sca-cpp/trunk/samples/store-cluster/start index 4612ca2770..2b3afc320c 100755 --- a/sca-cpp/trunk/samples/store-cluster/start +++ b/sca-cpp/trunk/samples/store-cluster/start @@ -22,15 +22,25 @@ ../../components/cache/memcached-start 11212 ../../components/cache/memcached-start 11213 -# Start three app servers +# Start three app servers, with a master database and +# two hot standby databases ./server-conf tmp/server1 8101 +./sqldb-master-conf tmp/server1 5432 +../../components/sqldb/pgsql-start tmp/server1 ../../modules/http/httpd-start tmp/server1 +sleep 1 ./server-conf tmp/server2 8102 +./sqldb-standby-conf tmp/server2 localhost 5432 8101 5433 +../../components/sqldb/pgsql-start tmp/server2 ../../modules/http/httpd-start tmp/server2 +sleep 1 ./server-conf tmp/server3 8103 +./sqldb-standby-conf tmp/server3 localhost 5432 8101 5434 +../../components/sqldb/pgsql-start tmp/server3 ../../modules/http/httpd-start tmp/server3 +sleep 1 # Start two proxy balancers ./proxy-conf tmp/proxy1 8091 diff --git a/sca-cpp/trunk/samples/store-cluster/stop b/sca-cpp/trunk/samples/store-cluster/stop index 9df37dc948..d3d29f9cb2 100755 --- a/sca-cpp/trunk/samples/store-cluster/stop +++ b/sca-cpp/trunk/samples/store-cluster/stop @@ -17,11 +17,18 @@ # specific language governing permissions and limitations # under the License. +../../components/sqldb/pgsql-stop tmp/server2 +../../components/sqldb/pgsql-stop tmp/server3 +../../components/sqldb/pgsql-stop tmp/server1 + ../../modules/http/httpd-stop tmp/server1 ../../modules/http/httpd-stop tmp/server2 ../../modules/http/httpd-stop tmp/server3 + ../../modules/http/httpd-stop tmp/proxy1 ../../modules/http/httpd-stop tmp/proxy2 + ../../components/cache/memcached-stop 11211 ../../components/cache/memcached-stop 11212 ../../components/cache/memcached-stop 11213 + diff --git a/sca-cpp/trunk/samples/store-cpp/shopping-cart.cpp b/sca-cpp/trunk/samples/store-cpp/shopping-cart.cpp index 5cbbb2feff..3a1df44490 100644 --- a/sca-cpp/trunk/samples/store-cpp/shopping-cart.cpp +++ b/sca-cpp/trunk/samples/store-cpp/shopping-cart.cpp @@ -23,8 +23,6 @@ * Shopping cart component implementation. */ -#include -#include #include "string.hpp" #include "function.hpp" #include "list.hpp" @@ -42,27 +40,21 @@ const string cartId("1234"); */ const list getcart(const value& id, const lambda&)> cache) { const value cart = cache(mklist("get", mklist(id))); + cerr << "cart value: " << cart << "\n"; + const failable fcart = cart; + cerr << "cart fvalue: " << fcart << "\n"; + cerr << "cart content: " << content(fcart) << "\n"; + cerr << "cart reason: " << reason(fcart) << "\n"; if (isNil(cart)) return value(list()); return (list)cart; } -/** - * Returns a UUID. - */ -const value uuid() { - apr_uuid_t uuid; - apr_uuid_get(&uuid); - char buf[APR_UUID_FORMATTED_LENGTH]; - apr_uuid_format(buf, &uuid); - return string(buf, APR_UUID_FORMATTED_LENGTH); -} - /** * Post a new item to the cart. Create a new cart if necessary. */ const failable post(unused const list& collection, const value& item, const lambda&)> cache) { - const value id(uuid()); + const value id(mkuuid()); const list newItem(mklist(car(item), id, caddr(item))); const list cart(cons(newItem, getcart(cartId, cache))); cache(mklist("put", mklist(cartId), cart)); diff --git a/sca-cpp/trunk/samples/store-sql/ssl-start b/sca-cpp/trunk/samples/store-sql/ssl-start index 46e46dd32c..9263e16dfb 100755 --- a/sca-cpp/trunk/samples/store-sql/ssl-start +++ b/sca-cpp/trunk/samples/store-sql/ssl-start @@ -21,6 +21,7 @@ ../../modules/http/ssl-cert-conf tmp localhost ../../modules/http/httpd-conf tmp localhost 8090 htdocs ../../modules/http/httpd-ssl-conf tmp 8453 +../../modules/http/httpd-auth-conf tmp ../../modules/server/server-conf tmp ../../modules/server/scheme-conf tmp cat >>tmp/conf/httpd.conf </dev/null 2>&1 ../../modules/http/httpd-start tmp diff --git a/sca-cpp/trunk/samples/store-sql/start b/sca-cpp/trunk/samples/store-sql/start index 60f5a2d702..95881294d1 100755 --- a/sca-cpp/trunk/samples/store-sql/start +++ b/sca-cpp/trunk/samples/store-sql/start @@ -27,6 +27,8 @@ SCAComposite store.composite EOF +../../components/cache/memcached-start +../../components/sqldb/pgsql-conf tmp ../../components/sqldb/pgsql-start tmp ../../components/sqldb/pgsql "create table store(key text, value text);" 1>/dev/null 2>&1 ../../modules/http/httpd-start tmp diff --git a/sca-cpp/trunk/samples/store-sql/stop b/sca-cpp/trunk/samples/store-sql/stop index 603165ef46..2226018a3f 100755 --- a/sca-cpp/trunk/samples/store-sql/stop +++ b/sca-cpp/trunk/samples/store-sql/stop @@ -19,3 +19,4 @@ ../../modules/http/httpd-stop tmp ../../components/sqldb/pgsql-stop tmp +../../components/cache/memcached-stop diff --git a/sca-cpp/trunk/samples/store-sql/store.composite b/sca-cpp/trunk/samples/store-sql/store.composite index 501d465b03..18a77c2802 100644 --- a/sca-cpp/trunk/samples/store-sql/store.composite +++ b/sca-cpp/trunk/samples/store-sql/store.composite @@ -49,7 +49,7 @@ - + @@ -59,9 +59,28 @@ + + + + + + + + + + + + + + + + + localhost:11211 + + - dbname=db + host=localhost port=5432 dbname=db store -- cgit v1.2.3