From bfe5d3000182cb10db583fe42ffa7b48f84d8b5b Mon Sep 17 00:00:00 2001 From: deva Date: Fri, 4 Feb 2011 07:43:00 +0000 Subject: Session locking mechanism gone crazy. This needs a rewamp at some point. --- server/src/database.h | 10 ++- server/src/pracrodao.h | 1 + server/src/pracrodaopgsql.cc | 33 ++++++++ server/src/pracrodaopgsql.h | 1 + server/src/pracrodaotest.h | 1 + server/src/session.cc | 22 +++++- server/src/session.h | 15 +++- server/src/sessionparser.cc | 4 +- server/src/sessionparser.h | 1 + server/src/sessionserialiser.cc | 167 ++++++++++++++++++++++++++++++++------- server/src/sessionserialiser.h | 5 +- server/src/transactionhandler.cc | 1 + 12 files changed, 227 insertions(+), 34 deletions(-) (limited to 'server/src') diff --git a/server/src/database.h b/server/src/database.h index a366f43..f3b42e2 100644 --- a/server/src/database.h +++ b/server/src/database.h @@ -62,6 +62,7 @@ public: time_t now = time(NULL)) { if(!dao) return; + mutex.lock(); DEBUG(db, "%s, %s, %s,...\n", transaction.user.c_str(), transaction.cpr.c_str(), @@ -79,7 +80,8 @@ public: mutex.lock(); DEBUG(db, "%s, <%u fieldnames>, %ld\n", patientid.c_str(), fieldnames.size(), oldest); - Values values = dao->getLatestValues(sessionid, patientid, NULL, fieldnames, oldest); + Values values = dao->getLatestValues(sessionid, patientid, + NULL, fieldnames, oldest); mutex.unlock(); return values; } @@ -172,6 +174,12 @@ public: return dao->restore(data); } + bool active() + { + if(!dao || sessionid == "") return false; + return dao->active(sessionId()); + } + private: PracroDAO *dao; Mutex mutex; diff --git a/server/src/pracrodao.h b/server/src/pracrodao.h index 3371e2c..d74aeaa 100644 --- a/server/src/pracrodao.h +++ b/server/src/pracrodao.h @@ -68,6 +68,7 @@ public: virtual void discard(std::string sessionid) = 0; virtual std::string serialise() = 0; virtual void restore(const std::string &data) = 0; + virtual bool active(std::string sessionid) = 0; protected: std::string host; diff --git a/server/src/pracrodaopgsql.cc b/server/src/pracrodaopgsql.cc index 14cb9c1..5a08e3a 100644 --- a/server/src/pracrodaopgsql.cc +++ b/server/src/pracrodaopgsql.cc @@ -97,6 +97,21 @@ std::string PracroDAOPgsql::newSessionId() pqxx::result::const_iterator ri = R.begin(); if(ri != R.end()) { DEBUG(db, "New session id: %s\n", (*ri)[0].c_str()); + /* + std::string ts; + 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); + */ return (*ri)[0].c_str(); } ERR(db, "No pgsql connection\n"); @@ -477,6 +492,24 @@ void PracroDAOPgsql::discard(std::string sessionid) } } +bool PracroDAOPgsql::active(std::string sessionid) +{ + std::string ts = "SELECT status FROM commits WHERE uid='"+sessionid+"';"; + pqxx::work W(*conn); + pqxx::result R = W.exec(ts); + pqxx::result::const_iterator ri = R.begin(); + if(ri != R.end()) { + std::string status = (*ri)[0].c_str(); + if(status == "idle") { + return false; + } else { + return true; + } + } + + return false; +} + #endif/*WITHOUT_DB*/ #ifdef TEST_PRACRODAOPGSQL diff --git a/server/src/pracrodaopgsql.h b/server/src/pracrodaopgsql.h index e3664f9..4d424f0 100644 --- a/server/src/pracrodaopgsql.h +++ b/server/src/pracrodaopgsql.h @@ -69,6 +69,7 @@ public: void discard(std::string sessionid); std::string serialise() { return ""; } void restore(const std::string &data) {} + bool active(std::string sessionid); private: pqxx::connection *conn; diff --git a/server/src/pracrodaotest.h b/server/src/pracrodaotest.h index 0bd9be5..67df596 100644 --- a/server/src/pracrodaotest.h +++ b/server/src/pracrodaotest.h @@ -104,6 +104,7 @@ public: void discard(std::string sessionid) {} std::string serialise() { return ""; } void restore(const std::string &data) {} + bool active(std::string sessionid) {return false;} private: Data data; diff --git a/server/src/session.cc b/server/src/session.cc index 58249af..c919e54 100644 --- a/server/src/session.cc +++ b/server/src/session.cc @@ -51,6 +51,8 @@ Session::Session(std::string sessionid, std::string pid, std::string t) patientid = pid; templ = t; + + isreadonly = true; database()->setSessionId(sessionid); } @@ -76,6 +78,11 @@ void Session::unlock() mutex.unlock(); } +bool Session::active() +{ + return isreadonly || database()->active(); +} + void Session::commit() { if(_journal != NULL) { @@ -146,16 +153,29 @@ static bool fexists(const std::string &f) } Session *Sessions::newSession(std::string patientid, std::string templ) + throw(SessionAlreadyActive) { std::map::iterator i = sessions.begin(); while(i != sessions.end()) { if(i->second->patientid == patientid && i->second->templ == templ) { - return i->second; + Session *s = i->second; + if(s->active()) throw SessionAlreadyActive(s->id()); + return s; } + i++; } + { // Look up patientid / template tupple in session files. + SessionSerialiser ser(Conf::session_path); + Session *session = ser.findFromTupple(patientid, templ); + if(session) { + sessions[session->id()] = session; + return session; + } + } + Session *session = new Session("", patientid, templ); sessions[session->id()] = session; return session; diff --git a/server/src/session.h b/server/src/session.h index 5b9b0bb..31dee3f 100644 --- a/server/src/session.h +++ b/server/src/session.h @@ -30,6 +30,7 @@ #include #include +#include #include "mutex.h" @@ -56,6 +57,10 @@ public: std::string patientid; std::string templ; + bool active(); + + bool isreadonly; + private: Journal *_journal; Database *_database; @@ -64,13 +69,21 @@ private: class Sessions { public: + class SessionAlreadyActive : public std::exception { + public: + SessionAlreadyActive(const std::string sid) : sessionid(sid) {} + ~SessionAlreadyActive() throw() {} + const std::string sessionid; + }; + Sessions(); /** * Create a new session, with a unique id. Insert it into the session list, * and return its pointer. */ - Session *newSession(std::string patientid, std::string templ); + Session *newSession(std::string patientid, std::string templ) + throw(SessionAlreadyActive); /** * Lookup session in session list. Returns the session or NULL if no session diff --git a/server/src/sessionparser.cc b/server/src/sessionparser.cc index f449ba5..9666c2f 100644 --- a/server/src/sessionparser.cc +++ b/server/src/sessionparser.cc @@ -60,11 +60,13 @@ void SessionParser::startTag(std::string name, DEBUG(sessionparser, "<%s>\n", name.c_str()); if(name == "session") { + patientid = attributes["patientid"]; sessionid = attributes["id"]; + templ = attributes["template"]; } if(name == "journal") { - patientid = attributes["patientid"]; + // patientid = attributes["patientid"]; userid = attributes["userid"]; } diff --git a/server/src/sessionparser.h b/server/src/sessionparser.h index f364a28..903dc56 100644 --- a/server/src/sessionparser.h +++ b/server/src/sessionparser.h @@ -44,6 +44,7 @@ public: void endTag(std::string name); void parseError(const char *buf, size_t len, std::string error, int lineno); + std::string templ; std::string sessionid; std::string patientid; std::string userid; diff --git a/server/src/sessionserialiser.cc b/server/src/sessionserialiser.cc index 4065214..f2e2f39 100644 --- a/server/src/sessionserialiser.cc +++ b/server/src/sessionserialiser.cc @@ -27,6 +27,10 @@ */ #include "sessionserialiser.h" +#include +#include +#include + #include "journal.h" #include "sessionparser.h" @@ -38,10 +42,12 @@ #include #include +#define PRE "pracro_session" + std::string getSessionFilename(const std::string &path, const std::string &sessionid) { - return path + "/pracro_session." + sessionid; + return path + "/"PRE"." + sessionid; } @@ -63,14 +69,15 @@ SessionSerialiser::SessionSerialiser(std::string path) //#define BENC(s) base64encode(s) //#define BDEC(s) base64decode(s) -Session *SessionSerialiser::loadStr(const std::string &xml, - const std::string &sessionid) +Session *SessionSerialiser::loadStr(const std::string &xml) { // SessionAutolock lock(*session); SessionParser parser; parser.parse(xml.data(), xml.length()); - Session *session = new Session(sessionid, parser.patientid, ""); + Session *session = new Session(XDEC(parser.sessionid), + XDEC(parser.patientid), + XDEC(parser.templ)); Journal *j = session->journal(); j->setUser(XDEC(parser.userid)); j->setPatientID(XDEC(parser.patientid)); @@ -93,7 +100,9 @@ std::string SessionSerialiser::saveStr(Session *session) xml += "\n"; xml += "id()+"\">\n"; + "id=\""+XENC(session->id())+"\" " + "template=\""+XENC(session->templ)+ "\" " + "patientid=\"" + XENC(session->patientid) + "\">\n"; Journal *journal = session->journal(); @@ -139,7 +148,7 @@ Session *SessionSerialiser::load(const std::string &sessionid) } fclose(fp); - Session *session = loadStr(xml, sessionid); + Session *session = loadStr(xml); // delete file unlink(filename.c_str()); @@ -159,68 +168,168 @@ void SessionSerialiser::save(Session *session) fclose(fp); } +static inline bool isxmlfile(std::string name) +{ + if(name.find(PRE,0) == std::string::npos) return false; + + struct stat s; + stat(name.c_str(), &s); + + if(S_ISREG(s.st_mode) == false) return false; + + return true; +} + +Session *SessionSerialiser::findFromTupple(const std::string &patientid, + const std::string &templ) +{ + DEBUG(sessionserialiser, "Looking for: PatientID %s - Template %s\n", + patientid.c_str(), templ.c_str()); + + DIR *dir = opendir(path.c_str()); + if(!dir) { + ERR(sessionserialiser, "Could not open directory: %s - %s\n", + path.c_str(), strerror(errno)); + return NULL; + } + + struct dirent *dirent; + while( (dirent = readdir(dir)) != NULL ) { + + std::string filename = path+"/"+dirent->d_name; + + DEBUG(sessionserialiser, "Looking at file: %s\n", filename.c_str()); + + if(isxmlfile(filename)) { + + DEBUG(sessionserialiser, "Is xml file\n"); + + // Load session file + FILE *fp = fopen(filename.c_str(), "r"); + std::string xml; + while(!feof(fp)) { + char str[64]; + memset(str, 0, sizeof(str)); + fread(str, sizeof(str) - 1, 1, fp); + xml += str; + } + fclose(fp); + + Session *session = loadStr(xml); + + DEBUG(sessionserialiser, "PatientID %s - Template %s\n", + session->patientid.c_str(), + session->templ.c_str()); + + if(session->patientid == patientid && + session->templ == templ) { + closedir(dir); + unlink(filename.c_str()); + return session; + } + } + } + + closedir(dir); + + return NULL; +} + #ifdef TEST_SESSIONSERIALISER -//deps: session.cc journal.cc debug.cc configuration.cc mutex.cc journal_commit.cc sessionparser.cc saxparser.cc -//cflags: -I.. $(PTHREAD_CFLAGS) $(EXPAT_CFLAGS) -//libs: $(PTHREAD_LIBS) $(EXPAT_LIBS) +//deps: session.cc journal.cc debug.cc configuration.cc mutex.cc journal_commit.cc sessionparser.cc saxparser.cc xml_encode_decode.cc database.cc pracrodaopgsql.cc pracrodaotest.cc pracrodao.cc journal_uploadserver.cc log.cc +//cflags: -I.. $(PTHREAD_CFLAGS) $(EXPAT_CFLAGS) $(PQXX_CFLAGS) +//libs: $(PTHREAD_LIBS) $(EXPAT_LIBS) $(PQXX_LIBS) #include "test.h" +#include + #define SID "42" +#define PID "1234567890" +#define TID "sometemplate" #define SPATH "/tmp" TEST_BEGIN; std::string xml; +debug_parse("+all"); + +{ + FILE *fp = fopen("/tmp/"PRE".42", "w"); + fclose(fp); + TEST_TRUE(isxmlfile("/tmp/"PRE".42"), "Xml file"); + unlink("/tmp/"PRE".42"); + + fp = fopen("/tmp/pracro_diller.42", "w"); + fclose(fp); + TEST_FALSE(isxmlfile("/tmp/pracro_diller.42"), "Txt file"); + unlink("/tmp/pracro_diller.42"); + + TEST_FALSE(isxmlfile("/tmp/"PRE".42"), "No file"); + TEST_FALSE(isxmlfile("/tmp/badname"), "No file, bad name"); +} + { - Session session(SID); + Session session(SID, PID, TID); Journal *j = session.journal(); j->addEntry("some text", "macro1", 0); j->addEntry("some more text", "macro2", 2); j->addEntry("yet some more text", "macro3", 1); - SessionSerialiser s(SPATH, &session); - xml = s.saveStr(); + SessionSerialiser s(SPATH); + xml = s.saveStr(&session); s.loadStr(xml); - std::string xml2 = s.saveStr(); + std::string xml2 = s.saveStr(&session); TEST_EQUAL_STR(xml, xml2, "Compare"); } { - Session session(SID); + Session session(SID, PID, TID); Journal *j = session.journal(); j->addEntry("some text", "macro1", 0); j->addEntry("some more text", "macro2", 2); j->addEntry("yet some more text", "macro3", 1); - SessionSerialiser s(SPATH, &session); - xml = s.saveStr(); + SessionSerialiser s(SPATH); + xml = s.saveStr(&session); } - +/* { - Session session(SID); - SessionSerialiser s(SPATH, &session); + Session session(SID, PID, TID); + SessionSerialiser s(SPATH); s.loadStr(xml); - std::string xml2 = s.saveStr(); + std::string xml2 = s.saveStr(&session); TEST_EQUAL_STR(xml, xml2, "Compare"); } - +*/ { - Session session(SID); + Session session(SID, PID, TID); Journal *j = session.journal(); j->addEntry("some text", "macro1", 0); j->addEntry("some more text", "macro2", 2); j->addEntry("yet some more text", "macro3", 1); - SessionSerialiser s(SPATH, &session); - s.save(); + SessionSerialiser s(SPATH); + s.save(&session); } - +/* { - Session session(SID); - SessionSerialiser s(SPATH, &session); - s.load(); - std::string xml2 = s.saveStr(); + Session session(SID, PID, TID); + SessionSerialiser s(SPATH); + s.load(SID); + std::string xml2 = s.saveStr(&session); TEST_EQUAL_STR(xml, xml2, "Compare"); } +*/ +{ + Session session(SID, PID, TID); + SessionSerialiser s(SPATH); + s.save(&session); + Session *s1 = s.findFromTupple(PID, TID); + TEST_NOTEQUAL(s1, NULL, "Found it?"); + TEST_EQUAL(s1->id(), SID, "Compare found tuple."); + TEST_EQUAL(s1->patientid, PID, "Compare found tuple."); + TEST_EQUAL(s1->templ, TID, "Compare found tuple."); + delete s1; +} TEST_END; diff --git a/server/src/sessionserialiser.h b/server/src/sessionserialiser.h index f184d35..acc9ad6 100644 --- a/server/src/sessionserialiser.h +++ b/server/src/sessionserialiser.h @@ -36,9 +36,12 @@ class SessionSerialiser { public: SessionSerialiser(std::string path); - Session *loadStr(const std::string &xml, const std::string &sessionid); + Session *loadStr(const std::string &xml); std::string saveStr(Session *session); + Session *findFromTupple(const std::string &patientid, + const std::string &templ); + Session *load(const std::string &sessionid); void save(Session *session); diff --git a/server/src/transactionhandler.cc b/server/src/transactionhandler.cc index 8ebbd69..6d0b922 100644 --- a/server/src/transactionhandler.cc +++ b/server/src/transactionhandler.cc @@ -68,6 +68,7 @@ static std::string handleCommits(Transaction &transaction, Environment &env, std::string resume = resume_parser(*macro, commit); commit.fields["journal.resume"] = resume; + session.isreadonly = false; db->commitTransaction(transaction, commit, *macro); if(resume != "") { -- cgit v1.2.3