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; | 
