diff options
-rw-r--r-- | server/src/connection.cc | 19 | ||||
-rw-r--r-- | server/src/connection.h | 5 | ||||
-rw-r--r-- | server/src/database.h | 48 | ||||
-rw-r--r-- | server/src/journal.cc | 36 | ||||
-rw-r--r-- | server/src/journal.h | 4 | ||||
-rw-r--r-- | server/src/journal_commit.cc | 10 | ||||
-rw-r--r-- | server/src/journal_uploadserver.cc | 4 | ||||
-rw-r--r-- | server/src/pracrodao.h | 15 | ||||
-rw-r--r-- | server/src/pracrodaopgsql.cc | 231 | ||||
-rw-r--r-- | server/src/pracrodaopgsql.h | 22 | ||||
-rw-r--r-- | server/src/pracrodaotest.cc | 16 | ||||
-rw-r--r-- | server/src/pracrodaotest.h | 16 | ||||
-rw-r--r-- | server/src/server.cc | 4 | ||||
-rw-r--r-- | server/src/session.cc | 42 | ||||
-rw-r--r-- | server/src/session.h | 4 | ||||
-rw-r--r-- | server/src/sessionserialiser.cc | 24 | ||||
-rw-r--r-- | server/src/sessionserialiser.h | 11 | ||||
-rw-r--r-- | server/src/transactionhandler.cc | 19 |
18 files changed, 355 insertions, 175 deletions
diff --git a/server/src/connection.cc b/server/src/connection.cc index 849a90c..dd76f97 100644 --- a/server/src/connection.cc +++ b/server/src/connection.cc @@ -44,7 +44,7 @@ static std::string error_box(std::string message) static bool did_commit = false; #endif -Connection::Connection(Environment &e, std::string sid, bool c, bool d) +Connection::Connection(Environment &e, std::string sid, bool c, bool d, bool nc) : env(e), parser(&transaction) { DEBUG(connection, "[%p] CREATE\n", this); @@ -52,6 +52,7 @@ Connection::Connection(Environment &e, std::string sid, bool c, bool d) sessionid = sid; docommit = c; dodiscard = d; + donocommit = nc; #ifdef TEST_CONNECTION did_commit = false; @@ -65,11 +66,20 @@ Connection::~Connection() DEBUG(connection, "[%p] DESTROY\n", this); } +void Connection::nocommit(Session *session) +{ + if(donocommit) { + donocommit = false; + session->nocommit(); + } +} + void Connection::commit(Session *session) { if(docommit) { + std::string sid = session->id(); session->commit(); - env.sessions.deleteSession(session->id()); + env.sessions.deleteSession(sid); sessionid = ""; docommit = false; #ifdef TEST_CONNECTION @@ -81,8 +91,9 @@ void Connection::commit(Session *session) void Connection::discard(Session *session) { if(dodiscard) { + std::string sid = session->id(); session->discard(); - env.sessions.deleteSession(session->id()); + env.sessions.deleteSession(sid); sessionid = ""; dodiscard = false; } @@ -116,6 +127,7 @@ bool Connection::handle(const char *data, size_t size) parser_complete = true; commit(session); discard(session); + nocommit(session); return true; } @@ -129,6 +141,7 @@ bool Connection::handle(const char *data, size_t size) commit(session); discard(session); + nocommit(session); return true; } diff --git a/server/src/connection.h b/server/src/connection.h index f1735a8..010034e 100644 --- a/server/src/connection.h +++ b/server/src/connection.h @@ -37,7 +37,8 @@ class Session; class Connection { public: - Connection(Environment &e, std::string sessionid, bool commit, bool discard); + Connection(Environment &e, std::string sessionid, + bool commit, bool discard, bool nocommit); ~Connection(); bool handle(const char *data, size_t size); @@ -47,10 +48,12 @@ public: private: void commit(Session *session); + void nocommit(Session *session); void discard(Session *session); std::string sessionid; bool docommit; + bool donocommit; bool dodiscard; Environment &env; diff --git a/server/src/database.h b/server/src/database.h index 0bc37c0..a366f43 100644 --- a/server/src/database.h +++ b/server/src/database.h @@ -42,29 +42,44 @@ public: std::string _passwd, std::string _dbname); ~Database(); + std::string sessionId() + { + if(dao && sessionid == "") { + sessionid = dao->newSessionId(); + } + return sessionid; + } + + void setSessionId(std::string sessionid) + { + this->sessionid = sessionid; + } + // Make a commit to the db void commitTransaction(Transaction &transaction, Commit &commit, Macro ¯o, - time_t now = time(NULL)) { + time_t now = time(NULL)) + { if(!dao) return; mutex.lock(); DEBUG(db, "%s, %s, %s,...\n", transaction.user.c_str(), transaction.cpr.c_str(), macro.attributes["name"].c_str()); - dao->commitTransaction(transaction, commit, macro, now); + dao->commitTransaction(sessionId(), transaction, commit, macro, now); mutex.unlock(); } // Get a list of values from the db Values getValues(std::string patientid, Fieldnames &fieldnames, - time_t oldest = 0) { + time_t oldest = 0) + { if(!dao) return Values(); mutex.lock(); DEBUG(db, "%s, <%u fieldnames>, %ld\n", patientid.c_str(), fieldnames.size(), oldest); - Values values = dao->getLatestValues(patientid, NULL, fieldnames, oldest); + Values values = dao->getLatestValues(sessionid, patientid, NULL, fieldnames, oldest); mutex.unlock(); return values; } @@ -72,25 +87,27 @@ public: // Check if a macro has been committed. bool checkMacro(std::string patientid, std::string macro, - time_t oldest = 0) { + time_t oldest = 0) + { DEBUG(db, "%s, %s, %ld\n", patientid.c_str(), macro.c_str(), oldest); if(!dao) return false; mutex.lock(); - bool res = dao->nrOfCommits(patientid, macro, oldest) > 0; + bool res = dao->nrOfCommits(sessionid, patientid, macro, oldest) > 0; mutex.unlock(); return res; } // Get latest resume of a given macro - std::string getResume(std::string patientid, Macro ¯o, time_t oldest) { + std::string getResume(std::string patientid, Macro ¯o, time_t oldest) + { DEBUG(db, "%s, %s, %ld\n", patientid.c_str(), macro.attributes["name"].c_str(), oldest); if(!dao) return ""; Fieldnames fn; fn.push_back("journal.resume"); mutex.lock(); - Values v = dao->getLatestValues(patientid, ¯o, fn, oldest); + Values v = dao->getLatestValues(sessionid, patientid, ¯o, fn, oldest); mutex.unlock(); Values::iterator i = v.find("journal.resume"); if(i != v.end()) return i->second.value; @@ -127,14 +144,20 @@ public: void commit() { - if(!dao) return; - return dao->commit(); + if(!dao || sessionid == "") return; + return dao->commit(sessionId()); + } + + void nocommit() + { + if(!dao || sessionid == "") return; + return dao->nocommit(sessionId()); } void discard() { - if(!dao) return; - return dao->discard(); + if(!dao || sessionid == "") return; + return dao->discard(sessionId()); } std::string serialise() @@ -152,6 +175,7 @@ public: private: PracroDAO *dao; Mutex mutex; + std::string sessionid; }; #endif/*__PRACRO_DATABASE_H__*/ diff --git a/server/src/journal.cc b/server/src/journal.cc index 1f79c9f..70dba2f 100644 --- a/server/src/journal.cc +++ b/server/src/journal.cc @@ -79,14 +79,19 @@ void Journal::addEntry(std::string resume, std::string macro, int index) std::string r = resume; std::string m = macro; + DEBUG(journal, "Add: %p %s - %s\n", this, m.c_str(), r.c_str()); + ResumeEntry re; re.resume = r; re.macro = m; + re.dirty = false; entrylist[index] = re; } std::string Journal::getEntry(std::string macro) { + DEBUG(journal, "Get: %p %s\n", this, macro.c_str()); + std::map< int, ResumeEntry >::iterator i = entrylist.begin(); while(i != entrylist.end()) { if(i->second.macro == macro) return i->second.resume; @@ -97,6 +102,8 @@ std::string Journal::getEntry(std::string macro) void Journal::removeEntry(std::string macro) { + DEBUG(journal, "Remove: %p %s\n", this, macro.c_str()); + std::map< int, ResumeEntry >::iterator i = entrylist.begin(); while(i != entrylist.end()) { if(i->second.macro == macro) { @@ -107,6 +114,31 @@ void Journal::removeEntry(std::string macro) } } +void Journal::setDirty(std::string macro) +{ + std::map< int, ResumeEntry >::iterator i = entrylist.begin(); + while(i != entrylist.end()) { + if(i->second.macro == macro) { + i->second.dirty = true; + break; + } + i++; + } +} + +bool Journal::dirty(std::string macro) +{ + std::map< int, ResumeEntry >::iterator i = entrylist.begin(); + while(i != entrylist.end()) { + if(i->second.macro == macro) { + return i->second.dirty; + break; + } + i++; + } + return false; +} + void Journal::setUser(std::string usr) { _user = usr; @@ -126,7 +158,3 @@ std::string Journal::patientID() { return _patientid; } - -#ifdef TEST_JOURNAL - -#endif/*TEST_JOURNAL*/ diff --git a/server/src/journal.h b/server/src/journal.h index 3fbbbd6..fe1a4bd 100644 --- a/server/src/journal.h +++ b/server/src/journal.h @@ -52,6 +52,9 @@ public: std::string getEntry(std::string macro); void removeEntry(std::string macro); + void setDirty(std::string macro); + bool dirty(std::string macro); + void setUser(std::string user); std::string user(); @@ -63,6 +66,7 @@ protected: public: std::string resume; std::string macro; + bool dirty; }; std::string _user; diff --git a/server/src/journal_commit.cc b/server/src/journal_commit.cc index 734afcf..c81ff09 100644 --- a/server/src/journal_commit.cc +++ b/server/src/journal_commit.cc @@ -143,13 +143,3 @@ int journal_commit(const char *cpr, const char *user, return 0; } - -#ifdef TEST_JOURNAL_COMMIT - -int main() -{ - return 0; -} - -#endif/*TEST_JOURNAL_COMMIT*/ - diff --git a/server/src/journal_uploadserver.cc b/server/src/journal_uploadserver.cc index ce88f02..9988c81 100644 --- a/server/src/journal_uploadserver.cc +++ b/server/src/journal_uploadserver.cc @@ -167,6 +167,10 @@ void JournalUploadServer::commit() // Iterate through all resumes, and create a string containing them all. std::map< int, ResumeEntry >::iterator i = entrylist.begin(); while(i != entrylist.end()) { + if(i->second.dirty) { + i++; + continue; + } if(resume != "") resume += "\n\n"; // resume += i->macro + "\n"; resume += stripTrailingWhitepace(addNewlines(i->second.resume, 60)); diff --git a/server/src/pracrodao.h b/server/src/pracrodao.h index 83bd017..3371e2c 100644 --- a/server/src/pracrodao.h +++ b/server/src/pracrodao.h @@ -42,15 +42,19 @@ public: std::string _user, std::string _passwd, std::string _dbname); virtual ~PracroDAO(); - virtual void commitTransaction(Transaction &transaction, + virtual std::string newSessionId() = 0; + virtual void commitTransaction(std::string sessionid, + Transaction &transaction, Commit &commit, Macro ¯o, time_t now) = 0; - virtual Values getLatestValues(std::string patientid, + virtual Values getLatestValues(std::string sessionid, + std::string patientid, Macro *macro, Fieldnames &fieldnames, time_t oldest) = 0; - virtual unsigned nrOfCommits(std::string patientid, + virtual unsigned nrOfCommits(std::string sessionid, + std::string patientid, std::string macroname, time_t oldest) = 0; @@ -59,8 +63,9 @@ public: virtual void delFieldname(std::string name) = 0; virtual std::vector<Fieldname> getFieldnames() = 0; - virtual void commit() = 0; - virtual void discard() = 0; + virtual void commit(std::string sessionid) = 0; + virtual void nocommit(std::string sessionid) = 0; + virtual void discard(std::string sessionid) = 0; virtual std::string serialise() = 0; virtual void restore(const std::string &data) = 0; diff --git a/server/src/pracrodaopgsql.cc b/server/src/pracrodaopgsql.cc index 1c96035..14cb9c1 100644 --- a/server/src/pracrodaopgsql.cc +++ b/server/src/pracrodaopgsql.cc @@ -60,8 +60,7 @@ PracroDAOPgsql::PracroDAOPgsql(std::string _host, std::string _port, cs += " dbname=" + (dbname.size() ? dbname : "pracro"); try { conn = new pqxx::connection(cs); - W = new pqxx::work(*conn); - + /* std::string ts; try { ts = "BEGIN;"; @@ -69,6 +68,7 @@ PracroDAOPgsql::PracroDAOPgsql(std::string _host, std::string _port, pqxx::result R = W->exec(ts); } catch(...) { } + */ } catch(std::exception &e) { ERR_LOG(db, "Postgresql init failed: %s\n", e.what()); conn = NULL; @@ -80,59 +80,114 @@ PracroDAOPgsql::PracroDAOPgsql(std::string _host, std::string _port, PracroDAOPgsql::~PracroDAOPgsql() { if(conn) { - if(W) delete W; + // if(W) delete W; delete conn; } } -void PracroDAOPgsql::commitTransaction(Transaction &transaction, +std::string PracroDAOPgsql::newSessionId() +{ + if(!conn) { + ERR(db, "No pgsql connection\n"); + return ""; + } + + pqxx::work W(*conn); + pqxx::result R = W.exec("SELECT nextval('sessionseq');"); + pqxx::result::const_iterator ri = R.begin(); + if(ri != R.end()) { + DEBUG(db, "New session id: %s\n", (*ri)[0].c_str()); + return (*ri)[0].c_str(); + } + ERR(db, "No pgsql connection\n"); + return ""; +} + +void PracroDAOPgsql::commitTransaction(std::string sessionid, + Transaction &transaction, Commit &commit, Macro &_macro, time_t now) { - DEBUG(db, "(%s, %s, %s, <%u fields>, %ld)\n", + DEBUG(db, "commitTransaction (%s, %s, %s, <%u fields>, %ld)\n", transaction.user.c_str(), transaction.cpr.c_str(), _macro.attributes["name"].c_str(), commit.fields.size(), now); - if(!conn) DEBUG(db, "No pgsql connection\n"); + if(!conn) { + ERR(db, "No pgsql connection\n"); + return; + } + if(commit.fields.size() == 0) return; + pqxx::work W(*conn); + std::string version = _macro.attributes["version"]; std::string macro = _macro.attributes["name"]; std::stringstream timestamp; timestamp << now; std::string ts; + + ts = "SELECT status FROM commits WHERE uid='"+sessionid+"';"; + pqxx::result R = W.exec(ts); + if(!R.size()) { + ts = "INSERT INTO commits (patientid, template, version," + " \"timestamp\", uid, status) VALUES (" + " '" + W.esc(transaction.cpr) + "', " + " '" + W.esc(commit.templ) + "', " + " '" + "1.0" + "', " + " '" + W.esc(timestamp.str()) + "', " + " '" + W.esc(sessionid) + "', " + " 'active' " + ");" + ; + DEBUG(sql, "Query: %s\n", ts.c_str()); + pqxx::result R = W.exec(ts); + } else { + + pqxx::result::const_iterator ri = R.begin(); + if(ri != R.end()) { + std::string status = (*ri)[0].c_str(); + if(status == "committed") { + ERR_LOG(db, "Attempt to add to committed session %s blocked!\n", + sessionid.c_str()); + return; + } + } + + ts = "UPDATE commits SET status='active' WHERE uid="+sessionid+";"; + DEBUG(sql, "Query: %s\n", ts.c_str()); + /*pqxx::result R = */W.exec(ts); + } + try { - ts = "INSERT INTO transactions (uid, patientid, template, macro, version," - " \"timestamp\", \"user\") VALUES (" + ts = "INSERT INTO transactions (uid, macro, version," + " \"timestamp\", \"user\", cid) VALUES (" " nextval('trseq'), " - " '" + W->esc(transaction.cpr) + "', " - " '" + W->esc(commit.templ) + "', " - " '" + W->esc(macro) + "', " - " '" + W->esc(version) + "', " - " '" + W->esc(timestamp.str()) + "', " - " '" + W->esc(transaction.user) + "' " + " '" + W.esc(macro) + "', " + " '" + W.esc(version) + "', " + " '" + W.esc(timestamp.str()) + "', " + " '" + W.esc(transaction.user) + "', " + " '" + W.esc(sessionid) + "' " ");" ; DEBUG(sql, "Query: %s\n", ts.c_str()); - pqxx::result R = W->exec(ts); - statements += ts + "\n"; + pqxx::result R = W.exec(ts); if(commit.fields.size() > 0) { // field table lookup - ts = "SELECT name FROM fieldnames WHERE name IN ( "; + ts = "SELECT DISTINCT name FROM fieldnames WHERE name IN ( "; std::map< std::string, std::string >::iterator i = commit.fields.begin(); - ts += "'" + W->esc(i->first) + "'"; + ts += "'" + W.esc(i->first) + "'"; i++; while(i != commit.fields.end()) { - ts += ", '" + W->esc(i->first) + "'"; + ts += ", '" + W.esc(i->first) + "'"; i++; } ts += ");"; DEBUG(sql, "Query: %s\n", ts.c_str()); - R = W->exec(ts); - // statements += ts + "\n"; + R = W.exec(ts); DEBUG(db, "input fields: %d, output fields: %lu\n", commit.fields.size(), R.size()); @@ -144,8 +199,8 @@ void PracroDAOPgsql::commitTransaction(Transaction &transaction, DEBUG(db, "Storing: %s with value %s\n", name.c_str(), commit.fields[name].c_str()); ts = "INSERT INTO fields (transaction, name, value) " - "VALUES ( currval('trseq'), '" + W->esc(name) + "', '" + - W->esc(commit.fields[name]) + "')"; + "VALUES ( currval('trseq'), '" + W.esc(name) + "', '" + + W.esc(commit.fields[name]) + "')"; ri++; while(ri != R.end()) { name = (*ri)[0].c_str(); @@ -153,21 +208,22 @@ void PracroDAOPgsql::commitTransaction(Transaction &transaction, DEBUG(db, "Storing: %s with value %s\n", name.c_str(), commit.fields[name].c_str()); - ts += ", (currval('trseq'), '" + W->esc(name) + "', '" + - W->esc(commit.fields[name]) + "')"; + ts += ", (currval('trseq'), '" + W.esc(name) + "', '" + + W.esc(commit.fields[name]) + "')"; ri++; } ts += ";"; DEBUG(sql, "Query: %s\n", ts.c_str()); - W->exec(ts); - statements += ts + "\n"; - + W.exec(ts); } } - // W->commit(); + + W.commit(); + } catch(std::exception &e) { ERR_LOG(db, "Query failed: %s: %s\n", e.what(), ts.c_str()); } + } @@ -192,11 +248,15 @@ void PracroDAOPgsql::commitTransaction(Transaction &transaction, * AND tt.uid = ff.transaction * AND tt.patientid = '1505050505' */ -Values PracroDAOPgsql::getLatestValues(std::string patientid, +Values PracroDAOPgsql::getLatestValues(std::string sessionid, + std::string patientid, Macro *macro, Fieldnames &fieldnames, time_t oldest) { + + bool uncom = false; // get results that are not yet committed? + DEBUG(db, "(%s, %s, <%u fieldnames>, %ld)\n", patientid.c_str(), macro ? macro->attributes["name"].c_str() : "(null)", @@ -207,23 +267,37 @@ Values PracroDAOPgsql::getLatestValues(std::string patientid, std::string query; std::stringstream soldest; soldest << oldest; try { + { + pqxx::work W(*conn); + query = "UPDATE commits SET status='active' WHERE status='idle'" + " AND uid="+sessionid+";"; + DEBUG(sql, "Query: %s\n", query.c_str()); + /*pqxx::result R = */W.exec(query); + W.commit(); + } + + pqxx::work W(*conn); std::string namecond; if(fieldnames.size() > 0) { std::vector< std::string >::iterator i = fieldnames.begin(); - namecond += " AND f.name IN ('" + W->esc(*i) + "'"; + namecond += " AND f.name IN ('" + W.esc(*i) + "'"; i++; while(i != fieldnames.end()) { - namecond += ", '" + W->esc(*i) + "'"; + namecond += ", '" + W.esc(*i) + "'"; i++; } namecond += ')'; } query = "SELECT ff.name, ff.value, tt.timestamp FROM " // Begin inner query - " (SELECT f.name, MAX(t.timestamp) AS ts FROM fields f, transactions t " - " WHERE t.uid = f.transaction AND t.timestamp >= " + soldest.str() + - " AND t.patientid = '" + W->esc(patientid) + "' " + " (SELECT f.name, MAX(t.timestamp) AS ts " + " FROM commits c, fields f, transactions t " + " WHERE "; + if(!uncom) query += "(c.status='committed' OR c.uid="+sessionid+") AND "; + query += "c.uid = t.cid AND t.uid = f.transaction" + " AND t.timestamp >= " + soldest.str() + + " AND c.patientid = '" + W.esc(patientid) + "' " + namecond; if(macro) { query += " AND t.macro = '" + macro->attributes["name"] + "'"; @@ -232,11 +306,14 @@ Values PracroDAOPgsql::getLatestValues(std::string patientid, } query += " GROUP BY f.name) xx, " // End inner query - " transactions tt, fields ff " - " WHERE xx.ts = tt.timestamp " + " transactions tt, fields ff, commits cc " + " WHERE "; + if(!uncom) query += "(cc.status='committed' OR cc.uid="+sessionid+") AND "; + query += " xx.ts = tt.timestamp " " AND xx.name = ff.name " " AND tt.uid = ff.transaction " - " AND tt.patientid = '" + W->esc(patientid) + "' " + " AND tt.cid = cc.uid " + " AND cc.patientid = '" + W.esc(patientid) + "' " ; if(macro) { query += " AND tt.macro = '" + macro->attributes["name"] + "'"; @@ -245,7 +322,7 @@ Values PracroDAOPgsql::getLatestValues(std::string patientid, } DEBUG(sql, "Query: %s\n", query.c_str()); - pqxx::result R = W->exec(query); + pqxx::result R = W.exec(query); pqxx::result::const_iterator ri = R.begin(); while(ri != R.end()) { Value v; @@ -262,20 +339,26 @@ Values PracroDAOPgsql::getLatestValues(std::string patientid, } -unsigned PracroDAOPgsql::nrOfCommits(std::string patientid, +unsigned PracroDAOPgsql::nrOfCommits(std::string sessionid, + std::string patientid, std::string macroname, time_t oldest) { + + bool uncom = false; // get results that are not yet committed? + std::string query; std::stringstream soldest; soldest << oldest; try { - query = "SELECT count(*) FROM transactions " - " WHERE patientid = '" + W->esc(patientid) + "' " - " AND macro = '" + W->esc(macroname) + "' " - " AND timestamp >= " + soldest.str() + pqxx::work W(*conn); + query = "SELECT count(*) FROM commits c, transactions f" + " WHERE c.patientid = '" + W.esc(patientid) + "' AND c.uid = f.cid"; + if(!uncom) query += " AND (c.status='committed' OR c.uid="+sessionid+")"; + query += " AND f.macro = '" + W.esc(macroname) + "' " + " AND f.timestamp >= " + soldest.str() ; DEBUG(sql, "Query: %s\n", query.c_str()); - pqxx::result R = W->exec(query); + pqxx::result R = W.exec(query); if(R.size() != 1) { ERR_LOG(db, "No result set; expected one row with one column\n"); return 0; @@ -296,15 +379,16 @@ void PracroDAOPgsql::addFieldname(std::string name, std::string description) std::stringstream timestamp; timestamp << time(NULL); std::string ts; try { + pqxx::work W(*conn); ts = "INSERT INTO fieldnames (name, description, \"timestamp\") VALUES (" - " '" + W->esc(name) + "', " - " '" + W->esc(description) + "', " - " '" + W->esc(timestamp.str()) + "' " + " '" + W.esc(name) + "', " + " '" + W.esc(description) + "', " + " '" + W.esc(timestamp.str()) + "' " ")" ; DEBUG(sql, "Query: %s\n", ts.c_str()); - pqxx::result R = W->exec(ts); - W->commit(); + pqxx::result R = W.exec(ts); + W.commit(); } catch (std::exception &e) { ERR_LOG(db, "Query failed: %s: %s\n", e.what(), ts.c_str()); } @@ -314,11 +398,12 @@ void PracroDAOPgsql::delFieldname(std::string name) { std::string ts; try { + pqxx::work W(*conn); ts = "DELETE FROM fieldnames WHERE name=" - "'" + W->esc(name) + "' "; + "'" + W.esc(name) + "' "; DEBUG(sql, "Query: %s\n", ts.c_str()); - pqxx::result R = W->exec(ts); - W->commit(); + pqxx::result R = W.exec(ts); + W.commit(); } catch (std::exception &e) { ERR_LOG(db, "Query failed: %s: %s\n", e.what(), ts.c_str()); } @@ -331,9 +416,10 @@ std::vector<Fieldname> PracroDAOPgsql::getFieldnames() std::string query; try { + pqxx::work W(*conn); query = "SELECT * FROM fieldnames"; DEBUG(sql, "Query: %s\n", query.c_str()); - pqxx::result R = W->exec(query); + pqxx::result R = W.exec(query); pqxx::result::const_iterator ri = R.begin(); while(ri != R.end()) { Fieldname f; @@ -350,41 +436,44 @@ std::vector<Fieldname> PracroDAOPgsql::getFieldnames() return fieldnames; } -void PracroDAOPgsql::commit() +void PracroDAOPgsql::commit(std::string sessionid) { std::string ts; try { - W->commit(); - statements = ""; + pqxx::work W(*conn); + ts = "UPDATE commits SET status='committed' WHERE uid="+sessionid+";"; + /*pqxx::result R = */W.exec(ts); + + W.commit(); } catch (std::exception &e) { ERR_LOG(db, "Commit failed: %s: %s\n", e.what(), ts.c_str()); } } -void PracroDAOPgsql::discard() +void PracroDAOPgsql::nocommit(std::string sessionid) { std::string ts; try { - W->abort(); - statements = ""; + pqxx::work W(*conn); + ts = "UPDATE commits SET status='idle' WHERE uid="+sessionid+";"; + /*pqxx::result R = */W.exec(ts); + + W.commit(); } catch (std::exception &e) { - ERR_LOG(db, "Abort (rollback) failed: %s: %s\n", e.what(), ts.c_str()); + ERR_LOG(db, "NoCommit failed: %s: %s\n", e.what(), ts.c_str()); } } -std::string PracroDAOPgsql::serialise() -{ - return statements; -} - -void PracroDAOPgsql::restore(const std::string &data) +void PracroDAOPgsql::discard(std::string sessionid) { std::string ts; try { - DEBUG(sql, "Restore: %s\n", data.c_str()); - pqxx::result R = W->exec(data); - statements = data; - } catch( ... ) { + pqxx::work W(*conn); + ts = "DELETE FROM commits WHERE uid="+sessionid+";"; + /*pqxx::result R = */W.exec(ts); + W.commit(); + } catch (std::exception &e) { + ERR_LOG(db, "Abort (rollback) failed: %s: %s\n", e.what(), ts.c_str()); } } diff --git a/server/src/pracrodaopgsql.h b/server/src/pracrodaopgsql.h index e15a22b..e3664f9 100644 --- a/server/src/pracrodaopgsql.h +++ b/server/src/pracrodaopgsql.h @@ -44,15 +44,19 @@ public: std::string _user, std::string _passwd, std::string _dbname); ~PracroDAOPgsql(); - void commitTransaction(Transaction &transaction, + std::string newSessionId(); + void commitTransaction(std::string sessionid, + Transaction &transaction, Commit &commit, Macro ¯o, time_t now); - Values getLatestValues(std::string patientid, + Values getLatestValues(std::string sessionid, + std::string patientid, Macro *macro, Fieldnames &fieldnames, time_t oldest); - unsigned nrOfCommits(std::string patientid, + unsigned nrOfCommits(std::string sessionid, + std::string patientid, std::string macroname, time_t oldest); @@ -60,16 +64,14 @@ public: void delFieldname(std::string name); std::vector<Fieldname> getFieldnames(); - void commit(); - void discard(); - std::string serialise(); - void restore(const std::string &data); + void commit(std::string sessionid); + void nocommit(std::string sessionid); + void discard(std::string sessionid); + std::string serialise() { return ""; } + void restore(const std::string &data) {} private: pqxx::connection *conn; - pqxx::work *W; - - std::string statements; }; #endif/*WITHOUT_DB*/ diff --git a/server/src/pracrodaotest.cc b/server/src/pracrodaotest.cc index 45cafc7..ec9c293 100644 --- a/server/src/pracrodaotest.cc +++ b/server/src/pracrodaotest.cc @@ -45,7 +45,13 @@ PracroDAOTest::~PracroDAOTest() DEBUG(db, "Delete test (memory only) database\n"); } -void PracroDAOTest::commitTransaction(Transaction &transaction, +std::string PracroDAOTest::newSessionId() +{ + return data.sessionseq.nextval(); +} + +void PracroDAOTest::commitTransaction(std::string sessionid, + Transaction &transaction, Commit &commit, Macro &_macro, time_t now) @@ -106,7 +112,8 @@ void PracroDAOTest::commitTransaction(Transaction &transaction, } } -Values PracroDAOTest::getLatestValues(std::string patientid, Macro *macro, +Values PracroDAOTest::getLatestValues(std::string sessionid, + std::string patientid, Macro *macro, Fieldnames &fieldnames, time_t oldest) { std::string macro_name = macro ? macro->attributes["name"].c_str() : "(null)"; @@ -158,7 +165,10 @@ Values PracroDAOTest::getLatestValues(std::string patientid, Macro *macro, } -unsigned PracroDAOTest::nrOfCommits(std::string patientid, std::string macroname, time_t oldest) +unsigned PracroDAOTest::nrOfCommits(std::string sessionid, + std::string patientid, + std::string macroname, + time_t oldest) { unsigned num = 0; diff --git a/server/src/pracrodaotest.h b/server/src/pracrodaotest.h index 34886d0..0bd9be5 100644 --- a/server/src/pracrodaotest.h +++ b/server/src/pracrodaotest.h @@ -66,6 +66,7 @@ private: class Data { public: + dbcounter_t sessionseq; dbcounter_t trseq; dbtable_t transactions; dbtable_t fieldnames; @@ -78,15 +79,19 @@ public: PracroDAOTest(Data &data, bool ignore_fieldnames = false); ~PracroDAOTest(); - void commitTransaction(Transaction &transaction, + std::string newSessionId(); + void commitTransaction(std::string sessionid, + Transaction &transaction, Commit &commit, Macro ¯o, time_t now); - Values getLatestValues(std::string patientid, + Values getLatestValues(std::string sessionid, + std::string patientid, Macro *macro, Fieldnames &fieldnames, time_t oldest); - unsigned nrOfCommits(std::string patientid, + unsigned nrOfCommits(std::string sessionid, + std::string patientid, std::string macroname, time_t oldest); @@ -94,8 +99,9 @@ public: void delFieldname(std::string name); std::vector<Fieldname> getFieldnames(); - void commit() {} - void discard() {} + void commit(std::string sessionid) {} + void nocommit(std::string sessionid) {} + void discard(std::string sessionid) {} std::string serialise() { return ""; } void restore(const std::string &data) {} diff --git a/server/src/server.cc b/server/src/server.cc index cf99645..3973756 100644 --- a/server/src/server.cc +++ b/server/src/server.cc @@ -57,9 +57,11 @@ public: if(headers.contains("SessionID")) sessionid = headers["SessionID"]; bool commit = headers.contains("SessionCommit"); + bool nocommit = headers.contains("SessionNoCommit"); bool discard = headers.contains("SessionDiscard"); - Connection *connection = new Connection(env, sessionid, commit, discard); + Connection *connection = new Connection(env, sessionid, + commit, discard, nocommit); return connection; } diff --git a/server/src/session.cc b/server/src/session.cc index 5fe9230..612f264 100644 --- a/server/src/session.cc +++ b/server/src/session.cc @@ -46,9 +46,9 @@ Session::Session(std::string sessionid) { - _id = sessionid; _journal = NULL; _database = NULL; + database()->setSessionId(sessionid); } Session::~Session() @@ -59,7 +59,7 @@ Session::~Session() std::string Session::id() { - return _id; + return database()->sessionId(); } void Session::lock() @@ -86,6 +86,13 @@ void Session::commit() } } +void Session::nocommit() +{ + if(_database != NULL) { + _database->nocommit(); + } +} + void Session::discard() { if(_journal) { @@ -127,13 +134,6 @@ static bool fexists(const std::string &f) { bool ret; -/* - struct stat sbuf; - int n = stat(f.c_str(), &sbuf); - if(n != -1) ret = true; - ret = errno != ENOENT; -*/ - FILE *fp = fopen(f.c_str(), "r"); ret = fp != NULL; if(fp) fclose(fp); @@ -143,14 +143,7 @@ static bool fexists(const std::string &f) Session *Sessions::newSession() { - char sessionid[32]; - std::string filename; - do { - snprintf(sessionid, sizeof(sessionid)-1, "%d", rand()); - filename = getSessionFilename(Conf::session_path, sessionid); - } while(sessions.find(sessionid) != sessions.end() || fexists(filename)); - - Session *session = new Session(sessionid); + Session *session = new Session(); sessions[session->id()] = session; return session; } @@ -162,13 +155,9 @@ Session *Sessions::session(std::string sessionid) std::string filename = getSessionFilename(Conf::session_path, sessionid); if(fexists(filename)) { - Session *s = new Session(sessionid); - SessionSerialiser ser(Conf::session_path, s); - ser.load(); + SessionSerialiser ser(Conf::session_path); + Session *s = ser.load(sessionid); sessions[s->id()] = s; - - fprintf(stderr, "s: %p\n",s); - return s; } @@ -177,6 +166,8 @@ Session *Sessions::session(std::string sessionid) Session *Sessions::takeSession(std::string sessionid) { + DEBUG(session,"%s\n", sessionid.c_str()); + Session *s = NULL; if(sessions.find(sessionid) != sessions.end()) { s = sessions[sessionid]; @@ -185,6 +176,7 @@ Session *Sessions::takeSession(std::string sessionid) if(s) { sessions.erase(sessionid); } + else DEBUG(session, "No such session!\n"); return s; } @@ -204,8 +196,8 @@ void Sessions::store() { std::map<std::string, Session*>::iterator i = sessions.begin(); while(i != sessions.end()) { - SessionSerialiser ser(Conf::session_path, i->second); - ser.save(); + SessionSerialiser ser(Conf::session_path); + ser.save(i->second); delete i->second; sessions.erase(i); i++; diff --git a/server/src/session.h b/server/src/session.h index 0540541..c0f6dfc 100644 --- a/server/src/session.h +++ b/server/src/session.h @@ -38,7 +38,7 @@ class Journal; class Session { public: - Session(std::string sessionid); + Session(std::string sessionid = ""); ~Session(); std::string id(); @@ -47,6 +47,7 @@ public: void unlock(); void commit(); + void nocommit(); void discard(); Journal *journal(); @@ -55,7 +56,6 @@ public: private: Journal *_journal; Database *_database; - std::string _id; Mutex mutex; }; diff --git a/server/src/sessionserialiser.cc b/server/src/sessionserialiser.cc index 9489bd7..b816331 100644 --- a/server/src/sessionserialiser.cc +++ b/server/src/sessionserialiser.cc @@ -52,9 +52,8 @@ static std::string itostr(int i) return sid; } -SessionSerialiser::SessionSerialiser(std::string path, Session *session) +SessionSerialiser::SessionSerialiser(std::string path) { - this->session = session; this->path = path; } @@ -64,12 +63,14 @@ SessionSerialiser::SessionSerialiser(std::string path, Session *session) //#define BENC(s) base64encode(s) //#define BDEC(s) base64decode(s) -void SessionSerialiser::loadStr(const std::string &xml) +Session *SessionSerialiser::loadStr(const std::string &xml, + const std::string &sessionid) { // SessionAutolock lock(*session); SessionParser parser; parser.parse(xml.data(), xml.length()); + Session *session = new Session(sessionid); Journal *j = session->journal(); j->setUser(XDEC(parser.userid)); j->setPatientID(XDEC(parser.patientid)); @@ -80,9 +81,11 @@ void SessionSerialiser::loadStr(const std::string &xml) } session->database()->restore(XDEC(parser.database)); + + return session; } -std::string SessionSerialiser::saveStr() +std::string SessionSerialiser::saveStr(Session *session) { // SessionAutolock lock(*session); @@ -121,10 +124,10 @@ std::string SessionSerialiser::saveStr() return xml; } -void SessionSerialiser::load() +Session *SessionSerialiser::load(const std::string &sessionid) { // read xml from file - std::string filename = getSessionFilename(path, session->id()); + std::string filename = getSessionFilename(path, sessionid); FILE *fp = fopen(filename.c_str(), "r"); std::string xml; @@ -136,18 +139,19 @@ void SessionSerialiser::load() } fclose(fp); - loadStr(xml); + Session *session = loadStr(xml, sessionid); // delete file unlink(filename.c_str()); - + + return session; } -void SessionSerialiser::save() +void SessionSerialiser::save(Session *session) { std::string filename = getSessionFilename(path, session->id()); - std::string xml = saveStr(); + std::string xml = saveStr(session); // write xml to file FILE *fp = fopen(filename.c_str(), "w"); diff --git a/server/src/sessionserialiser.h b/server/src/sessionserialiser.h index 4002760..f184d35 100644 --- a/server/src/sessionserialiser.h +++ b/server/src/sessionserialiser.h @@ -34,16 +34,15 @@ class SessionSerialiser { public: - SessionSerialiser(std::string path, Session *session); + SessionSerialiser(std::string path); - void loadStr(const std::string &xml); - std::string saveStr(); + Session *loadStr(const std::string &xml, const std::string &sessionid); + std::string saveStr(Session *session); - void load(); - void save(); + Session *load(const std::string &sessionid); + void save(Session *session); private: - Session *session; std::string path; }; diff --git a/server/src/transactionhandler.cc b/server/src/transactionhandler.cc index 5a4bc6a..8ebbd69 100644 --- a/server/src/transactionhandler.cc +++ b/server/src/transactionhandler.cc @@ -246,16 +246,21 @@ static std::string handleRequest(Transaction &transaction, Environment &env, std::string resume = db->getResume(transaction.cpr, macro, time(NULL) - Conf::db_max_ttl); - - if(resume == jresume) state = "new"; - - if(jresume != "" && resume != jresume) { + if(session.journal()->dirty(macro.attributes["name"])) { state = "dirty"; - session.journal()->removeEntry(macro.attributes["name"]); + } else { + if(resume == jresume) { + state = "new"; + } else { + if(jresume != "") { + state = "dirty"; + session.journal()->setDirty(macro.attributes["name"]); + } else { + state = "old"; + } + } } - if(jresume == "" && resume != jresume) state = "old"; - answer += " <resume state=\""+state+"\">"; answer += xml_encode(resume); answer += "</resume>\n"; |