summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--server/src/connection.cc19
-rw-r--r--server/src/connection.h5
-rw-r--r--server/src/database.h48
-rw-r--r--server/src/journal.cc36
-rw-r--r--server/src/journal.h4
-rw-r--r--server/src/journal_commit.cc10
-rw-r--r--server/src/journal_uploadserver.cc4
-rw-r--r--server/src/pracrodao.h15
-rw-r--r--server/src/pracrodaopgsql.cc231
-rw-r--r--server/src/pracrodaopgsql.h22
-rw-r--r--server/src/pracrodaotest.cc16
-rw-r--r--server/src/pracrodaotest.h16
-rw-r--r--server/src/server.cc4
-rw-r--r--server/src/session.cc42
-rw-r--r--server/src/session.h4
-rw-r--r--server/src/sessionserialiser.cc24
-rw-r--r--server/src/sessionserialiser.h11
-rw-r--r--server/src/transactionhandler.cc19
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 &macro,
- 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 &macro, time_t oldest) {
+ std::string getResume(std::string patientid, Macro &macro, 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, &macro, fn, oldest);
+ Values v = dao->getLatestValues(sessionid, patientid, &macro, 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 &macro,
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 &macro,
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 &macro,
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";