diff options
-rw-r--r-- | project2/rdbmsDataSource.cpp | 85 | ||||
-rw-r--r-- | project2/rdbmsDataSource.h | 12 |
2 files changed, 82 insertions, 15 deletions
diff --git a/project2/rdbmsDataSource.cpp b/project2/rdbmsDataSource.cpp index 1a55fb8..ab515a1 100644 --- a/project2/rdbmsDataSource.cpp +++ b/project2/rdbmsDataSource.cpp @@ -1,48 +1,105 @@ #include "rdbmsDataSource.h" #include "xmlObjectLoader.h" #include <libxml++/nodes/textnode.h> +#include <sys/utsname.h> +#include <syslog.h> +#include <errno.h> +#include <sqlext.h> + +_RdbmsDataSource::DBHosts _RdbmsDataSource::dbhosts; _RdbmsDataSource::_RdbmsDataSource(const xmlpp::Element * p) : _SourceObject(p), _DataSource(p), - masterDsn(xmlChildText(p, "masterdsn")) + masterDsn(xmlChildText(p, "masterdsn")), + preferLocal(p->get_attribute_value("preferlocal") != "false") { + BOOST_FOREACH(const xmlpp::Node * node, p->find("readonly/dsn")) { + const xmlpp::Element * elem = dynamic_cast<const xmlpp::Element *>(node); + if (elem) { + roDSNs[elem->get_attribute_value("host")] = elem->get_child_text()->get_content(); + } + } } ODBC::Connection & _RdbmsDataSource::getWritable() const { - if (!database) { - database = boost::shared_ptr<ODBC::Connection>(new ODBC::Connection(masterDsn)); + ConnectionPtr master = connectTo(masterDsn); + if (!master->inTx()) { + master->beginTx(); } - if (!database->inTx()) { - database->beginTx(); - } - return *database; + return *master; } ODBC::Connection & _RdbmsDataSource::getReadonly() const { - if (!database) { - database = boost::shared_ptr<ODBC::Connection>(new ODBC::Connection(masterDsn)); + if (localhost.length() == 0 && preferLocal) { + struct utsname name; + if (uname(&name)) { + syslog(LOG_WARNING, "%s: Unable to determine local host name (%d:%s)", __FUNCTION__, errno, strerror(errno)); + localhost = "unknown"; + } + else { + localhost = name.nodename; + } + } + if (preferLocal) { + ReadonlyDSNs::const_iterator ro = roDSNs.find(localhost); + if (ro == roDSNs.end()) { + syslog(LOG_WARNING, "%s: No database host makes local host name (%s) Will use master DSN", __FUNCTION__, localhost.c_str()); + return *connectTo(masterDsn); + } + return *connectTo(ro->second); + } + else { + BOOST_FOREACH(ReadonlyDSNs::value_type db, roDSNs) { + try { + return *connectTo(db.second); + } + catch (...) { + } + } + return *connectTo(masterDsn); } - return *database; } void _RdbmsDataSource::commit() { - if (database && database->inTx()) { - database->commitTx(); + DBHosts::const_iterator m = dbhosts.find(masterDsn); + if (m != dbhosts.end() && m->second->inTx()) { + m->second->commitTx(); } } void _RdbmsDataSource::rollback() { - if (database && database->inTx()) { - database->rollbackTx(); + DBHosts::const_iterator m = dbhosts.find(masterDsn); + if (m != dbhosts.end() && m->second->inTx()) { + m->second->rollbackTx(); + } +} +_RdbmsDataSource::ConnectionPtr +_RdbmsDataSource::connectTo(const std::string & dsn) +{ + DBHosts::const_iterator dbi = dbhosts.find(dsn); + if (dbi != dbhosts.end()) { + try { + SQLINTEGER dead = dbi->second->getAttrInt(SQL_ATTR_CONNECTION_DEAD); + if (dead == SQL_CD_FALSE) { + return dbi->second; + } + } + catch (...) { + // Connection in failed state + syslog(LOG_WARNING, "%s: Cached connection failed", __FUNCTION__); + } } + ConnectionPtr db = ConnectionPtr(new ODBC::Connection(dsn)); + dbhosts[dsn] = db; + return db; } diff --git a/project2/rdbmsDataSource.h b/project2/rdbmsDataSource.h index ee75550..e5709b7 100644 --- a/project2/rdbmsDataSource.h +++ b/project2/rdbmsDataSource.h @@ -9,14 +9,24 @@ class _RdbmsDataSource : public _DataSource { public: + typedef boost::shared_ptr<ODBC::Connection> ConnectionPtr; + typedef std::map<std::string, std::string> ReadonlyDSNs; // Map hostname to DSN string + typedef std::map<std::string, ConnectionPtr> DBHosts; // Map DSN strings to connections _RdbmsDataSource(const xmlpp::Element * p); ODBC::Connection & getReadonly() const; ODBC::Connection & getWritable() const; virtual void commit(); virtual void rollback(); const std::string masterDsn; + const bool preferLocal; + + protected: + static ConnectionPtr connectTo(const std::string & dsn); + ReadonlyDSNs roDSNs; + private: - mutable boost::shared_ptr<ODBC::Connection> database; + mutable std::string localhost; + static DBHosts dbhosts; }; typedef boost::shared_ptr<_RdbmsDataSource> RdbmsDataSource; typedef std::map<std::string, RdbmsDataSource> RdbmsDataSources; |