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
This commit is contained in:
parent
e351502e55
commit
16f96409b9
44 changed files with 912 additions and 174 deletions
8
sca-cpp/trunk/components/cache/Makefile.am
vendored
8
sca-cpp/trunk/components/cache/Makefile.am
vendored
|
|
@ -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
|
||||
|
||||
|
|
|
|||
20
sca-cpp/trunk/components/cache/client-test.cpp
vendored
20
sca-cpp/trunk/components/cache/client-test.cpp
vendored
|
|
@ -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<value> i = list<value>()
|
||||
|
|
@ -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<value> val = http::get(uri + path, cs);
|
||||
const failable<value> 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<value>(string("item"), string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"), i);
|
||||
|
||||
http::CURLSession cs;
|
||||
const failable<value> id = http::post(a, uri, cs);
|
||||
const failable<value> 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;
|
||||
|
|
|
|||
125
sca-cpp/trunk/components/cache/frontcache.cpp
vendored
Normal file
125
sca-cpp/trunk/components/cache/frontcache.cpp
vendored
Normal file
|
|
@ -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<value> get(const value& key, const lambda<value(const list<value>&)> rcache1, const lambda<value(const list<value>&)> wcache1, const lambda<value(const list<value>&)> rcache2, unused const lambda<value(const list<value>&)> wcache2) {
|
||||
|
||||
// Lookup level1 cache
|
||||
const value val1 = rcache1(mklist<value>("get", key));
|
||||
if (!isNil(val1))
|
||||
return val1;
|
||||
|
||||
// Lookup level2 cache
|
||||
const value val2 = rcache2(mklist<value>("get", key));
|
||||
if (isNil(val2))
|
||||
return mkfailure<value>("Couldn't get cache entry");
|
||||
|
||||
// Update level1 cache
|
||||
wcache1(mklist<value>("put", key, val2));
|
||||
|
||||
return val2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Post an item to the cache.
|
||||
*/
|
||||
const failable<value> post(const value& key, const value& val, unused const lambda<value(const list<value>&)> rcache1, const lambda<value(const list<value>&)> wcache1, unused const lambda<value(const list<value>&)> rcache2, const lambda<value(const list<value>&)> wcache2) {
|
||||
const value id = append<value>(key, mklist(mkuuid()));
|
||||
|
||||
// Update level1 cache
|
||||
wcache1(mklist<value>("put", id, val));
|
||||
|
||||
// Update level2 cache
|
||||
wcache2(mklist<value>("put", id, val));
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Put an item into the cache.
|
||||
*/
|
||||
const failable<value> put(const value& key, const value& val, unused const lambda<value(const list<value>&)> rcache1, const lambda<value(const list<value>&)> wcache1, unused const lambda<value(const list<value>&)> rcache2, const lambda<value(const list<value>&)> wcache2) {
|
||||
|
||||
// Update level1 cache
|
||||
wcache1(mklist<value>("put", key, val));
|
||||
|
||||
// Update level2 cache
|
||||
wcache2(mklist<value>("put", key, val));
|
||||
|
||||
return value(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete an item from the cache.
|
||||
*/
|
||||
const failable<value> del(const value& key, unused const lambda<value(const list<value>&)> rcache1, const lambda<value(const list<value>&)> wcache1, unused const lambda<value(const list<value>&)> rcache2, const lambda<value(const list<value>&)> wcache2) {
|
||||
|
||||
// Delete from level1 cache
|
||||
wcache1(mklist<value>("delete", key));
|
||||
|
||||
// Delete from level2 cache
|
||||
wcache2(mklist<value>("delete", key));
|
||||
|
||||
return value(true);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
const tuscany::value apply(const tuscany::list<tuscany::value>& 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<tuscany::value>();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -28,6 +28,25 @@
|
|||
<t:binding.http uri="memcache"/>
|
||||
</service>
|
||||
<property name="servers">localhost,localhost:11212,localhost:11213</property>
|
||||
</component>
|
||||
</component>
|
||||
|
||||
<component name="l2cache">
|
||||
<implementation.cpp path="." library="libmemcache"/>
|
||||
<service name="l2cache">
|
||||
<t:binding.http uri="l2cache"/>
|
||||
</service>
|
||||
<property name="servers">localhost:11411,localhost:11412,localhost:11413</property>
|
||||
</component>
|
||||
|
||||
<component name="frontcache">
|
||||
<implementation.cpp path="." library="libfrontcache"/>
|
||||
<service name="frontcache">
|
||||
<t:binding.http uri="frontcache"/>
|
||||
</service>
|
||||
<reference name="l1reader" target="memcache"/>
|
||||
<reference name="l1writer" target="memcache"/>
|
||||
<reference name="l2reader" target="l2cache"/>
|
||||
<reference name="l2writer" target="l2cache"/>
|
||||
</component>
|
||||
|
||||
</composite>
|
||||
|
|
|
|||
13
sca-cpp/trunk/components/cache/memcache.cpp
vendored
13
sca-cpp/trunk/components/cache/memcache.cpp
vendored
|
|
@ -23,10 +23,7 @@
|
|||
* Memcached-based cache 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, 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<value> post(const list<value>& params, memcache::MemCached& ch) {
|
||||
const value id = append<value>(car(params), mklist(uuidValue()));
|
||||
const value id = append<value>(car(params), mklist(mkuuid()));
|
||||
const failable<bool> val = memcache::post(id, cadr(params), ch);
|
||||
if (!hasContent(val))
|
||||
return mkfailure<value>(reason(val));
|
||||
|
|
|
|||
15
sca-cpp/trunk/components/cache/memcache.hpp
vendored
15
sca-cpp/trunk/components/cache/memcache.hpp
vendored
|
|
@ -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<bool>("Could not create server");
|
||||
return mkfailure<bool>("Could not create memcached server");
|
||||
const apr_status_t as = apr_memcache_add_server(mc, server);
|
||||
if (as != APR_SUCCESS)
|
||||
return mkfailure<bool>("Could not add server");
|
||||
return mkfailure<bool>("Could not add memcached server");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -131,7 +131,7 @@ const failable<bool> 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<char*>(c_str(vs)), length(vs), 0, 27);
|
||||
if (rc != APR_SUCCESS)
|
||||
return mkfailure<bool>("Could not add entry");
|
||||
return mkfailure<bool>("Could not add memcached entry");
|
||||
|
||||
debug(true, "memcache::post::result");
|
||||
return true;
|
||||
|
|
@ -148,7 +148,7 @@ const failable<bool> 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<char*>(c_str(vs)), length(vs), 0, 27);
|
||||
if (rc != APR_SUCCESS)
|
||||
return mkfailure<bool>("Could not set entry");
|
||||
return mkfailure<bool>("Could not set memcached entry");
|
||||
|
||||
debug(true, "memcache::put::result");
|
||||
return true;
|
||||
|
|
@ -164,9 +164,8 @@ const failable<value> 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<value>("Could not get entry");
|
||||
}
|
||||
if (rc != APR_SUCCESS)
|
||||
return mkfailure<value>("Could not get memcached entry");
|
||||
const value val(scheme::readValue(string(data, size)));
|
||||
|
||||
debug(val, "memcache::get::result");
|
||||
|
|
@ -182,7 +181,7 @@ const failable<bool> 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<bool>("Could not delete entry");
|
||||
return mkfailure<bool>("Could not delete memcached entry");
|
||||
|
||||
debug(true, "memcache::delete::result");
|
||||
return true;
|
||||
|
|
|
|||
6
sca-cpp/trunk/components/cache/server-test
vendored
6
sca-cpp/trunk/components/cache/server-test
vendored
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -26,8 +26,6 @@
|
|||
* XMPP support functions.
|
||||
*/
|
||||
|
||||
#include <apr_uuid.h>
|
||||
|
||||
#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));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,10 +23,7 @@
|
|||
* TinyCDB-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, 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<value> post(const list<value>& params, tinycdb::TinyCDB& cdb) {
|
||||
const value id = append<value>(car(params), mklist(uuidValue()));
|
||||
const value id = append<value>(car(params), mklist(mkuuid()));
|
||||
const failable<bool> val = tinycdb::post(id, cadr(params), cdb);
|
||||
if (!hasContent(val))
|
||||
return mkfailure<value>(reason(val));
|
||||
|
|
|
|||
|
|
@ -141,13 +141,13 @@ const failable<int> cdbopen(TinyCDB& cdb) {
|
|||
struct stat st;
|
||||
const int s = stat(c_str(cdb.name), &st);
|
||||
if (s == -1)
|
||||
return mkfailure<int>(string("Couldn't read database stat ") + cdb.name);
|
||||
return mkfailure<int>(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<int>(string("Couldn't open database file ") + cdb.name);
|
||||
return mkfailure<int>(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<int> cdbopen(TinyCDB& cdb) {
|
|||
// Reopen database
|
||||
const int newfd = open(c_str(cdb.name), O_RDONLY);
|
||||
if (newfd == -1)
|
||||
return mkfailure<int>(string("Couldn't open database file ") + cdb.name);
|
||||
return mkfailure<int>(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<int> 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<int>(string("Couldn't dup database file handle ") + cdb.name);
|
||||
return mkfailure<int>(string("Couldn't dup tinycdb database file handle ") + cdb.name);
|
||||
close(newfd);
|
||||
|
||||
debug(cdb.fd, "tinycdb::open::fd");
|
||||
|
|
@ -212,9 +212,9 @@ const failable<bool> rewrite(const lambda<failable<bool>(buffer& buf, const unsi
|
|||
// Read the db header
|
||||
unsigned int pos = 0;
|
||||
if (lseek(fd, 0, SEEK_SET) != 0)
|
||||
return mkfailure<bool>("Could not seek to database start");
|
||||
return mkfailure<bool>("Could not seek to tinycdb database start");
|
||||
if (::read(fd, buf, 2048) != 2048)
|
||||
return mkfailure<bool>("Could not read database header");
|
||||
return mkfailure<bool>("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<bool> rewrite(const lambda<failable<bool>(buffer& buf, const unsi
|
|||
// Read and add the existing entries
|
||||
while(pos < eod) {
|
||||
if (eod - pos < 8)
|
||||
return mkfailure<bool>("Invalid database format, couldn't read entry header");
|
||||
return mkfailure<bool>("Invalid tinycdb database format, couldn't read entry header");
|
||||
if (::read(fd, buf, 8) != 8)
|
||||
return mkfailure<bool>("Couldn't read entry header");
|
||||
return mkfailure<bool>("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<bool> rewrite(const lambda<failable<bool>(buffer& buf, const unsi
|
|||
// Read existing entry
|
||||
buf = mkbuffer(buf, elen);
|
||||
if (eod - pos < elen)
|
||||
return mkfailure<bool>("Invalid database format, couldn't read entry");
|
||||
return mkfailure<bool>("Invalid tinycdb database format, couldn't read entry");
|
||||
if ((unsigned int)::read(fd, buf, elen) != elen)
|
||||
return mkfailure<bool>("Couldn't read entry");
|
||||
return mkfailure<bool>("Couldn't read tinycdb entry");
|
||||
pos += elen;
|
||||
|
||||
// Apply the update function to the entry
|
||||
|
|
@ -251,10 +251,10 @@ const failable<bool> rewrite(const lambda<failable<bool>(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<bool>("Could not add entry");
|
||||
return mkfailure<bool>("Could not add tinycdb entry");
|
||||
}
|
||||
if (pos != eod)
|
||||
return mkfailure<bool>("Invalid database format");
|
||||
return mkfailure<bool>("Invalid tinycdb database format");
|
||||
|
||||
// Call the finish function
|
||||
const failable<bool> f = finish(cdbm);
|
||||
|
|
@ -263,7 +263,7 @@ const failable<bool> rewrite(const lambda<failable<bool>(buffer& buf, const unsi
|
|||
|
||||
// Save the new db
|
||||
if (cdb_make_finish(&cdbm) == -1)
|
||||
return mkfailure<bool>("Could not save database");
|
||||
return mkfailure<bool>("Could not save tinycdb database");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -274,7 +274,7 @@ const failable<bool> rewrite(const lambda<failable<bool>(buffer& buf, const unsi
|
|||
string tmpname = dbname(cdb) + ".XXXXXX";
|
||||
int tmpfd = mkstemp(const_cast<char*>(c_str(tmpname)));
|
||||
if (tmpfd == -1)
|
||||
return mkfailure<bool>("Could not create temporary database");
|
||||
return mkfailure<bool>("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<bool> rewrite(const lambda<failable<bool>(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<bool>("Could not rename temporary database");
|
||||
return mkfailure<bool>("Could not rename temporary tinycdb database");
|
||||
cdbclose(cdb);
|
||||
failable<int> ffd = cdbopen(cdb);
|
||||
if (!hasContent(ffd))
|
||||
|
|
@ -305,7 +305,7 @@ struct postUpdate {
|
|||
}
|
||||
const failable<bool> operator()(buffer& buf, const unsigned int klen, unused const unsigned int vlen) const {
|
||||
if (ks == string((char*)buf, klen))
|
||||
return mkfailure<bool>("Key already exists");
|
||||
return mkfailure<bool>("Key already exists in tinycdb database");
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
|
@ -317,7 +317,7 @@ struct postFinish {
|
|||
}
|
||||
const failable<bool> operator()(struct cdb_make& cdbm) const {
|
||||
if (cdb_make_add(&cdbm, c_str(ks), length(ks), c_str(vs), length(vs)) == -1)
|
||||
return mkfailure<bool>("Could not add entry");
|
||||
return mkfailure<bool>("Could not add tinycdb entry");
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
|
@ -363,7 +363,7 @@ struct putFinish {
|
|||
}
|
||||
const failable<bool> operator()(struct cdb_make& cdbm) const {
|
||||
if (cdb_make_add(&cdbm, c_str(ks), length(ks), c_str(vs), length(vs)) == -1)
|
||||
return mkfailure<bool>("Could not add entry");
|
||||
return mkfailure<bool>("Could not add tinycdb entry");
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
|
@ -404,7 +404,7 @@ const failable<value> get(const value& key, TinyCDB& cdb) {
|
|||
|
||||
cdbi_t vlen;
|
||||
if (cdb_seek(fd, c_str(ks), length(ks), &vlen) <= 0)
|
||||
return mkfailure<value>("Could not get entry");
|
||||
return mkfailure<value>("Could not get tinycdb entry");
|
||||
char* data = gc_cnew(vlen + 1);
|
||||
cdb_bread(fd, data, vlen);
|
||||
data[vlen] = '\0';
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
41
sca-cpp/trunk/components/sqldb/pgsql-backup
Executable file
41
sca-cpp/trunk/components/sqldb/pgsql-backup
Executable file
|
|
@ -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
|
||||
|
||||
105
sca-cpp/trunk/components/sqldb/pgsql-conf
Executable file
105
sca-cpp/trunk/components/sqldb/pgsql-conf
Executable file
|
|
@ -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
|
||||
|
||||
122
sca-cpp/trunk/components/sqldb/pgsql-standby-conf
Executable file
122
sca-cpp/trunk/components/sqldb/pgsql-standby-conf
Executable file
|
|
@ -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
|
||||
|
||||
BIN
sca-cpp/trunk/components/sqldb/pgsql-standby-test
Executable file
BIN
sca-cpp/trunk/components/sqldb/pgsql-standby-test
Executable file
Binary file not shown.
88
sca-cpp/trunk/components/sqldb/pgsql-standby-test.cpp
Normal file
88
sca-cpp/trunk/components/sqldb/pgsql-standby-test.cpp
Normal file
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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,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<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;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Setup the database connection if necessary.
|
||||
*/
|
||||
const failable<bool> setup(const PGSql& pgsql) {
|
||||
return pgsql.setup(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Post a new item to the database.
|
||||
*/
|
||||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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"/>
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
39
sca-cpp/trunk/components/sqldb/standby-test
Executable file
39
sca-cpp/trunk/components/sqldb/standby-test
Executable file
|
|
@ -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
|
||||
|
|
@ -313,26 +313,54 @@ template<typename T> const list<T> cdr(const list<T>& p) {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns the car of the cdr of a list.
|
||||
* Returns the car of the cdr (the 2nd element) of a list.
|
||||
*/
|
||||
template<typename T> const T cadr(const list<T>& 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<typename T> const T caddr(const list<T>& 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<typename T> const T cadddr(const list<T>& p) {
|
||||
return car(cdr(cdr(cdr(p))));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the 5th element of a list.
|
||||
*/
|
||||
template<typename T> const T caddddr(const list<T>& p) {
|
||||
return car(cdr(cdr(cdr(cdr(p)))));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the 6th element of a list.
|
||||
*/
|
||||
template<typename T> const T cadddddr(const list<T>& p) {
|
||||
return car(cdr(cdr(cdr(cdr(cdr(p))))));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the 7th element of a list.
|
||||
*/
|
||||
template<typename T> const T caddddddr(const list<T>& p) {
|
||||
return car(cdr(cdr(cdr(cdr(cdr(cdr(p)))))));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the 8th element of a list.
|
||||
*/
|
||||
template<typename T> const T cadddddddr(const list<T>& p) {
|
||||
return car(cdr(cdr(cdr(cdr(cdr(cdr(cdr(p))))))));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the cdr of a cdr of a list.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <apr_uuid.h>
|
||||
#include "string.hpp"
|
||||
#include "sstream.hpp"
|
||||
#include "gc.hpp"
|
||||
|
|
@ -589,5 +590,16 @@ const value path(const list<value>& 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 */
|
||||
|
|
|
|||
|
|
@ -76,6 +76,7 @@ LoadModule setenvif_module ${modules_prefix}/modules/mod_setenvif.so
|
|||
LoadModule log_config_module ${modules_prefix}/modules/mod_log_config.so
|
||||
</IfModule>
|
||||
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
|
||||
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@
|
|||
* Java component implementation evaluation logic.
|
||||
*/
|
||||
#include <jni.h>
|
||||
#include <apr_uuid.h>
|
||||
|
||||
#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));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -26,8 +26,6 @@
|
|||
* Script evaluator primitive functions.
|
||||
*/
|
||||
|
||||
#include <apr_general.h>
|
||||
#include <apr_uuid.h>
|
||||
#include "stream.hpp"
|
||||
#include "function.hpp"
|
||||
#include "list.hpp"
|
||||
|
|
@ -144,11 +142,7 @@ const value logProc(const list<value>& args) {
|
|||
}
|
||||
|
||||
const value uuidProc(unused const list<value>& 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<value>& args) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -58,15 +58,44 @@
|
|||
<t:implementation.python script="currency-converter.py"/>
|
||||
<service name="CurrencyConverter">
|
||||
<t:binding.jsonrpc uri="currencyConverter"/>
|
||||
</service>
|
||||
</component>
|
||||
</service>
|
||||
</component>
|
||||
|
||||
<component name="Cache">
|
||||
<implementation.cpp path="../../../../components/cache" library="libmemcache"/>
|
||||
<implementation.cpp path="../../../../components/cache" library="libfrontcache"/>
|
||||
<service name="Cache">
|
||||
<t:binding.atom uri="cache"/>
|
||||
</service>
|
||||
<reference name="l1reader" target="Memcache"/>
|
||||
<reference name="l1writer" target="Memcache"/>
|
||||
<reference name="l2reader" target="Standbydb"/>
|
||||
<reference name="l2writer" target="Masterdb"/>
|
||||
</component>
|
||||
|
||||
<component name="Memcache">
|
||||
<implementation.cpp path="../../../../components/cache" library="libmemcache"/>
|
||||
<service name="Memcache">
|
||||
<t:binding.atom uri="memcache"/>
|
||||
</service>
|
||||
<property name="servers">localhost:11211,localhost:11212,localhost:11213</property>
|
||||
</component>
|
||||
</component>
|
||||
|
||||
<component name="Masterdb">
|
||||
<implementation.cpp path="../../../../components/sqldb" library="libsqldb"/>
|
||||
<property name="conninfo">host=localhost port=5432 dbname=db</property>
|
||||
<property name="table">store</property>
|
||||
<service name="Masterdb">
|
||||
<t:binding.atom uri="masterdb"/>
|
||||
</service>
|
||||
</component>
|
||||
|
||||
<component name="Standbydb">
|
||||
<implementation.cpp path="../../../../components/sqldb" library="libsqldb"/>
|
||||
<property name="conninfo">host=localhost port=5433 dbname=db</property>
|
||||
<property name="table">store</property>
|
||||
<service name="Standbydb">
|
||||
<t:binding.atom uri="standbydb"/>
|
||||
</service>
|
||||
</component>
|
||||
|
||||
</composite>
|
||||
|
|
|
|||
|
|
@ -58,15 +58,44 @@
|
|||
<t:implementation.python script="currency-converter.py"/>
|
||||
<service name="CurrencyConverter">
|
||||
<t:binding.jsonrpc uri="currencyConverter"/>
|
||||
</service>
|
||||
</component>
|
||||
</service>
|
||||
</component>
|
||||
|
||||
<component name="Cache">
|
||||
<implementation.cpp path="../../../../components/cache" library="libmemcache"/>
|
||||
<implementation.cpp path="../../../../components/cache" library="libfrontcache"/>
|
||||
<service name="Cache">
|
||||
<t:binding.atom uri="cache"/>
|
||||
</service>
|
||||
<reference name="l1reader" target="Memcache"/>
|
||||
<reference name="l1writer" target="Memcache"/>
|
||||
<reference name="l2reader" target="Standbydb"/>
|
||||
<reference name="l2writer" target="Masterdb"/>
|
||||
</component>
|
||||
|
||||
<component name="Memcache">
|
||||
<implementation.cpp path="../../../../components/cache" library="libmemcache"/>
|
||||
<service name="Memcache">
|
||||
<t:binding.atom uri="memcache"/>
|
||||
</service>
|
||||
<property name="servers">localhost:11211,localhost:11212,localhost:11213</property>
|
||||
</component>
|
||||
</component>
|
||||
|
||||
<component name="Masterdb">
|
||||
<implementation.cpp path="../../../../components/sqldb" library="libsqldb"/>
|
||||
<property name="conninfo">host=localhost port=5432 dbname=db</property>
|
||||
<property name="table">store</property>
|
||||
<service name="Masterdb">
|
||||
<t:binding.atom uri="masterdb"/>
|
||||
</service>
|
||||
</component>
|
||||
|
||||
<component name="Standbydb">
|
||||
<implementation.cpp path="../../../../components/sqldb" library="libsqldb"/>
|
||||
<property name="conninfo">host=localhost port=5434 dbname=db</property>
|
||||
<property name="table">store</property>
|
||||
<service name="Standbydb">
|
||||
<t:binding.atom uri="standbydb"/>
|
||||
</service>
|
||||
</component>
|
||||
|
||||
</composite>
|
||||
|
|
|
|||
35
sca-cpp/trunk/samples/store-cluster/sqldb-master-conf
Executable file
35
sca-cpp/trunk/samples/store-cluster/sqldb-master-conf
Executable file
|
|
@ -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
|
||||
|
||||
28
sca-cpp/trunk/samples/store-cluster/sqldb-standby-conf
Executable file
28
sca-cpp/trunk/samples/store-cluster/sqldb-standby-conf
Executable file
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -23,8 +23,6 @@
|
|||
* Shopping cart component implementation.
|
||||
*/
|
||||
|
||||
#include <apr_general.h>
|
||||
#include <apr_uuid.h>
|
||||
#include "string.hpp"
|
||||
#include "function.hpp"
|
||||
#include "list.hpp"
|
||||
|
|
@ -42,27 +40,21 @@ const string cartId("1234");
|
|||
*/
|
||||
const list<value> getcart(const value& id, const lambda<value(const list<value>&)> cache) {
|
||||
const value cart = cache(mklist<value>("get", mklist<value>(id)));
|
||||
cerr << "cart value: " << cart << "\n";
|
||||
const failable<value> 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<value>());
|
||||
return (list<value>)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<value> post(unused const list<value>& collection, const value& item, const lambda<value(const list<value>&)> cache) {
|
||||
const value id(uuid());
|
||||
const value id(mkuuid());
|
||||
const list<value> newItem(mklist<value>(car<value>(item), id, caddr<value>(item)));
|
||||
const list<value> cart(cons<value>(newItem, getcart(cartId, cache)));
|
||||
cache(mklist<value>("put", mklist<value>(cartId), cart));
|
||||
|
|
|
|||
|
|
@ -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 <<EOF
|
||||
|
|
@ -30,6 +31,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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -19,3 +19,4 @@
|
|||
|
||||
../../modules/http/httpd-stop tmp
|
||||
../../components/sqldb/pgsql-stop tmp
|
||||
../../components/cache/memcached-stop
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@
|
|||
<service name="Total">
|
||||
<t:binding.jsonrpc uri="total"/>
|
||||
</service>
|
||||
<reference name="cache" target="Sqldb"/>
|
||||
<reference name="cache" target="Cache"/>
|
||||
</component>
|
||||
|
||||
<component name="CurrencyConverter">
|
||||
|
|
@ -59,9 +59,28 @@
|
|||
</service>
|
||||
</component>
|
||||
|
||||
<component name="Cache">
|
||||
<implementation.cpp path="../../components/cache" library="libfrontcache"/>
|
||||
<service name="Cache">
|
||||
<t:binding.atom uri="cache"/>
|
||||
</service>
|
||||
<reference name="l1reader" target="Memcache"/>
|
||||
<reference name="l1writer" target="Memcache"/>
|
||||
<reference name="l2reader" target="Sqldb"/>
|
||||
<reference name="l2writer" target="Sqldb"/>
|
||||
</component>
|
||||
|
||||
<component name="Memcache">
|
||||
<implementation.cpp path="../../components/cache" library="libmemcache"/>
|
||||
<service name="Memcache">
|
||||
<t:binding.atom uri="memcache"/>
|
||||
</service>
|
||||
<property name="servers">localhost:11211</property>
|
||||
</component>
|
||||
|
||||
<component name="Sqldb">
|
||||
<implementation.cpp path="../../components/sqldb" library="libsqldb"/>
|
||||
<property name="conninfo">dbname=db</property>
|
||||
<property name="conninfo">host=localhost port=5432 dbname=db</property>
|
||||
<property name="table">store</property>
|
||||
<service name="Sqldb">
|
||||
<t:binding.atom uri="sqldb"/>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue