From 0e819eb42b4d680a99ae7b04702bfc9510495aee Mon Sep 17 00:00:00 2001 From: deva Date: Wed, 6 Jan 2010 07:47:58 +0000 Subject: New artefact connection class (to later wrap libartefact). New environment class to hold all global resources. Made ConnectionPool a template class. Split journal code up into two files (class from commit code). --- server/src/Makefile.am | 6 + server/src/artefact.cc | 58 ++++++++ server/src/artefact.h | 42 ++++++ server/src/configuration.cc | 10 +- server/src/configuration.h | 8 +- server/src/configurationparser.cc | 20 ++- server/src/connectionpool.cc | 167 +++++---------------- server/src/connectionpool.h | 143 ++++++++++++++++-- server/src/environment.cc | 77 ++++++++++ server/src/environment.h | 50 +++++++ server/src/journal_commit.cc | 97 +----------- server/src/journal_commit.h | 33 +---- server/src/journalwriter.cc | 198 +++++++++++++++++++++++++ server/src/journalwriter.h | 62 ++++++++ server/src/pracrod.cc | 5 + server/src/queryhandlerpentominos.cc | 18 +-- server/src/queryhandlerpentominos.h | 6 +- server/src/server.cc | 180 +++++++++------------- server/src/session.cc | 64 ++++++-- server/src/session.h | 18 ++- server/src/transactionhandler.cc | 280 ++++++++++++++++++----------------- server/src/transactionhandler.h | 17 +-- 22 files changed, 992 insertions(+), 567 deletions(-) create mode 100644 server/src/artefact.cc create mode 100644 server/src/artefact.h create mode 100644 server/src/environment.cc create mode 100644 server/src/environment.h create mode 100644 server/src/journalwriter.cc create mode 100644 server/src/journalwriter.h diff --git a/server/src/Makefile.am b/server/src/Makefile.am index 3d30adf..ab49bf7 100644 --- a/server/src/Makefile.am +++ b/server/src/Makefile.am @@ -7,17 +7,20 @@ pracrod_CXXFLAGS = $(PQXX_CXXFLAGS) $(CONFIG_CXXFLAGS) $(LUA_CXXFLAGS) $(HTTPD_C pracrod_SOURCES = \ pracrod.cc \ + artefact.cc \ daemon.cc \ database.cc \ configuration.cc \ configurationparser.cc \ connectionpool.cc \ debug.cc \ + environment.cc \ exception.cc \ queryhandlerpentominos.cc \ queryhandlerpracro.cc \ queryparser.cc \ journal_commit.cc \ + journalwriter.cc \ log.cc \ luaquerymapper.cc \ luaresume.cc \ @@ -72,6 +75,7 @@ macrotool_SOURCES = \ versionstr.cc EXTRA_DIST = \ + artefact.h \ configuration.h \ configurationparser.h \ connectionpool.h \ @@ -79,12 +83,14 @@ EXTRA_DIST = \ database.h \ dbtypes.h \ debug.h \ + environment.h \ exception.h \ queryhandler.h \ queryhandlerpentominos.h \ queryhandlerpracro.h \ queryparser.h \ journal_commit.h \ + journalwriter.h \ log.h \ luaquerymapper.h \ luaresume.h \ diff --git a/server/src/artefact.cc b/server/src/artefact.cc new file mode 100644 index 0000000..836e5a9 --- /dev/null +++ b/server/src/artefact.cc @@ -0,0 +1,58 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set et sw=2 ts=2: */ +/*************************************************************************** + * artefact.cc + * + * Tue Jan 5 14:45:34 CET 2010 + * Copyright 2010 Bent Bisballe Nyeng + * deva@aasimon.org + ****************************************************************************/ + +/* + * This file is part of Pracro. + * + * Pracro is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Pracro is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Pracro; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ +#include "artefact.h" + +#include "debug.h" +#include "configuration.h" + +Artefact::Artefact() +{ +#ifndef WITHOUT_PENTOMINOS + PRACRO_DEBUG(artefact, "Creating artefact connection %s : %d", + Conf::artefact_addr.c_str(), Conf::artefact_port) + socket.connect(Conf::artefact_addr, Conf::artefact_port); +#endif/*WITHOUT_PENTOMINOS*/ +} + + +#ifdef TEST_ARTEFACT +//Additional dependency files +//deps: +//Required cflags (autoconf vars may be used) +//cflags: +//Required link options (autoconf vars may be used) +//libs: +#include "test.h" + +TEST_BEGIN; + +// TODO: Put some testcode here (see test.h for usable macros). + +TEST_END; + +#endif/*TEST_ARTEFACT*/ diff --git a/server/src/artefact.h b/server/src/artefact.h new file mode 100644 index 0000000..15dcaa0 --- /dev/null +++ b/server/src/artefact.h @@ -0,0 +1,42 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set et sw=2 ts=2: */ +/*************************************************************************** + * artefact.h + * + * Tue Jan 5 14:45:34 CET 2010 + * Copyright 2010 Bent Bisballe Nyeng + * deva@aasimon.org + ****************************************************************************/ + +/* + * This file is part of Pracro. + * + * Pracro is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Pracro is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Pracro; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ +#ifndef __PRACRO_ARTEFACT_H__ +#define __PRACRO_ARTEFACT_H__ + +// TODO: use libartefact here... + +#include "tcpsocket.h" + +class Artefact { +public: + Artefact(); + + TCPSocket socket; +}; + +#endif/*__PRACRO_ARTEFACT_H__*/ diff --git a/server/src/configuration.cc b/server/src/configuration.cc index 34729c4..4d61079 100644 --- a/server/src/configuration.cc +++ b/server/src/configuration.cc @@ -38,17 +38,21 @@ port_t Conf::journal_commit_port = 18112; time_t Conf::db_max_ttl = 7 * 60 * 60 * 24; time_t Conf::pentominos_max_ttl = 7 * 60 * 60 * 24; -std::string Conf::pentominos_addr = "localhost"; -port_t Conf::pentominos_port = 11108; +std::string Conf::artefact_addr = "localhost"; +port_t Conf::artefact_port = 11108; + +int Conf::artefact_poolsize = 1; std::string Conf::database_backend = "pgsql"; std::string Conf::database_addr = "localhost"; std::string Conf::database_user = "pracro"; std::string Conf::database_passwd = "pracro"; +int Conf::database_poolsize = 2; + std::string Conf::xml_basedir = XML; -bool Conf::use_ssl = false; +bool Conf::use_ssl = false; std::string Conf::ssl_key = ""; std::string Conf::ssl_cert = ""; diff --git a/server/src/configuration.h b/server/src/configuration.h index c12bf19..4b5cf09 100644 --- a/server/src/configuration.h +++ b/server/src/configuration.h @@ -45,14 +45,18 @@ namespace Conf { extern time_t db_max_ttl; extern time_t pentominos_max_ttl; - extern std::string pentominos_addr; - extern port_t pentominos_port; + extern std::string artefact_addr; + extern port_t artefact_port; + + extern int artefact_poolsize; extern std::string database_backend; extern std::string database_addr; extern std::string database_user; extern std::string database_passwd; + extern int database_poolsize; + extern std::string xml_basedir; extern bool use_ssl; diff --git a/server/src/configurationparser.cc b/server/src/configurationparser.cc index 551e8da..d16920f 100644 --- a/server/src/configurationparser.cc +++ b/server/src/configurationparser.cc @@ -93,14 +93,20 @@ void ConfigurationParser::reload() } try { - std::string a = lookup("pentominos_addr"); - Conf::pentominos_addr = a; + std::string s = lookup("artefact_addr"); + Conf::artefact_addr = s; } catch( ... ) { } try { - int p = lookup("pentominos_port"); - Conf::pentominos_port = p; + int i = lookup("artefact_port"); + Conf::artefact_port = i; + } catch( ... ) { + } + + try { + int i = lookup("artefact_poolsize"); + Conf::artefact_poolsize = i; } catch( ... ) { } @@ -128,6 +134,12 @@ void ConfigurationParser::reload() } catch( ... ) { } + try { + int i = lookup("database_poolsize"); + Conf::database_poolsize = i; + } catch( ... ) { + } + try { std::string p = lookup("xml_basedir"); Conf::xml_basedir = p; diff --git a/server/src/connectionpool.cc b/server/src/connectionpool.cc index 9271871..743bb68 100644 --- a/server/src/connectionpool.cc +++ b/server/src/connectionpool.cc @@ -27,104 +27,9 @@ */ #include "connectionpool.h" -ConnectionPool::ConnectionPool() -{ -} - -void ConnectionPool::addDatabase(Database *db) -{ - mutex.lock(); - passivedbs.push_back(db); - semaphore.post(); - mutex.unlock(); -} - -static inline bool contains(std::list list, Database *db) -{ - std::list::iterator i = list.begin(); - while(i != list.end()) { - if(*i == db) return true; - i++; - } - return false; -} - -void ConnectionPool::removeDatabase(Database *db) -{ - mutex.lock(); - if(contains(passivedbs, db)) { - semaphore.post(); - passivedbs.remove(db); - } - mutex.unlock(); -} - -bool ConnectionPool::testFree(Database *db) -{ - bool testfree = false; - - mutex.lock(); - testfree = contains(passivedbs, db); - mutex.unlock(); - - return testfree; -} - -int ConnectionPool::numFreeDatabases() -{ - int num; - mutex.lock(); - num = passivedbs.size(); - mutex.unlock(); - return num; -} - -Database *ConnectionPool::borrowDatabase() -{ - Database *db = NULL; - - semaphore.wait(); - - mutex.lock(); - - db = passivedbs.front(); - passivedbs.remove(db); - activedbs.push_back(db); - - mutex.unlock(); - - return db; -} - -void ConnectionPool::returnDatabase(Database *db) -{ - mutex.lock(); - - if(contains(activedbs, db)) { - activedbs.remove(db); - passivedbs.push_back(db); - semaphore.post(); - } - - mutex.unlock(); -} - -AutoBorrower::AutoBorrower(ConnectionPool &p) - : pool(p) -{ - _db = pool.borrowDatabase(); -} - -AutoBorrower::~AutoBorrower() -{ - pool.returnDatabase(_db); -} - -Database *AutoBorrower::db() -{ - return _db; -} - +// +// Implementation is in the header file. +// #ifdef TEST_CONNECTIONPOOL //deps: mutex.cc semaphore.cc @@ -136,78 +41,78 @@ Database *AutoBorrower::db() static void* thread_run(void *data) { - ConnectionPool *pool = (ConnectionPool*)data; + ConnectionPool *pool = (ConnectionPool*)data; - Database *db1 = pool->borrowDatabase(); - Database *db2 = pool->borrowDatabase(); - Database *db3 = pool->borrowDatabase(); - Database *db4 = pool->borrowDatabase(); + int db1 = pool->borrow(); + int db2 = pool->borrow(); + int db3 = pool->borrow(); + int db4 = pool->borrow(); usleep(100); - pool->returnDatabase(db1); - pool->returnDatabase(db2); - pool->returnDatabase(db3); - pool->returnDatabase(db4); + pool->giveBack(db1); + pool->giveBack(db2); + pool->giveBack(db3); + pool->giveBack(db4); return NULL; } TEST_BEGIN; -ConnectionPool pool; +ConnectionPool pool; -Database *db1 = (Database*)1; -Database *db2 = (Database*)2; -Database *db3 = (Database*)3; -Database *db4 = (Database*)4; +int db1 = 1; +int db2 = 2; +int db3 = 3; +int db4 = 4; -pool.addDatabase(db1); -pool.addDatabase(db2); -pool.addDatabase(db3); -pool.addDatabase(db4); +pool.add(db1); +pool.add(db2); +pool.add(db3); +pool.add(db4); TEST_TRUE(pool.testFree(db1), "Testing if db1 is free."); TEST_TRUE(pool.testFree(db2), "Testing if db2 is free."); TEST_TRUE(pool.testFree(db3), "Testing if db3 is free."); TEST_TRUE(pool.testFree(db4), "Testing if db4 is free."); -TEST_EQUAL(pool.numFreeDatabases(), 4, "Testing number of free databases."); +TEST_EQUAL(pool.numFree(), 4, "Testing number of free databases."); -Database *b_db1 = pool.borrowDatabase(); +int b_db1 = pool.borrow(); TEST_FALSE(pool.testFree(b_db1), "Testing if borrowed db is free."); -Database *b_db2 = pool.borrowDatabase(); +int b_db2 = pool.borrow(); TEST_NOTEQUAL(b_db1, b_db2, "Testing if borrowed db is unique."); -pool.returnDatabase(b_db1); +pool.giveBack(b_db1); TEST_TRUE(pool.testFree(b_db1), "Testing if returned db is free."); -pool.returnDatabase(b_db2); +pool.giveBack(b_db2); -TEST_EQUAL(pool.numFreeDatabases(), 4, "Testing number of free databases."); +TEST_EQUAL(pool.numFree(), 4, "Testing number of free databases."); pthread_attr_t attr; pthread_t tid; pthread_attr_init(&attr); pthread_create(&tid, &attr, thread_run, &pool); -while(pool.numFreeDatabases() > 0) { usleep(10); } +while(pool.numFree() > 0) { usleep(10); } -Database *b_db3 = pool.borrowDatabase(); +int b_db3 = pool.borrow(); TEST_FALSE(pool.testFree(b_db3), "Testing if returned db is free (semaphore test)."); -pool.returnDatabase(db3); +pool.giveBack(db3); pthread_join(tid, NULL); pthread_attr_destroy(&attr); -TEST_EQUAL(pool.numFreeDatabases(), 4, "Testing if all database are now available again"); +TEST_EQUAL(pool.numFree(), 4, "Testing if all database are now available again"); { - TEST_EQUAL(pool.numFreeDatabases(), 4, "Testing if autoborrower has not yet borrowed a db."); - AutoBorrower b(pool); - TEST_EQUAL(pool.numFreeDatabases(), 3, "Testing if autoborrower has borrowed a db."); - TEST_FALSE(pool.testFree(b.db()), "Testing if the autoborrowed db is actually taken."); + TEST_EQUAL(pool.numFree(), 4, "Testing if autoborrower has not yet borrowed a db."); + AutoBorrower b(pool); + TEST_EQUAL(pool.numFree(), 3, "Testing if autoborrower has borrowed a db."); + TEST_FALSE(pool.testFree(b.get()), "Testing if the autoborrowed db is actually taken."); } -TEST_EQUAL(pool.numFreeDatabases(), 4, "Testing if autoborrower has returned the db."); +TEST_EQUAL(pool.numFree(), 4, "Testing if autoborrower has returned the db."); TEST_END; diff --git a/server/src/connectionpool.h b/server/src/connectionpool.h index 548d76a..77fc33b 100644 --- a/server/src/connectionpool.h +++ b/server/src/connectionpool.h @@ -33,38 +33,149 @@ #include "mutex.h" #include "semaphore.h" -class Database; - +template class ConnectionPool { public: - ConnectionPool(); - - void addDatabase(Database *db); - void removeDatabase(Database *db); + void add(T t); + void remove(T t); - bool testFree(Database *db); - int numFreeDatabases(); + bool testFree(T t); + int numFree(); - Database *borrowDatabase(); - void returnDatabase(Database *db); + T borrow(); + void giveBack(T t); private: + bool contains(std::list &list, T t); + Semaphore semaphore; Mutex mutex; - std::list activedbs; - std::list passivedbs; + std::list active; + std::list passive; }; +template class AutoBorrower { public: - AutoBorrower(ConnectionPool &pool); + AutoBorrower(ConnectionPool &pool); ~AutoBorrower(); - Database *db(); + T get(); private: - ConnectionPool &pool; - Database *_db; + ConnectionPool &pool; + T t; }; + +// +// Implementation is below +// + +template +void ConnectionPool::add(T t) +{ + mutex.lock(); + passive.push_back(t); + semaphore.post(); + mutex.unlock(); +} + +template +bool ConnectionPool::contains(std::list &list, T t) +{ + typename std::list::iterator i = list.begin(); + while(i != list.end()) { + if(*i == t) return true; + i++; + } + + return false; +} + +template +void ConnectionPool::remove(T t) +{ + mutex.lock(); + if(contains(passive, t)) { + semaphore.post(); + passive.remove(t); + } + mutex.unlock(); +} + +template +bool ConnectionPool::testFree(T t) +{ + bool testfree = false; + + mutex.lock(); + testfree = contains(passive, t); + mutex.unlock(); + + return testfree; +} + +template +int ConnectionPool::numFree() +{ + int num; + mutex.lock(); + num = passive.size(); + mutex.unlock(); + return num; +} + +template +T ConnectionPool::borrow() +{ + T t = NULL; + + semaphore.wait(); + + mutex.lock(); + + t = passive.front(); + passive.remove(t); + active.push_back(t); + + mutex.unlock(); + + return t; +} + +template +void ConnectionPool::giveBack(T t) +{ + mutex.lock(); + + if(contains(active, t)) { + active.remove(t); + passive.push_back(t); + semaphore.post(); + } + + mutex.unlock(); +} + + +template +AutoBorrower::AutoBorrower(ConnectionPool &p) + : pool(p) +{ + t = pool.borrow(); +} + +template +AutoBorrower::~AutoBorrower() +{ + pool.giveBack(t); +} + +template +T AutoBorrower::get() +{ + return t; +} + #endif/*__PRACRO_CONNECTIONPOOL_H__*/ diff --git a/server/src/environment.cc b/server/src/environment.cc new file mode 100644 index 0000000..1cdfaba --- /dev/null +++ b/server/src/environment.cc @@ -0,0 +1,77 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set et sw=2 ts=2: */ +/*************************************************************************** + * environment.cc + * + * Tue Jan 5 11:41:23 CET 2010 + * Copyright 2010 Bent Bisballe Nyeng + * deva@aasimon.org + ****************************************************************************/ + +/* + * This file is part of Pracro. + * + * Pracro is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Pracro is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Pracro; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ +#include "environment.h" + +#include "configuration.h" +#include "database.h" + +Environment::Environment() + : macrolist(Conf::xml_basedir + "/macros"), + templatelist(Conf::xml_basedir + "/templates") +{ + for(int i = 0; i < Conf::database_poolsize; i++) { + dbpool.add(new Database(Conf::database_backend, Conf::database_addr, + "", Conf::database_user, Conf::database_passwd, "")); + } + + for(int i = 0; i < Conf::artefact_poolsize; i++) { + atfpool.add(new Artefact); + } +} + +Environment::~Environment() +{ +} + +/* + TCPSocket pentominos_socket; +#ifndef WITHOUT_PENTOMINOS + pentominos_socket.connect(Conf::pentominos_addr, Conf::pentominos_port); +#endif +*/ + +#ifdef TEST_ENVIRONMENT +//deps: configuration.cc database.cc artefact.cc pracrodao.cc session.cc mutex.cc semaphore.cc debug.cc pracrodaotest.cc pracrodaopgsql.cc journalwriter.cc journal_commit.cc +//cflags: -I.. $(PQXX_CXXFLAGS) +//libs: $(PQXX_LIBS) -lpthread +#include "test.h" + +TEST_BEGIN; + +Conf::database_backend = "testdb"; +Conf::database_poolsize = 1; + +Conf::artefact_poolsize = 1; + +Environment env; + +// TODO: Put some testcode here (see test.h for usable macros). + +TEST_END; + +#endif/*TEST_ENVIRONMENT*/ diff --git a/server/src/environment.h b/server/src/environment.h new file mode 100644 index 0000000..a7b9677 --- /dev/null +++ b/server/src/environment.h @@ -0,0 +1,50 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set et sw=2 ts=2: */ +/*************************************************************************** + * environment.h + * + * Tue Jan 5 11:41:23 CET 2010 + * Copyright 2010 Bent Bisballe Nyeng + * deva@aasimon.org + ****************************************************************************/ + +/* + * This file is part of Pracro. + * + * Pracro is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Pracro is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Pracro; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ +#ifndef __PRACRO_ENVIRONMENT_H__ +#define __PRACRO_ENVIRONMENT_H__ + +#include "database.h" +#include "artefact.h" +#include "connectionpool.h" +#include "session.h" +#include "templatelist.h" +#include "macrolist.h" + +class Environment { +public: + Environment(); + ~Environment(); + + ConnectionPool dbpool; + ConnectionPool atfpool; + Sessions sessions; + MacroList macrolist; + TemplateList templatelist; +}; + +#endif/*__PRACRO_ENVIRONMENT_H__*/ diff --git a/server/src/journal_commit.cc b/server/src/journal_commit.cc index 414fa20..bc47fce 100644 --- a/server/src/journal_commit.cc +++ b/server/src/journal_commit.cc @@ -52,6 +52,7 @@ #include "template.h" #include "templateparser.h" +#if 0 static inline bool iswhitespace(char c) { return c == ' ' || c == '\n' || c == '\t'; @@ -109,6 +110,7 @@ static std::string addNewlines(std::string str, size_t width) return output; } +#endif static int mwrite(int sock, const char *fmt, ...) { @@ -184,7 +186,7 @@ int journal_commit(const char *cpr, const char *user, mwrite(sock, "charset: utf8\r\n"); mwrite(sock, "\r\n"); - std::string resume = stripTrailingWhitepace(addNewlines(buf, 60)); + std::string resume = buf;//stripTrailingWhitepace(addNewlines(buf, 60)); // send body if(sock != -1 && write(sock, resume.c_str(), resume.size()) != (ssize_t)resume.size()) { @@ -200,103 +202,10 @@ int journal_commit(const char *cpr, const char *user, return 0; } -JournalWriter::JournalWriter(std::string host, unsigned short int port) -{ - this->host = host; - this->port = port; -} - -void JournalWriter::addEntry(Transaction &transaction, Commit &commit, - std::string resume, Template *templ) -{ - size_t index = 0; - std::vector< Macro >::iterator i = templ->macros.begin(); - while(i != templ->macros.end()) { - Macro &m = *i; - if(commit.macro == m.attributes["name"]) break; - index++; - i++; - } - - if(index >= templ->macros.size()) { - PRACRO_ERR(journal, "Could not find macro %s in template %s\n", - commit.macro.c_str(), templ->attributes["name"].c_str()); - // return; - } else { - PRACRO_DEBUG(journal, "Found macro %s as index %u in template %s\n", - commit.macro.c_str(), index, templ->attributes["name"].c_str()); - } - - // First run - initialize username and cpr. - if(currentuser == "" && entrylist.size() == 0) currentuser = transaction.user; - if(currentcpr == "" && entrylist.size() == 0) currentcpr = transaction.cpr; - - PRACRO_DEBUG(journal, "addEntry: template(%s)\n", templ->attributes["name"].c_str()); - - // Add the template resume as the header (ie. first entry) of the journal entry. - if(entrylist.size() == 0 && templ->attributes["name"] != "") { - std::string template_resume = templ->attributes["resume"]; - - PRACRO_DEBUG(journal, "TemplateResume: %s\n", template_resume.c_str()); - - if(template_resume != "") { - ResumeEntry re; - re.resume = template_resume; - re.macro = "template_header"; - entrylist[-1] = re; // Make sure it comes first. - } - } - - // Test if the username or the cpr has changed... if so, commit and clear the list. - if(currentuser != transaction.user || currentcpr != transaction.cpr) { - this->commit(); - entrylist.clear(); - } - - // Strip trailing whitespace, and add newlines. - std::string r = stripTrailingWhitepace(addNewlines(resume, 60)); - std::string m = commit.macro; - - ResumeEntry re; - re.resume = r; - re.macro = m; - entrylist[index] = re; -} - -void JournalWriter::commit() -{ - std::string resume; - - // Iterate through all resumes, and create a string containing them all. - std::map< int, ResumeEntry >::iterator i = entrylist.begin(); - while(i != entrylist.end()) { - if(resume != "") resume += "\n\n"; - // resume += i->macro + "\n"; - resume += i->second.resume; - i++; - } - - if(resume == "") return; - - // Connect to praxisuploadserver and commit all resumes in one bulk. - journal_commit(currentcpr.c_str(), currentuser.c_str(), - host.c_str(), port, - resume.c_str(), resume.size()); -} - - #ifdef TEST_JOURNAL_COMMIT int main() { - std::string text = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do\neiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. \n\n \t"; - - std::string resume = stripTrailingWhitepace(addNewlines(text, 60)); - printf("[%s]\n", resume.c_str()); - - resume = stripTrailingWhitepace(addNewlines("", 60)); - printf("[%s]\n", resume.c_str()); - return 0; } diff --git a/server/src/journal_commit.h b/server/src/journal_commit.h index 4f7f211..1bc8086 100644 --- a/server/src/journal_commit.h +++ b/server/src/journal_commit.h @@ -27,35 +27,10 @@ #ifndef __PRACRO_JOURNAL_COMMIT_H__ #define __PRACRO_JOURNAL_COMMIT_H__ -#include -#include +#include -#include "transaction.h" -#include "template.h" - -class JournalWriter { -public: - JournalWriter(std::string host, unsigned short int port); - - void addEntry(Transaction &transaction, Commit &commit, - std::string resume, Template *templ); - - void commit(); - -private: - std::string host; - unsigned short int port; - - std::string currentuser; - std::string currentcpr; - - class ResumeEntry { - public: - std::string resume; - std::string macro; - }; - - std::map< int, ResumeEntry > entrylist; -}; +int journal_commit(const char *cpr, const char *user, + const char *addr, unsigned short int port, + const char *buf, size_t size); #endif/*__PRACRO_JOURNAL_COMMIT_H__*/ diff --git a/server/src/journalwriter.cc b/server/src/journalwriter.cc new file mode 100644 index 0000000..b84018a --- /dev/null +++ b/server/src/journalwriter.cc @@ -0,0 +1,198 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set et sw=2 ts=2: */ +/*************************************************************************** + * journalwriter.cc + * + * Tue Jan 5 15:52:54 CET 2010 + * Copyright 2010 Bent Bisballe Nyeng + * deva@aasimon.org + ****************************************************************************/ + +/* + * This file is part of Pracro. + * + * Pracro is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Pracro is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Pracro; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ +#include "journalwriter.h" + +#include "debug.h" +#include "journal_commit.h" + +static inline bool iswhitespace(char c) +{ + return c == ' ' || c == '\n' || c == '\t'; +} + +/** + * Remove all spaces, tabs and newline trailing the string. + */ +static std::string stripTrailingWhitepace(std::string str) +{ + if(str == "") return str; + + ssize_t end = str.size() - 1; + + while(end && iswhitespace(str[end]) + && (end>0 && str[end-1] & 0x80) == false // Make sure we are not in a utf8 character. + ) { + end--; + } + end++; + + return str.substr(0, end); +} + +/** + * Find all lines longer than 'width', and insert a newline in the + * first backward occurring space. + */ +static std::string addNewlines(std::string str, size_t width) +{ + std::string output; + + std::string fraction; + size_t linelen = 0; + for(size_t i = 0; i < str.size(); i++) { + + fraction += str[i]; + + if(iswhitespace(str[i]) + && (i>0 && str[i-1] & 0x80) == false // Make sure we are not in a utf8 character. + ) { + if(linelen + fraction.size() > width) { + output[output.size() - 1] = '\n'; + linelen = 0; + } + output += fraction; + linelen += fraction.size(); + fraction = ""; + } + + if(str[i] == '\n') linelen = 0; + + } + output += fraction; + + return output; +} + +JournalWriter::JournalWriter(std::string host, unsigned short int port) +{ + this->host = host; + this->port = port; +} + +void JournalWriter::addEntry(Transaction &transaction, Commit &commit, + std::string resume, Template *templ) +{ + size_t index = 0; + std::vector< Macro >::iterator i = templ->macros.begin(); + while(i != templ->macros.end()) { + Macro &m = *i; + if(commit.macro == m.attributes["name"]) break; + index++; + i++; + } + + if(index >= templ->macros.size()) { + PRACRO_ERR(journal, "Could not find macro %s in template %s\n", + commit.macro.c_str(), templ->attributes["name"].c_str()); + // return; + } else { + PRACRO_DEBUG(journal, "Found macro %s as index %u in template %s\n", + commit.macro.c_str(), index, templ->attributes["name"].c_str()); + } + + // First run - initialize username and cpr. + if(currentuser == "" && entrylist.size() == 0) currentuser = transaction.user; + if(currentcpr == "" && entrylist.size() == 0) currentcpr = transaction.cpr; + + PRACRO_DEBUG(journal, "addEntry: template(%s)\n", templ->attributes["name"].c_str()); + + // Add the template resume as the header (ie. first entry) of the journal entry. + if(entrylist.size() == 0 && templ->attributes["name"] != "") { + std::string template_resume = templ->attributes["resume"]; + + PRACRO_DEBUG(journal, "TemplateResume: %s\n", template_resume.c_str()); + + if(template_resume != "") { + ResumeEntry re; + re.resume = template_resume; + re.macro = "template_header"; + entrylist[-1] = re; // Make sure it comes first. + } + } + + // Test if the username or the cpr has changed... if so, commit and clear the list. + if(currentuser != transaction.user || currentcpr != transaction.cpr) { + this->commit(); + entrylist.clear(); + } + + // Strip trailing whitespace, and add newlines. + std::string r = stripTrailingWhitepace(addNewlines(resume, 60)); + std::string m = commit.macro; + + ResumeEntry re; + re.resume = r; + re.macro = m; + entrylist[index] = re; +} + +void JournalWriter::commit() +{ + std::string resume; + + // Iterate through all resumes, and create a string containing them all. + std::map< int, ResumeEntry >::iterator i = entrylist.begin(); + while(i != entrylist.end()) { + if(resume != "") resume += "\n\n"; + // resume += i->macro + "\n"; + resume += i->second.resume; + i++; + } + + if(resume == "") return; + + // Connect to praxisuploadserver and commit all resumes in one bulk. + journal_commit(currentcpr.c_str(), currentuser.c_str(), + host.c_str(), port, + resume.c_str(), resume.size()); +} + +#ifdef TEST_JOURNALWRITER +//Additional dependency files +//deps: +//Required cflags (autoconf vars may be used) +//cflags: +//Required link options (autoconf vars may be used) +//libs: +#include "test.h" + +TEST_BEGIN; + +std::string text = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do\neiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. \n\n \t"; + +std::string resume = stripTrailingWhitepace(addNewlines(text, 60)); +printf("[%s]\n", resume.c_str()); + +resume = stripTrailingWhitepace(addNewlines("", 60)); +printf("[%s]\n", resume.c_str()); + +// TODO: Put some testcode here (see test.h for usable macros). + +TEST_END; + +#endif/*TEST_JOURNALWRITER*/ diff --git a/server/src/journalwriter.h b/server/src/journalwriter.h new file mode 100644 index 0000000..5bde707 --- /dev/null +++ b/server/src/journalwriter.h @@ -0,0 +1,62 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set et sw=2 ts=2: */ +/*************************************************************************** + * journalwriter.h + * + * Tue Jan 5 15:52:54 CET 2010 + * Copyright 2010 Bent Bisballe Nyeng + * deva@aasimon.org + ****************************************************************************/ + +/* + * This file is part of Pracro. + * + * Pracro is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Pracro is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Pracro; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ +#ifndef __PRACRO_JOURNALWRITER_H__ +#define __PRACRO_JOURNALWRITER_H__ + +#include +#include + +#include "transaction.h" +#include "template.h" + +class JournalWriter { +public: + JournalWriter(std::string host, unsigned short int port); + + void addEntry(Transaction &transaction, Commit &commit, + std::string resume, Template *templ); + + void commit(); + +private: + std::string host; + unsigned short int port; + + std::string currentuser; + std::string currentcpr; + + class ResumeEntry { + public: + std::string resume; + std::string macro; + }; + + std::map< int, ResumeEntry > entrylist; +}; + +#endif/*__PRACRO_JOURNALWRITER_H__*/ diff --git a/server/src/pracrod.cc b/server/src/pracrod.cc index 6154f06..e15b0f0 100644 --- a/server/src/pracrod.cc +++ b/server/src/pracrod.cc @@ -274,6 +274,11 @@ int main(int argc, char *argv[]) Conf::database_backend = database; } + if(Conf::database_backend == "testdb") { + // Test db (memory only db) does not work in plural. + Conf::database_poolsize = 1; + } + if(!user) { user = strdup(Conf::server_user.c_str()); } diff --git a/server/src/queryhandlerpentominos.cc b/server/src/queryhandlerpentominos.cc index 62a742f..4abf5da 100644 --- a/server/src/queryhandlerpentominos.cc +++ b/server/src/queryhandlerpentominos.cc @@ -135,8 +135,8 @@ static std::string getUID(const char *interface) } -QueryHandlerPentominos::QueryHandlerPentominos(TCPSocket &_socket, std::string cpr) - : QueryHandler(), socket(_socket) +QueryHandlerPentominos::QueryHandlerPentominos(Artefact &atf, std::string cpr) + : QueryHandler(), artefact(atf) { this->cpr = cpr; } @@ -154,7 +154,7 @@ QueryResult QueryHandlerPentominos::exec(Query &query) " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" " xsi:schemaLocation=\"http://www.aasimon.org/pentominos schema.xsd\">\n"; #ifndef WITHOUT_PENTOMINOS - socket.write(header, strlen(header)); + artefact.socket.write(header, strlen(header)); #endif/*WITHOUT_PENTOMINOS*/ PRACRO_DEBUG(queryhandler, "%s", header); @@ -169,8 +169,8 @@ QueryResult QueryHandlerPentominos::exec(Query &query) cpr.c_str(), "pracro", #ifndef WITHOUT_PENTOMINOS - socket.srcaddr().c_str(), - socket.dstaddr().c_str(), + artefact.socket.srcaddr().c_str(), + artefact.socket.dstaddr().c_str(), #else "127.0.0.1", "127.0.0.1", @@ -178,7 +178,7 @@ QueryResult QueryHandlerPentominos::exec(Query &query) (unsigned int)timestamp, uid.c_str()); #ifndef WITHOUT_PENTOMINOS - socket.write(buf, strlen(buf)); + artefact.socket.write(buf, strlen(buf)); #endif/*WITHOUT_PENTOMINOS*/ PRACRO_DEBUG(queryhandler, "%s", buf); @@ -191,7 +191,7 @@ QueryResult QueryHandlerPentominos::exec(Query &query) query.attributes["class"].c_str()); #ifndef WITHOUT_PENTOMINOS - socket.write(buf, strlen(buf)); + artefact.socket.write(buf, strlen(buf)); #endif/*WITHOUT_PENTOMINOS*/ PRACRO_DEBUG(queryhandler, "%s", buf); @@ -199,7 +199,7 @@ QueryResult QueryHandlerPentominos::exec(Query &query) sprintf(buf, ""); #ifndef WITHOUT_PENTOMINOS - socket.write(buf, strlen(buf)); + artefact.socket.write(buf, strlen(buf)); #endif/*WITHOUT_PENTOMINOS*/ PRACRO_DEBUG(queryhandler, "%s", buf); @@ -212,7 +212,7 @@ QueryResult QueryHandlerPentominos::exec(Query &query) ssize_t size; // Read until we've got the entire result. - while((size = socket.read(buf, sizeof(buf))) > 0) { + while((size = artefact.socket.read(buf, sizeof(buf))) > 0) { // fwrite(buf, size, 1, stdout); fflush(stdout); if(parser.parse(buf, size)) break; } diff --git a/server/src/queryhandlerpentominos.h b/server/src/queryhandlerpentominos.h index 9c56d07..4c5e932 100644 --- a/server/src/queryhandlerpentominos.h +++ b/server/src/queryhandlerpentominos.h @@ -29,7 +29,7 @@ #include "queryhandler.h" -#include "tcpsocket.h" +#include "artefact.h" #include "template.h" #include "queryresult.h" @@ -41,14 +41,14 @@ */ class QueryHandlerPentominos : public QueryHandler { public: - QueryHandlerPentominos(TCPSocket &socket, std::string cpr); + QueryHandlerPentominos(Artefact &artefact, std::string cpr); ~QueryHandlerPentominos() {} // Execute all queries. QueryResult exec(Query &query); private: - TCPSocket &socket; + Artefact &artefact; std::string cpr; }; diff --git a/server/src/server.cc b/server/src/server.cc index 9b8f7f1..84c3463 100644 --- a/server/src/server.cc +++ b/server/src/server.cc @@ -43,40 +43,13 @@ #include "configuration.h" #include "transaction.h" #include "transactionparser.h" -#include "templateparser.h" -#include "macroparser.h" - -#include "queryhandler.h" -#include "queryhandlerpracro.h" -#include "queryhandlerpentominos.h" - -#include "queryparser.h" -#include "luaquerymapper.h" #include "database.h" -#include "widgetgenerator.h" -#include "resumeparser.h" -#include "journal_commit.h" -#include "xml_encode_decode.h" - -#include "macrolist.h" -#include "templatelist.h" -#include "versionstr.h" -#include "mutex.h" #include "log.h" - +#include "environment.h" #include "transactionhandler.h" - -typedef long long unsigned int sessionid_t; - -typedef struct { - JournalWriter *journalwriter; -} session_t; - -struct conn_t { - Database *db; - Mutex mutex; - std::map sessions; -}; +#include "connectionpool.h" +#include "session.h" +#include "xml_encode_decode.h" static std::string error_box(std::string message) { @@ -88,32 +61,52 @@ static std::string error_box(std::string message) return errorbox; } -static std::string handleConnection(const char *buf, size_t size, struct conn_t *conn, - sessionid_t sid, bool commitsession) +static std::string handleConnection(const char *buf, size_t size, + Environment &env, + char **sessionid, + const char *sessioncommit) { - /* - if(size == 0) - return error_box(xml_encode("Empty document received.")); - */ - TCPSocket pentominos_socket; -#ifndef WITHOUT_PENTOMINOS - pentominos_socket.connect(Conf::pentominos_addr, Conf::pentominos_port); -#endif/*WITHOUT_PENTOMINOS*/ - - JournalWriter *journalwriter = NULL; - conn->mutex.lock(); - if(conn->sessions.find(sid) == conn->sessions.end()) { - conn->sessions[sid].journalwriter = - new JournalWriter(Conf::journal_commit_addr.c_str(), Conf::journal_commit_port); + std::string res; + + Session *session = NULL; + if(*sessionid == NULL) { + session = env.sessions.newSession(); + } else { + session = env.sessions.session(*sessionid); + if(session == NULL) session = env.sessions.newSession(); + } + + if(session == NULL) { + PRACRO_ERR(server, "New session could not be created."); + return error_box(xml_encode("New session could not be created.")); } - journalwriter = conn->sessions[sid].journalwriter; - conn->mutex.unlock(); - MacroList macrolist(Conf::xml_basedir + "/macros"); - TemplateList templatelist(Conf::xml_basedir + "/templates"); + session->lock(); + + if(asprintf(sessionid, "%s", session->id().c_str()) == -1) *sessionid = NULL; Transaction transaction; TransactionParser parser(&transaction); + + if(!parser.parse(buf, size)) { + PRACRO_ERR(server, "Failed to parse data!\n"); + res = error_box(xml_encode("XML Parse error.")); + } else { + res = handleTransaction(transaction, env, *session); + } + + session->unlock(); + + if(sessioncommit != NULL) { + session->commit(); + env.sessions.deleteSession(session->id()); + } + + return res; + + /* + Transaction transaction; + TransactionParser parser(&transaction); PRACRO_DEBUG(server, "Read %d bytes from network\n", size); @@ -123,75 +116,49 @@ static std::string handleConnection(const char *buf, size_t size, struct conn_t PRACRO_DEBUG(server, "Got complete XML document, %d bytes in current buffer.\n", size); res = handleTransaction(&transaction, pentominos_socket, - *conn->db, *journalwriter, macrolist, templatelist); + *conn->db, session, macrolist, templatelist); } else { PRACRO_ERR(server, "Failed to parse data!\n"); res = error_box(xml_encode("XML Parse error.")); } } - - if(commitsession) { - journalwriter->commit(); - delete journalwriter; - conn->mutex.lock(); - conn->sessions.erase(sid); - conn->mutex.unlock(); - } - return res; + + */ } -static int handle_request(void *cls, - struct MHD_Connection *con, - const char *url, - const char *method, - const char *version, - const char *data, - unsigned int *data_size, - void **ptr) +static int handle_request_callback(void *cls, + struct MHD_Connection *con, + const char *url, + const char *method, + const char *version, + const char *data, + unsigned int *data_size, + void **ptr) { - struct conn_t *conn = (struct conn_t*)cls; + Environment *env = (Environment *)cls; PRACRO_DEBUG(httpd, "handle_request(url=\"%s\", method=\"%s\"," " version=\"%s\", data_size=\"%d\")\n", url, method, version, *data_size); - sessionid_t sessionid; - bool commitsession = false; - bool sid_ok = true; - - const char *sessionids = MHD_lookup_connection_value(con, MHD_HEADER_KIND, "SessionID"); - if(sessionids == NULL) { - sessionid = 42;//newSessionID(conn); - } else { - sessionid = atoll(sessionids); - conn->mutex.lock(); - sid_ok = conn->sessions.find(sessionid) != conn->sessions.end(); - conn->mutex.unlock(); - } - PRACRO_DEBUG(httpd, "SessionID: %llu\n", sessionid); - const char *session_commit = MHD_lookup_connection_value(con, MHD_HEADER_KIND, "SessionCommit"); - if(session_commit) { - PRACRO_DEBUG(httpd, "COMMIT: sessionid %llu\n", sessionid); - commitsession = true; - } + const char *sessionid = + MHD_lookup_connection_value(con, MHD_HEADER_KIND, "SessionID"); + const char *sessioncommit = + MHD_lookup_connection_value(con, MHD_HEADER_KIND, "SessionCommit"); - std::string reply; - if(sid_ok) { - reply = handleConnection(data, *data_size, conn, sessionid, commitsession); - } else { - PRACRO_ERR(httpd, "No such sessionid %llu\n", sessionid); - reply = error_box("No such session ID!"); - } + std::string reply = + handleConnection(data, *data_size, *env, (char**)&sessionid, sessioncommit); - struct MHD_Response *rsp; - rsp = MHD_create_response_from_data(reply.length(), (char*)reply.c_str(), MHD_NO, MHD_YES); + struct MHD_Response *rsp = + MHD_create_response_from_data(reply.length(), (char*)reply.c_str(), MHD_NO, MHD_YES); MHD_add_response_header(rsp, MHD_HTTP_HEADER_CONTENT_TYPE, "text/plain; charset=UTF-8"); - char idbuf[32]; - snprintf(idbuf, sizeof(idbuf), "%llu", sessionid); - MHD_add_response_header(rsp, "SessionID", idbuf); + if(*sessionid) { + MHD_add_response_header(rsp, "SessionID", sessionid); + free((char*)sessionid); + } int ret = MHD_queue_response(con, MHD_HTTP_OK, rsp); MHD_destroy_response(rsp); @@ -221,13 +188,11 @@ void server() PRACRO_DEBUG(server, "Server running on port %d.\n", port); - struct conn_t conn; - conn.db = new Database(Conf::database_backend, Conf::database_addr, - "", Conf::database_user, Conf::database_passwd, ""); + Environment env; struct MHD_Daemon *d; d = MHD_start_daemon(flags, port, NULL, NULL, - handle_request, &conn, + handle_request_callback, &env, MHD_OPTION_NOTIFY_COMPLETED, NULL, NULL, MHD_OPTION_CONNECTION_LIMIT, Conf::connection_limit, #ifndef WITHOUT_SSL @@ -245,11 +210,11 @@ void server() again: while(pracro_is_running) sleep(1); - if(!forceshutdown && conn.sessions.size() != 0) { + if(!forceshutdown && env.sessions.size() != 0) { char *errbuf; if(asprintf(&errbuf, "There are %d live sessions." " Kill again to force shutdown.\n", - conn.sessions.size()) != -1) { + env.sessions.size()) != -1) { PRACRO_ERR_LOG(server, "%s", errbuf); log(errbuf); free(errbuf); @@ -258,7 +223,6 @@ void server() forceshutdown = true; goto again; } - delete conn.db; MHD_stop_daemon(d); diff --git a/server/src/session.cc b/server/src/session.cc index 0e8679c..b53df1a 100644 --- a/server/src/session.cc +++ b/server/src/session.cc @@ -29,22 +29,14 @@ #include -#include "journal_commit.h" - -static std::string newSessionID(std::map &sessions) -{ - char sid[32]; - do { - snprintf(sid, sizeof(sid)-1, "%d", rand()); - } while(sessions.find(sid) != sessions.end()); - return sid; -} - +#include "journalwriter.h" +#include "configuration.h" +#include "connectionpool.h" Session::Session(std::string sessionid) { _id = sessionid; - journal = NULL; + _journal = NULL; } std::string Session::id() @@ -52,13 +44,46 @@ std::string Session::id() return _id; } +void Session::lock() +{ + mutex.lock(); +} + +void Session::unlock() +{ + mutex.unlock(); +} + +void Session::commit() +{ + if(_journal != NULL) { + _journal->commit(); + delete _journal; + _journal = NULL; + } +} + +JournalWriter *Session::journal() +{ + if(_journal == NULL) { + _journal = + new JournalWriter(Conf::journal_commit_addr, Conf::journal_commit_port); + } + return _journal; +} + Sessions::Sessions() { } Session *Sessions::newSession() { - Session *session = new Session(newSessionID(sessions)); + char sessionid[32]; + do { + snprintf(sessionid, sizeof(sessionid)-1, "%d", rand()); + } while(sessions.find(sessionid) != sessions.end()); + + Session *session = new Session(sessionid); sessions[session->id()] = session; return session; } @@ -84,10 +109,15 @@ void Sessions::deleteSession(std::string sessionid) if(s) delete s; } +size_t Sessions::size() +{ + return sessions.size(); +} + #ifdef TEST_SESSION -//deps: -//cflags: -//libs: +//deps: configuration.cc journalwriter.cc journal_commit.cc mutex.cc debug.cc +//cflags: -I.. +//libs: -lpthread #include TEST_BEGIN; @@ -100,6 +130,8 @@ Session *s2 = sessions.newSession(); TEST_NOTEQUAL(s1->id(), s2->id(), "Testing if IDs are unique."); +TEST_EQUAL(sessions.size(), 2, "Testing if size match."); + TEST_END; #endif/*TEST_SESSION*/ diff --git a/server/src/session.h b/server/src/session.h index a4d93f4..12c831a 100644 --- a/server/src/session.h +++ b/server/src/session.h @@ -31,6 +31,8 @@ #include #include +#include "mutex.h" + class JournalWriter; class Session { @@ -38,10 +40,18 @@ public: Session(std::string sessionid); std::string id(); + + void lock(); + void unlock(); + + void commit(); + + JournalWriter *journal(); private: - JournalWriter *journal; + JournalWriter *_journal; std::string _id; + Mutex mutex; }; class Sessions { @@ -71,9 +81,13 @@ public: */ void deleteSession(std::string sessionid); + /** + * Return number of active sessions. + */ + size_t size(); + private: std::map sessions; - }; diff --git a/server/src/transactionhandler.cc b/server/src/transactionhandler.cc index 06e5be4..65da013 100644 --- a/server/src/transactionhandler.cc +++ b/server/src/transactionhandler.cc @@ -36,6 +36,7 @@ #include "queryhandlerpracro.h" #include "xml_encode_decode.h" #include "widgetgenerator.h" +#include "journalwriter.h" static std::string error_box(std::string message) { @@ -47,205 +48,207 @@ static std::string error_box(std::string message) return errorbox; } -static std::string handleCommits(Transaction *transaction, Database &db, - JournalWriter &journalwriter, MacroList ¯olist, - TemplateList &templatelist) +static std::string handleCommits(Transaction &transaction, Environment &env, Session &session) { std::string answer; - Commits::iterator i = transaction->commits.begin(); - while(i != transaction->commits.end()) { - Commit &commit = *i; - - MacroParser mp(macrolist.getLatestVersion(commit.macro)); - mp.parse(); - Macro *macro = mp.getMacro(); - - std::string resume = resume_parser(macro->resume, commit); - commit.fields["journal.resume"] = resume; - db.commitTransaction(transaction->user, transaction->cpr, *macro, commit.fields); - - if(resume != "") { + if(transaction.commits.size() > 0) { + AutoBorrower borrower(env.dbpool); + Database *db = borrower.get(); - TemplateParser tp(templatelist.getLatestVersion(commit.templ)); - tp.parse(); - Template *templ = tp.getTemplate(); - - journalwriter.addEntry(*transaction, commit, resume, templ); + Commits::iterator i = transaction.commits.begin(); + while(i != transaction.commits.end()) { + Commit &commit = *i; + + MacroParser mp(env.macrolist.getLatestVersion(commit.macro)); + mp.parse(); + Macro *macro = mp.getMacro(); + + std::string resume = resume_parser(macro->resume, commit); + commit.fields["journal.resume"] = resume; + db->commitTransaction(transaction.user, transaction.cpr, *macro, commit.fields); + + if(resume != "") { + + TemplateParser tp(env.templatelist.getLatestVersion(commit.templ)); + tp.parse(); + Template *templ = tp.getTemplate(); + + session.journal()->addEntry(transaction, commit, resume, templ); + } + + i++; } - - i++; } return answer; } - -static std::string handleRequest(Transaction *transaction, - TCPSocket &pentominos_socket, - Database &db, - MacroList ¯olist, - TemplateList &templatelist) +static std::string handleRequest(Transaction &transaction, Environment &env, Session &session) { std::string answer; - Requests::iterator i = transaction->requests.begin(); - while(i != transaction->requests.end()) { - Request &request = *i; + if(transaction.requests.size() > 0) { + + AutoBorrower borrower(env.dbpool); + Database *db = borrower.get(); - PRACRO_DEBUG(server, "Handling request - macro: %s, template: %s\n", - request.macro.c_str(), request.templ.c_str()); + Requests::iterator i = transaction.requests.begin(); + while(i != transaction.requests.end()) { + Request &request = *i; - // Read and parse the template file. - TemplateParser tp(templatelist.getLatestVersion(request.templ)); - tp.parse(); + PRACRO_DEBUG(server, "Handling request - macro: %s, template: %s\n", + request.macro.c_str(), request.templ.c_str()); - Template *templ = tp.getTemplate(); + // Read and parse the template file. + TemplateParser tp(env.templatelist.getLatestVersion(request.templ)); + tp.parse(); + + Template *templ = tp.getTemplate(); - answer += " \n"; - i++; + i++; + } } return answer; } -std::string handleTransaction(Transaction *transaction, - TCPSocket &pentominos_socket, - Database &db, - JournalWriter &journalwriter, - MacroList ¯olist, - TemplateList &templatelist) +std::string handleTransaction(Transaction &transaction, Environment &env, Session &session) { std::string answer; + answer += "\n"; answer += "\n"; try { - answer += handleCommits(transaction, db, - journalwriter, macrolist, templatelist); + answer += handleCommits(transaction, env, session); } catch( std::exception &e ) { PRACRO_ERR(server, "Commit error: %s\n", e.what()); return error_box(xml_encode(e.what())); } try { - answer += handleRequest(transaction, pentominos_socket, db, macrolist, templatelist); + answer += handleRequest(transaction, env, session); } catch( std::exception &e ) { PRACRO_ERR(server, "Request error: %s\n", e.what()); return error_box(xml_encode(e.what())); @@ -255,6 +258,7 @@ std::string handleTransaction(Transaction *transaction, PRACRO_DEBUG(server, "Done handling transaction\n"); PRACRO_DEBUG(serverxml, "%s\n", answer.c_str()); + return answer; } diff --git a/server/src/transactionhandler.h b/server/src/transactionhandler.h index 9a2086a..ae1857c 100644 --- a/server/src/transactionhandler.h +++ b/server/src/transactionhandler.h @@ -28,13 +28,11 @@ #ifndef __PRACRO_TRANSACTIONHANDLER_H__ #define __PRACRO_TRANSACTIONHANDLER_H__ -#include "exception.h" #include "transaction.h" -#include "tcpsocket.h" -#include "database.h" -#include "journal_commit.h" -#include "macrolist.h" -#include "templatelist.h" +#include "session.h" +#include "environment.h" + +#include "exception.h" class NotFoundException : public Exception { public: @@ -42,11 +40,6 @@ public: : Exception("Macro " + r.macro + " not found in template " + r.templ) {} }; -std::string handleTransaction(Transaction *transaction, - TCPSocket &pentominos_socket, - Database &db, - JournalWriter &journalwriter, - MacroList ¯olist, - TemplateList &templatelist); +std::string handleTransaction(Transaction &transaction, Environment &env, Session &session); #endif/*__PRACRO_TRANSACTIONHANDLER_H__*/ -- cgit v1.2.3