From 95fa76f5f3208d913320c13a05171ecdcd7134c2 Mon Sep 17 00:00:00 2001 From: jsdelfino Date: Sat, 2 Jan 2010 10:27:26 +0000 Subject: Performance improvements when running both in multi-threaded and pre-forked HTTPD. Changed memory management to use Apache APR pools instead of ref counting pointers as it's much faster and easier to integrate with the Python and Ruby interpreters. Changed to use simple pool-based string and stream implementations instead of the STL ones, which cause a lots of mutex locks in a multi-threaded environment. Added build options to compile with threading and profiling. git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@895165 13f79535-47bb-0310-9956-ffa450edef68 --- sca-cpp/trunk/modules/server/mod-eval.cpp | 126 +++++++++++++++--------------- 1 file changed, 65 insertions(+), 61 deletions(-) (limited to 'sca-cpp/trunk/modules/server/mod-eval.cpp') diff --git a/sca-cpp/trunk/modules/server/mod-eval.cpp b/sca-cpp/trunk/modules/server/mod-eval.cpp index d8354c6a58..8e8870dd52 100644 --- a/sca-cpp/trunk/modules/server/mod-eval.cpp +++ b/sca-cpp/trunk/modules/server/mod-eval.cpp @@ -23,15 +23,11 @@ * HTTPD module used to eval component implementations. */ -#include -#include -#include -#include - +#include "string.hpp" +#include "stream.hpp" #include "function.hpp" #include "list.hpp" #include "tree.hpp" -#include "slist.hpp" #include "value.hpp" #include "element.hpp" #include "monad.hpp" @@ -58,9 +54,10 @@ class ServerConf { public: ServerConf(server_rec* s) : s(s), home(""), wiringServerName("") { } + const server_rec* s; - std::string home; - std::string wiringServerName; + string home; + string wiringServerName; }; /** @@ -71,8 +68,8 @@ public: DirConf(char* dirspec) : dirspec(dirspec), contributionPath(""), compositeName("") { } const char* dirspec; - std::string contributionPath; - std::string compositeName; + string contributionPath; + string compositeName; list implementations; }; @@ -80,16 +77,16 @@ public: * Convert a result represented as a content + failure pair to a * failable monad. */ -const failable failableResult(const list& v) { +const failable failableResult(const list& v) { if (isNil(cdr(v))) return car(v); - return mkfailure(cadr(v)); + return mkfailure(string(cadr(v))); } /** * Handle an HTTP GET. */ -const failable get(request_rec* r, const lambda&)>& impl) { +const failable get(request_rec* r, const lambda&)>& impl) { debug(r->uri, "modeval::get::uri"); // Inspect the query string @@ -102,12 +99,12 @@ const failable get(request_rec* r, const lambda val = failableResult(impl(cons(func, httpd::queryParams(args)))); + const failable val = failableResult(impl(cons(func, httpd::queryParams(args)))); if (!hasContent(val)) - return mkfailure(reason(val)); + return mkfailure(reason(val)); // Return JSON result json::JSONContext cx; @@ -115,58 +112,58 @@ const failable get(request_rec* r, const lambda path(httpd::path(r->uri)); + const list path(httpd::pathValues(r->uri)); if (isNil(cddr(path))) { - const failable val = failableResult(impl(cons("getall", list()))); + const failable val = failableResult(impl(cons("getall", list()))); if (!hasContent(val)) - return mkfailure(reason(val)); + return mkfailure(reason(val)); return httpd::writeResult(atom::writeATOMFeed(atom::feedValuesToElements(content(val))), "application/atom+xml;type=feed", r); } // Evaluate an ATOM GET and return an ATOM entry - const failable val = failableResult(impl(cons("get", mklist(caddr(path))))); + const failable val = failableResult(impl(cons("get", mklist(caddr(path))))); if (!hasContent(val)) - return mkfailure(reason(val)); + return mkfailure(reason(val)); return httpd::writeResult(atom::writeATOMEntry(atom::entryValuesToElements(content(val))), "application/atom+xml;type=entry", r); } /** * Handle an HTTP POST. */ -const failable post(request_rec* r, const lambda&)>& impl) { - const list ls = httpd::read(r); +const failable post(request_rec* r, const lambda&)>& impl) { + const list ls = httpd::read(r); debug(r->uri, "modeval::post::url"); debug(ls, "modeval::post::input"); // Evaluate a JSON-RPC request and return a JSON result - const std::string ct = httpd::contentType(r); - if (ct.find("application/json-rpc") != std::string::npos || ct.find("text/plain") != std::string::npos) { + const string ct = httpd::contentType(r); + if (contains(ct, "application/json-rpc") || contains(ct, "text/plain")) { json::JSONContext cx; const list json = elementsToValues(content(json::readJSON(ls, cx))); const list > args = httpd::postArgs(json); // Extract the request id, method and params const value id = cadr(assoc(value("id"), args)); - const value func = std::string(cadr(assoc(value("method"), args))).c_str(); + const value func = c_str(cadr(assoc(value("method"), args))); const list params = (list)cadr(assoc(value("params"), args)); // Evaluate the request expression - const failable val = failableResult(impl(cons(func, params))); + const failable val = failableResult(impl(cons(func, params))); if (!hasContent(val)) - return mkfailure(reason(val)); + return mkfailure(reason(val)); // Return JSON result return httpd::writeResult(json::jsonResult(id, content(val), cx), "application/json-rpc", r); } // Evaluate an ATOM POST request and return the created resource location - if (ct.find("application/atom+xml") != std::string::npos) { + if (contains(ct, "application/atom+xml")) { // Evaluate the request expression const value entry = atom::entryValue(content(atom::readEntry(ls))); - const failable val = failableResult(impl(cons("post", mklist(entry)))); + const failable val = failableResult(impl(cons("post", mklist(entry)))); if (!hasContent(val)) - return mkfailure(reason(val)); + return mkfailure(reason(val)); // Return the created resource location apr_table_setn(r->headers_out, "Location", apr_pstrdup(r->pool, httpd::url(content(val), r))); @@ -180,17 +177,17 @@ const failable post(request_rec* r, const lambda put(request_rec* r, const lambda&)>& impl) { - const list ls = httpd::read(r); +const failable put(request_rec* r, const lambda&)>& impl) { + const list ls = httpd::read(r); debug(r->uri, "modeval::put::url"); debug(ls, "modeval::put::input"); // Evaluate an ATOM PUT request - const list path(httpd::path(r->uri)); + const list path(httpd::pathValues(r->uri)); const value entry = atom::entryValue(content(atom::readEntry(ls))); - const failable val = failableResult(impl(cons("put", mklist(caddr(path), entry)))); + const failable val = failableResult(impl(cons("put", mklist(caddr(path), entry)))); if (!hasContent(val)) - return mkfailure(reason(val)); + return mkfailure(reason(val)); if (val == value(false)) return HTTP_NOT_FOUND; return OK; @@ -199,14 +196,14 @@ const failable put(request_rec* r, const lambda del(request_rec* r, const lambda&)>& impl) { +const failable del(request_rec* r, const lambda&)>& impl) { debug(r->uri, "modeval::delete::url"); // Evaluate an ATOM delete request - const list path(httpd::path(r->uri)); - const failable val = failableResult(impl(cons("delete", mklist(caddr(path))))); + const list path(httpd::pathValues(r->uri)); + const failable val = failableResult(impl(cons("delete", mklist(caddr(path))))); if (!hasContent(val)) - return mkfailure(reason(val)); + return mkfailure(reason(val)); if (val == value(false)) return HTTP_NOT_FOUND; return OK; @@ -216,6 +213,7 @@ const failable del(request_rec* r, const lambdapool); if (strncmp(r->uri, "/components/", 12) != 0) return DECLINED; r->handler = "mod_tuscany_eval"; @@ -226,6 +224,7 @@ int translate(request_rec *r) { * HTTP request handler. */ int handler(request_rec *r) { + gc_scoped_pool pool(r->pool); if(strcmp(r->handler, "mod_tuscany_eval")) return DECLINED; httpdDebugRequest(r, "modeval::handler::input"); @@ -237,7 +236,7 @@ int handler(request_rec *r) { // Get the component implementation lambda DirConf& dc = httpd::dirConf(r, &mod_tuscany_eval); - const list path(httpd::path(r->uri)); + const list path(httpd::pathValues(r->uri)); const list impl(assoctree(cadr(path), dc.implementations)); if (isNil(impl)) return HTTP_NOT_FOUND; @@ -260,11 +259,11 @@ int handler(request_rec *r) { /** * Convert a list of component references to a list of HTTP proxy lambdas. */ -const value mkproxy(const value& ref, const std::string& base) { - return lambda&)>(http::proxy(base + std::string(scdl::name(ref)))); +const value mkproxy(const value& ref, const string& base) { + return lambda&)>(http::proxy(base + string(scdl::name(ref)))); } -const list proxies(const list& refs, const std::string& base) { +const list proxies(const list& refs, const string& base) { if (isNil(refs)) return refs; return cons(mkproxy(car(refs), base), proxies(cdr(refs), base)); @@ -274,31 +273,31 @@ const list proxies(const list& refs, const std::string& base) { * Return a configured component implementation. * For now only Scheme and C++ implementations are supported. */ -const failable&)>, std::string> readImplementation(const std::string& itype, const std::string& path, const list& px) { - if (itype.find(".scheme") != std::string::npos) +const failable&)> > readImplementation(const string& itype, const string& path, const list& px) { + if (contains(itype, ".scheme")) return scm::readImplementation(path, px); - if (itype.find(".cpp") != std::string::npos) + if (contains(itype, ".cpp")) return cpp::readImplementation(path, px); - return mkfailure&)>, std::string>("Unsupported implementation type: " + itype); + return mkfailure&)> >(string("Unsupported implementation type: ") + itype); } const value confImplementation(DirConf& dc, ServerConf& sc, server_rec& server, const value& comp) { const value impl = scdl::implementation(comp); - const std::string path = dc.contributionPath + std::string(scdl::uri(impl)); + const string path = dc.contributionPath + string(scdl::uri(impl)); // Convert component references to configured proxy lambdas - std::ostringstream base; + ostringstream base; if (sc.wiringServerName == "") base << (server.server_scheme == NULL? "http" : server.server_scheme) << "://" << (server.server_hostname == NULL? "localhost" : server.server_hostname) << ":" << (server.port == 0? 80 : server.port) - << "/references/" << std::string(scdl::name(comp)) << "/"; + << "/references/" << string(scdl::name(comp)) << "/"; else - base << sc.wiringServerName << "/references/" << std::string(scdl::name(comp)) << "/"; - const list px(proxies(scdl::references(comp), base.str())); + base << sc.wiringServerName << "/references/" << string(scdl::name(comp)) << "/"; + const list px(proxies(scdl::references(comp), str(base))); // Read and configure the implementation - const failable&)>, std::string> cimpl(readImplementation(elementName(impl), path, px)); + const failable&)> > cimpl(readImplementation(elementName(impl), path, px)); if (!hasContent(cimpl)) return reason(cimpl); return content(cimpl); @@ -320,10 +319,10 @@ const list componentToImplementationTree(DirConf& dc, ServerConf& sc, ser /** * Read the components declared in a composite. */ -const failable, std::string> readComponents(const std::string& path) { - std::ifstream is(path); - if (is.fail() || is.bad()) - return mkfailure, std::string>("Could not read composite: " + path); +const failable > readComponents(const string& path) { + ifstream is(path); + if (fail(is)) + return mkfailure >(string("Could not read composite: ") + path); return scdl::components(readXML(streamList(is))); } @@ -333,7 +332,7 @@ const failable, std::string> readComponents(const std::string& path) const bool confComponents(DirConf& dc, ServerConf& sc, server_rec& server) { if (dc.contributionPath == "" || dc.compositeName == "") return true; - const failable, std::string> comps = readComponents(dc.contributionPath + dc.compositeName); + const failable > comps = readComponents(dc.contributionPath + dc.compositeName); if (!hasContent(comps)) return true; dc.implementations = componentToImplementationTree(dc, sc, server, content(comps)); @@ -345,16 +344,19 @@ const bool confComponents(DirConf& dc, ServerConf& sc, server_rec& server) { * Configuration commands. */ const char *confHome(cmd_parms *cmd, unused void *c, const char *arg) { + gc_scoped_pool pool(cmd->pool); ServerConf& sc = httpd::serverConf(cmd, &mod_tuscany_eval); sc.home = arg; return NULL; } const char *confWiringServerName(cmd_parms *cmd, unused void *c, const char *arg) { + gc_scoped_pool pool(cmd->pool); ServerConf& sc = httpd::serverConf(cmd, &mod_tuscany_eval); sc.wiringServerName = arg; return NULL; } const char *confContribution(cmd_parms *cmd, void *c, const char *arg) { + gc_scoped_pool pool(cmd->pool); ServerConf& sc = httpd::serverConf(cmd, &mod_tuscany_eval); DirConf& dc = *(DirConf*)c; dc.contributionPath = arg; @@ -362,6 +364,7 @@ const char *confContribution(cmd_parms *cmd, void *c, const char *arg) { return NULL; } const char *confComposite(cmd_parms *cmd, void *c, const char *arg) { + gc_scoped_pool pool(cmd->pool); ServerConf& sc = httpd::serverConf(cmd, &mod_tuscany_eval); DirConf& dc = *(DirConf*)c; dc.compositeName = arg; @@ -384,10 +387,11 @@ int postConfig(unused apr_pool_t *p, unused apr_pool_t *plog, unused apr_pool_t return OK; } -void childInit(unused apr_pool_t* p, server_rec* svr_rec) { +void childInit(apr_pool_t* p, server_rec* svr_rec) { + gc_scoped_pool pool(p); ServerConf* c = (ServerConf*)ap_get_module_config(svr_rec->module_config, &mod_tuscany_eval); if(c == NULL) { - std::cerr << "[Tuscany] Due to one or more errors mod_tuscany_eval loading failed. Causing apache to stop loading." << std::endl; + cerr << "[Tuscany] Due to one or more errors mod_tuscany_eval loading failed. Causing apache to stop loading." << endl; exit(APEXIT_CHILDFATAL); } } -- cgit v1.2.3