diff options
-rw-r--r-- | project2/cgiAppEngine.cpp | 1 | ||||
-rw-r--r-- | project2/rdbmsDataSource.cpp | 52 | ||||
-rw-r--r-- | project2/rdbmsDataSource.h | 2 |
3 files changed, 38 insertions, 17 deletions
diff --git a/project2/cgiAppEngine.cpp b/project2/cgiAppEngine.cpp index 4f04b7e..363bcb7 100644 --- a/project2/cgiAppEngine.cpp +++ b/project2/cgiAppEngine.cpp @@ -5,7 +5,6 @@ #include "cgiEnvironment.h" #include <libxml/xinclude.h> #include "xmlObjectLoader.h" -#include "rdbmsDataSource.h" #include "iterate.h" #include <boost/bind.hpp> #include <boost/lexical_cast.hpp> diff --git a/project2/rdbmsDataSource.cpp b/project2/rdbmsDataSource.cpp index e9c0089..6f3fc92 100644 --- a/project2/rdbmsDataSource.cpp +++ b/project2/rdbmsDataSource.cpp @@ -7,6 +7,7 @@ #include <sqlext.h> _RdbmsDataSource::DBHosts _RdbmsDataSource::dbhosts; +_RdbmsDataSource::FailedHosts _RdbmsDataSource::failedhosts; _RdbmsDataSource::_RdbmsDataSource(const xmlpp::Element * p) : _SourceObject(p), @@ -53,23 +54,26 @@ _RdbmsDataSource::getReadonly() const } 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); + try { + 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); + } + catch (...) { + // Failed to connect to a preferred DB... carry on and try the others... } - return *connectTo(ro->second); } - else { - BOOST_FOREACH(ReadonlyDSNs::value_type db, roDSNs) { - try { - return *connectTo(db.second); - } - catch (...) { - } + BOOST_FOREACH(ReadonlyDSNs::value_type db, roDSNs) { + try { + return *connectTo(db.second); + } + catch (...) { } - return *connectTo(masterDsn); } + return *connectTo(masterDsn); } void @@ -94,6 +98,15 @@ _RdbmsDataSource::rollback() _RdbmsDataSource::ConnectionPtr _RdbmsDataSource::connectTo(const std::string & dsn) { + FailedHosts::iterator dbf = failedhosts.find(dsn); + if (dbf != failedhosts.end()) { + if (time(NULL) - 20 > dbf->second.FailureTime) { + failedhosts.erase(dbf); + } + else { + throw dbf->second; + } + } DBHosts::const_iterator dbi = dbhosts.find(dsn); if (dbi != dbhosts.end()) { try { @@ -107,8 +120,15 @@ _RdbmsDataSource::connectTo(const std::string & dsn) syslog(LOG_WARNING, "%s: Cached connection failed", __FUNCTION__); } } - ConnectionPtr db = ConnectionPtr(new ODBC::Connection(dsn)); - dbhosts[dsn] = db; - return db; + + try { + ConnectionPtr db = ConnectionPtr(new ODBC::Connection(dsn)); + dbhosts[dsn] = db; + return db; + } + catch (const ODBC::ConnectionError & e) { + failedhosts.insert(FailedHosts::value_type(dsn, e)); + throw; + } } diff --git a/project2/rdbmsDataSource.h b/project2/rdbmsDataSource.h index 57a607f..a9dad6c 100644 --- a/project2/rdbmsDataSource.h +++ b/project2/rdbmsDataSource.h @@ -12,6 +12,7 @@ class _RdbmsDataSource : public _DataSource { 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 + typedef std::map<std::string, const ODBC::ConnectionError> FailedHosts; // Map DSN strings to failures _RdbmsDataSource(const xmlpp::Element * p); ODBC::Connection & getReadonly() const; ODBC::Connection & getWritable() const; @@ -28,6 +29,7 @@ class _RdbmsDataSource : public _DataSource { private: mutable std::string localhost; static DBHosts dbhosts; + static FailedHosts failedhosts; }; typedef boost::shared_ptr<_RdbmsDataSource> RdbmsDataSource; typedef std::map<std::string, RdbmsDataSource> RdbmsDataSources; |