diff options
Diffstat (limited to 'server')
| -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"; | 
