From 8d625d0cdba5bd47000efb9eea51cfa7b84ac1cd Mon Sep 17 00:00:00 2001 From: randomdan Date: Tue, 26 Oct 2010 17:28:35 +0000 Subject: Add callbacks for key points in time allow clean up of unused stuff Use these callbacks to clean up unused DB connections --- project2/cgi/p2webMain.cpp | 20 ++++++++++++++++++++ project2/console/p2consoleMain.cpp | 3 +++ project2/rdbmsDataSource.cpp | 35 ++++++++++++++++++++++++++++++++++- project2/rdbmsDataSource.h | 11 ++++++++++- project2/xmlObjectLoader.cpp | 26 ++++++++++++++++++++++++++ project2/xmlObjectLoader.h | 6 +++++- 6 files changed, 98 insertions(+), 3 deletions(-) diff --git a/project2/cgi/p2webMain.cpp b/project2/cgi/p2webMain.cpp index d464406..c36335a 100644 --- a/project2/cgi/p2webMain.cpp +++ b/project2/cgi/p2webMain.cpp @@ -18,9 +18,22 @@ xmlWrite(void * _out, const char * buf, int len) return len; } +time_t lastPeriodic = 0; +time_t periodicDelay = 600; + +void +p2webPeriodic() +{ + time(&lastPeriodic); + LoaderBase::onPeriodic(); +} + void p2webGoingIdle(int) { + if (time(NULL) > lastPeriodic + periodicDelay) { + p2webPeriodic(); + } LoaderBase::onIdle(); } @@ -64,6 +77,10 @@ int main(void) IO << "Kaboom!" << std::endl << std::endl << "Unknown exception."; } alarm(60); + LoaderBase::onIteration(); + if (time(NULL) > lastPeriodic + periodicDelay) { + p2webPeriodic(); + } } } else { @@ -72,6 +89,9 @@ int main(void) CgiApplicationEngine app(&env); app.process(); app.write(boost::bind(xmlDocDump, realstdout, _1)); + LoaderBase::onIteration(); + LoaderBase::onPeriodic(); + LoaderBase::onIdle(); } return 0; } diff --git a/project2/console/p2consoleMain.cpp b/project2/console/p2consoleMain.cpp index 25c06fa..eb3ff0d 100644 --- a/project2/console/p2consoleMain.cpp +++ b/project2/console/p2consoleMain.cpp @@ -9,6 +9,9 @@ int main(int argc, char ** argv) BOOST_FOREACH(const boost::filesystem::path & file, env.todolist) { ConsoleApplicationEngine app(&env, file); app.process(); + LoaderBase::onIteration(); } + LoaderBase::onPeriodic(); + LoaderBase::onIdle(); } diff --git a/project2/rdbmsDataSource.cpp b/project2/rdbmsDataSource.cpp index cab37bf..4f9c7d7 100644 --- a/project2/rdbmsDataSource.cpp +++ b/project2/rdbmsDataSource.cpp @@ -16,6 +16,18 @@ class RdbmsDataSourceLoader : public ElementLoaderImpl<_RdbmsDataSource> { // Disconnect all cached database connections _RdbmsDataSource::dbhosts.clear(); } + static bool isConnectionExpired(const _RdbmsDataSource::DBHosts::value_type & con) + { + return con.second->isExpired(); + } + void onPeriodic() + { + // Disconnect expired database connections + _RdbmsDataSource::DBHosts::iterator i; + while ((i = std::find_if(_RdbmsDataSource::dbhosts.begin(), _RdbmsDataSource::dbhosts.end(), isConnectionExpired)) != _RdbmsDataSource::dbhosts.end()) { + _RdbmsDataSource::dbhosts.erase(i); + } + } } rdbmsLoader; _RdbmsDataSource::DBHosts _RdbmsDataSource::dbhosts; @@ -129,6 +141,7 @@ _RdbmsDataSource::connectTo(const std::string & dsn) try { SQLINTEGER dead = dbi->second->getAttrInt(SQL_ATTR_CONNECTION_DEAD); if (dead == SQL_CD_FALSE) { + dbi->second->touch(); return dbi->second; } } @@ -139,8 +152,9 @@ _RdbmsDataSource::connectTo(const std::string & dsn) } try { - ConnectionPtr db = ConnectionPtr(new ODBC::Connection(dsn)); + ConnectionPtr db = ConnectionPtr(new RdbmsConnection(dsn, 300)); dbhosts[dsn] = db; + db->touch(); return db; } catch (const ODBC::ConnectionError & e) { @@ -149,3 +163,22 @@ _RdbmsDataSource::connectTo(const std::string & dsn) } } +_RdbmsDataSource::RdbmsConnection::RdbmsConnection(const std::string & dsn, time_t kat) : + ODBC::Connection(dsn), + lastUsedTime(0), + keepAliveTime(kat) +{ +} + +void +_RdbmsDataSource::RdbmsConnection::touch() const +{ + time(&lastUsedTime); +} + +bool +_RdbmsDataSource::RdbmsConnection::isExpired() const +{ + return (time(NULL) > lastUsedTime + keepAliveTime); +} + diff --git a/project2/rdbmsDataSource.h b/project2/rdbmsDataSource.h index bb1047a..77fbe3a 100644 --- a/project2/rdbmsDataSource.h +++ b/project2/rdbmsDataSource.h @@ -9,7 +9,16 @@ class _RdbmsDataSource : public _DataSource { public: - typedef boost::shared_ptr ConnectionPtr; + class RdbmsConnection : public ODBC::Connection { + public: + RdbmsConnection(const std::string & dsn, time_t keepAliveTime); + void touch() const; + bool isExpired() const; + private: + mutable time_t lastUsedTime; + const time_t keepAliveTime; + }; + typedef boost::shared_ptr ConnectionPtr; typedef std::map ReadonlyDSNs; // Map hostname to DSN string typedef std::map DBHosts; // Map DSN strings to connections typedef std::map FailedHosts; // Map DSN strings to failures diff --git a/project2/xmlObjectLoader.cpp b/project2/xmlObjectLoader.cpp index 6934aaf..9b4b24b 100644 --- a/project2/xmlObjectLoader.cpp +++ b/project2/xmlObjectLoader.cpp @@ -63,8 +63,34 @@ LoaderBase::onIdle() } } +void +LoaderBase::onIteration() +{ + BOOST_FOREACH(ElementLoaderMap::value_type l, getMap()) { + l.second->onIteration(); + } +} + +void +LoaderBase::onPeriodic() +{ + BOOST_FOREACH(ElementLoaderMap::value_type l, getMap()) { + l.second->onPeriodic(); + } +} + void ElementLoader::onIdle() { } +void +ElementLoader::onIteration() +{ +} + +void +ElementLoader::onPeriodic() +{ +} + diff --git a/project2/xmlObjectLoader.h b/project2/xmlObjectLoader.h index d871d9b..56cdfac 100644 --- a/project2/xmlObjectLoader.h +++ b/project2/xmlObjectLoader.h @@ -95,6 +95,8 @@ class LoaderBase { std::set > supportedStorers; static void onIdle(); + static void onIteration(); + static void onPeriodic(); private: static unsigned int depth; @@ -104,7 +106,9 @@ class LoaderBase { class ElementLoader { public: virtual Project2SourceObject go(const xmlpp::Element * xml) const = 0; - virtual void onIdle(); + virtual void onIdle(); // When the app engine goes idle + virtual void onIteration(); // When the app engine has completed an iteration + virtual void onPeriodic(); // When the app engine feels like it }; template -- cgit v1.2.3