diff options
author | Bent Bisballe Nyeng <deva@aasimon.org> | 2012-08-09 11:24:11 +0200 |
---|---|---|
committer | Bent Bisballe Nyeng <deva@aasimon.org> | 2012-08-09 11:24:11 +0200 |
commit | 40211cd5598c5349358e1d33b6353a4c729b17b3 (patch) | |
tree | 8c2cf76aed3847cc4e1d74d3b1df50b662908eed | |
parent | 24900ef2773fdcd3afc1f7598e2d2ab99e138d71 (diff) |
Added SessionHeaderParser for faster session xml file content searching.
-rw-r--r-- | server/src/Makefile.am | 2 | ||||
-rw-r--r-- | server/src/sessionheaderparser.cc | 178 | ||||
-rw-r--r-- | server/src/sessionheaderparser.h | 96 | ||||
-rw-r--r-- | server/src/sessionserialiser.cc | 42 |
4 files changed, 303 insertions, 15 deletions
diff --git a/server/src/Makefile.am b/server/src/Makefile.am index bb172bd..c852eb0 100644 --- a/server/src/Makefile.am +++ b/server/src/Makefile.am @@ -57,6 +57,7 @@ pracrod_SOURCES = \ semaphore.cc \ server.cc \ session.cc \ + sessionheaderparser.cc \ sessionparser.cc \ sessionserialiser.cc \ templatelist.cc \ @@ -121,6 +122,7 @@ EXTRA_DIST = \ semaphore.h \ server.h \ session.h \ + sessionheaderparser.h \ sessionparser.h \ sessionserialiser.h \ template.h \ diff --git a/server/src/sessionheaderparser.cc b/server/src/sessionheaderparser.cc new file mode 100644 index 0000000..93bd80b --- /dev/null +++ b/server/src/sessionheaderparser.cc @@ -0,0 +1,178 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set et sw=2 ts=2: */ +/*************************************************************************** + * sessionheaderparser.cc + * + * Thu Aug 9 09:06:32 CEST 2012 + * Copyright 2012 Bent Bisballe Nyeng + * deva@aasimon.org + ****************************************************************************/ + +/* + * This file is part of Pracro. + * + * Pracro is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Pracro is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Pracro; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ +#include "sessionheaderparser.h" + +/* +<session timestamp="1234567890" + status="readonly"" + id="12345" + template="amd_forunders" + patientid="0000000000"> + ... +</session> +*/ + +#include <stdio.h> + +// For assert +#include <assert.h> + +// For open and friends +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> + +// For vprintf and friends +#include <stdarg.h> + +#include <errno.h> +#include <string.h> + +#include "debug.h" +#include "configuration.h" +#include "exception.h" + +void SessionHeaderParser::error(const char* fmt, ...) +{ + ERR_LOG(session, "Error in SessionHeaderParser: "); + + { + va_list argp; + va_start(argp, fmt); + ERR_LOG_VA(session, fmt, argp); + va_end(argp); + + fprintf(stderr, "\n"); + } + + { + char *p; + va_list argp; + va_start(argp, fmt); + if(vasprintf(&p, fmt, argp) != -1) { + throw Exception("Error in SessionHeaderParser: " + std::string(p)); + free(p); + } + va_end(argp); + } + +} + +SessionHeaderParser::SessionHeaderParser(std::string sessionfile) +{ + done = false; + + file = sessionfile; + + DEBUG(session, "Using session file: %s\n", sessionfile.c_str()); + + fd = open(sessionfile.c_str(), O_RDONLY); + if(fd == -1) error("Could not open file %s", sessionfile.c_str()); +} + +SessionHeaderParser::~SessionHeaderParser() +{ + if(fd != -1) close(fd); +} + +void SessionHeaderParser::startTag(std::string name, attributes_t &attr) +{ + if(done) return; + + if(name == "session") { + done = true; + if(attr.find("patientid") != attr.end()) patientid = attr["patientid"]; + if(attr.find("template") != attr.end()) templ = attr["template"]; + } else { + throw Exception("Missing root tag 'session' - found '" + name + "'"); + } +} + +int SessionHeaderParser::readData(char *data, size_t size) +{ + if(done) return 0; // If done is true we already found what we were looking + // for and can dismiss the rest of the document. + + if(fd == -1) { + ERR_LOG(session, "Invalid file descriptor.\n"); + return 0; + } + ssize_t r = read(fd, data, size); + if(r == -1) { + ERR_LOG(session, "Could not read...%s\n", strerror(errno)); + return 0; + } + return r; +} + +void SessionHeaderParser::parseError(const char *buf, size_t len, std::string error, int lineno) +{ + if(done) return; // If done is true we already found what we were looking + // for and can dismiss the rest of the document. + + ERR_LOG(session, "SessionHeaderParser[%s] error at line %d: %s\n", + file.c_str(), lineno, error.c_str()); + ERR_LOG(session, "\tBuffer %u bytes: [", len); + if(fwrite(buf, len, 1, stderr) != len) {} + ERR_LOG(session, "]\n"); + + char *slineno; + if(asprintf(&slineno, " at line %d\n", lineno) != -1) { + throw Exception(error + slineno); + free(slineno); + } +} + +std::string SessionHeaderParser::getPatientID() +{ + return patientid; +} + +std::string SessionHeaderParser::getTemplate() +{ + return templ; +} + +#ifdef TEST_SESSIONHEADERPARSER +//Additional dependency files +//deps: +//Required cflags (autoconf vars may be used) +//cflags: +//Required link options (autoconf vars may be used) +//libs: +#include "test.h" + +TEST_BEGIN; + +// TODO: Put some testcode here (see test.h for usable macros). +TEST_TRUE(false, "No tests yet!"); + +TEST_END; + +#endif/*TEST_SESSIONHEADERPARSER*/ diff --git a/server/src/sessionheaderparser.h b/server/src/sessionheaderparser.h new file mode 100644 index 0000000..a56215a --- /dev/null +++ b/server/src/sessionheaderparser.h @@ -0,0 +1,96 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set et sw=2 ts=2: */ +/*************************************************************************** + * sessionheaderparser.h + * + * Thu Aug 9 09:06:32 CEST 2012 + * Copyright 2012 Bent Bisballe Nyeng + * deva@aasimon.org + ****************************************************************************/ + +/* + * This file is part of Pracro. + * + * Pracro is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Pracro is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Pracro; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ +#ifndef __PRACRO_SESSIONHEADERPARSER_H__ +#define __PRACRO_SESSIONHEADERPARSER_H__ + +#include "saxparser.h" + +/** + * Partial session parser. + * This class is used to parse only the first tag of a session xml file. + * The parser will run about 10 times faster than the one parsing the entire + * file (see the SessionParser class) and can be used to find a + * patientid/template match. + * This class inherits the SAXParser baseclass. + * Use the parse() method to run the parser, and collect the result via the + * getPatientID() and getTemplate() methods. + * If the file does not contain a session, or the file is not a valid xml file, + * an Exception is thrown. + */ +class SessionHeaderParser : public SAXParser { +public: + /** + * Constructor. + * @param sessionfile A std::string containing the name of the file to parse. + */ + SessionHeaderParser(std::string sessionfile); + + /** + * Destructor. + */ + ~SessionHeaderParser(); + + /** + * Overloaded parser callback method. + */ + void startTag(std::string name, attributes_t &attr); + + /** + * Overloaded parser callback method. + */ + void parseError(const char *buf, size_t len, std::string error, int lineno); + + /** + * Get a pointer to the parsed macro. + * NOTE: The allocated memory for the macro is owned by the parser, and will be + * freed upon parser deletion. + * @return A pointer to the macro or NULL on error. + */ + std::string getPatientID(); + std::string getTemplate(); + +protected: + /** + * Overloaded parser callback method. + */ + int readData(char *data, size_t size); + +private: + int fd; + + bool done; + + std::string patientid; + std::string templ; + + std::string file; + // Error callback function. + void error(const char* fmt, ...); +}; + +#endif/*__PRACRO_SESSIONHEADERPARSER_H__*/ diff --git a/server/src/sessionserialiser.cc b/server/src/sessionserialiser.cc index 386a115..d5150ac 100644 --- a/server/src/sessionserialiser.cc +++ b/server/src/sessionserialiser.cc @@ -34,6 +34,7 @@ #include "journal.h" #include "sessionparser.h" +#include "sessionheaderparser.h" #include "database.h" #include "xml_encode_decode.h" @@ -255,25 +256,36 @@ Session *SessionSerialiser::findFromTupple(const std::string &patientid, 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; + std::string pid; + std::string tpl; + + SessionHeaderParser p(filename); + try { + p.parse(); + pid = p.getPatientID(); + tpl = p.getTemplate(); + } catch( ... ) { + continue; } - fclose(fp); - Session *session = loadStr(xml); + if(patientid == pid && templ == tpl) { + // 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()); + 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; |