From: Razvan Becheriu Date: Fri, 6 Nov 2020 16:25:13 +0000 (+0200) Subject: [#1375] added dbReconnect to host manager X-Git-Tag: Kea-1.9.3~96 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=eaa6810139d313daa5355a6e2ae9e6f8426ca594;p=thirdparty%2Fkea.git [#1375] added dbReconnect to host manager --- diff --git a/src/lib/asiolink/io_service.h b/src/lib/asiolink/io_service.h index acfb97361c..f6f33c15e2 100644 --- a/src/lib/asiolink/io_service.h +++ b/src/lib/asiolink/io_service.h @@ -5,7 +5,7 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef ASIOLINK_IO_SERVICE_H -#define ASIOLINK_IO_SERVICE_H 1 +#define ASIOLINK_IO_SERVICE_H #include #include diff --git a/src/lib/dhcpsrv/base_host_data_source.h b/src/lib/dhcpsrv/base_host_data_source.h index 9050feb83c..c83a0bea34 100644 --- a/src/lib/dhcpsrv/base_host_data_source.h +++ b/src/lib/dhcpsrv/base_host_data_source.h @@ -8,6 +8,7 @@ #define BASE_HOST_DATA_SOURCE_H #include +#include #include #include #include @@ -458,6 +459,15 @@ public: /// @return Type of the backend. virtual std::string getType() const = 0; + /// @brief Return backend parameters + /// + /// Returns the backend parameters + /// + /// @return Parameters of the backend. + virtual isc::db::DatabaseConnection::ParameterMap getParameters() const { + return (isc::db::DatabaseConnection::ParameterMap()); + }; + /// @brief Commit Transactions /// /// Commits all pending database operations. On databases that don't diff --git a/src/lib/dhcpsrv/cql_host_data_source.cc b/src/lib/dhcpsrv/cql_host_data_source.cc index 38cd0e2107..ff4f76e738 100644 --- a/src/lib/dhcpsrv/cql_host_data_source.cc +++ b/src/lib/dhcpsrv/cql_host_data_source.cc @@ -2052,7 +2052,7 @@ public: /// This constructor opens database connection and initializes /// prepared statements used in the queries. /// @param parameters parameters passed to the CQL connection. - explicit CqlHostDataSourceImpl(const CqlConnection::ParameterMap& parameters); + explicit CqlHostDataSourceImpl(const DatabaseConnection::ParameterMap& parameters); /// @brief Destructor. virtual ~CqlHostDataSourceImpl(); @@ -2509,7 +2509,7 @@ operator==(const HostKey& key1, const HostKey& key2) { std::get(key1) == std::get(key2)); } -CqlHostDataSourceImpl::CqlHostDataSourceImpl(const CqlConnection::ParameterMap& parameters) +CqlHostDataSourceImpl::CqlHostDataSourceImpl(const DatabaseConnection::ParameterMap& parameters) : parameters_(parameters), dbconn_(parameters) { // Validate the schema version first. std::pair code_version(CQL_SCHEMA_VERSION_MAJOR, @@ -3447,7 +3447,7 @@ CqlHostDataSourceImpl::mergeHosts(const ConstHostPtr& source_host, source_host->getCfgOption6()->mergeTo(*target_host->getCfgOption6()); } -CqlHostDataSource::CqlHostDataSource(const CqlConnection::ParameterMap& parameters) +CqlHostDataSource::CqlHostDataSource(const DatabaseConnection::ParameterMap& parameters) : impl_(new CqlHostDataSourceImpl(parameters)) { } diff --git a/src/lib/dhcpsrv/host_data_source_factory.cc b/src/lib/dhcpsrv/host_data_source_factory.cc index 6def277d55..45817b614e 100644 --- a/src/lib/dhcpsrv/host_data_source_factory.cc +++ b/src/lib/dhcpsrv/host_data_source_factory.cc @@ -87,6 +87,7 @@ HostDataSourceFactory::add(HostDataSourceList& sources, bool HostDataSourceFactory::del(HostDataSourceList& sources, const string& db_type) { + bool result = false; for (auto it = sources.begin(); it != sources.end(); ++it) { if ((*it)->getType() != db_type) { continue; @@ -94,9 +95,28 @@ HostDataSourceFactory::del(HostDataSourceList& sources, LOG_DEBUG(hosts_logger, DHCPSRV_DBG_TRACE, HOSTS_CFG_CLOSE_HOST_DATA_SOURCE) .arg(db_type); sources.erase(it); - return (true); + result = true; + } + return (result); +} + +bool +HostDataSourceFactory::del(HostDataSourceList& sources, + const string& db_type, + const string& dbaccess) { + DatabaseConnection::ParameterMap parameters = + DatabaseConnection::parse(dbaccess); + bool result = false; + for (auto it = sources.begin(); it != sources.end(); ++it) { + if ((*it)->getType() != db_type || (*it)->getParameters() != parameters) { + continue; + } + LOG_DEBUG(hosts_logger, DHCPSRV_DBG_TRACE, HOSTS_CFG_CLOSE_HOST_DATA_SOURCE) + .arg((*it)->getType()); + sources.erase(it); + result = true; } - return (false); + return (result); } bool diff --git a/src/lib/dhcpsrv/host_data_source_factory.h b/src/lib/dhcpsrv/host_data_source_factory.h index 8543ee7eeb..97b9d2a674 100644 --- a/src/lib/dhcpsrv/host_data_source_factory.h +++ b/src/lib/dhcpsrv/host_data_source_factory.h @@ -67,7 +67,7 @@ public: /// @brief Delete a host data source. /// - /// Delete the first instance of a host data source of the given type. + /// Delete all instances of a host data source of the given type. /// This should have the effect of closing the database connection. /// /// @param sources host data source list. @@ -75,6 +75,21 @@ public: /// @return true when found and removed, false when not found. static bool del(HostDataSourceList& sources, const std::string& db_type); + /// @brief Delete a host data source. + /// + /// Delete instance of a host data source which matches specific parameters. + /// This should have the effect of closing the database connection. + /// + /// @param sources host data source list. + /// @param db_type database backend type. + /// @param dbaccess Database access parameters. These are in the form of + /// "keyword=value" pairs, separated by spaces. They are backend- + /// -end specific, although must include the "type" keyword which + /// gives the backend in use. + /// @return true when found and removed, false when not found. + static bool del(HostDataSourceList& sources, const std::string& db_type, + const std::string& dbaccess); + /// @brief Type of host data source factory /// /// A factory takes a parameter map and returns a pointer to a host diff --git a/src/lib/dhcpsrv/host_mgr.cc b/src/lib/dhcpsrv/host_mgr.cc index 205bbf429d..9a08018bf3 100644 --- a/src/lib/dhcpsrv/host_mgr.cc +++ b/src/lib/dhcpsrv/host_mgr.cc @@ -29,6 +29,7 @@ namespace isc { namespace dhcp { using namespace isc::asiolink; +using namespace isc::db; IOServicePtr HostMgr::io_service_ = IOServicePtr(); @@ -57,6 +58,11 @@ HostMgr::delBackend(const std::string& db_type) { return (HostDataSourceFactory::del(getHostMgrPtr()->alternate_sources_, db_type)); } +bool +HostMgr::delBackend(const std::string& db_type, const std::string& access) { + return (HostDataSourceFactory::del(getHostMgrPtr()->alternate_sources_, db_type, access)); +} + void HostMgr::delAllBackends() { getHostMgrPtr()->alternate_sources_.clear(); diff --git a/src/lib/dhcpsrv/host_mgr.h b/src/lib/dhcpsrv/host_mgr.h index 2c8df47ff8..0860761d8e 100644 --- a/src/lib/dhcpsrv/host_mgr.h +++ b/src/lib/dhcpsrv/host_mgr.h @@ -80,6 +80,14 @@ public: /// @return true when found and removed, false when not found. static bool delBackend(const std::string& db_type); + /// @brief Delete an alternate host backend (aka host data source). + /// + /// @param db_type database backend type. + /// @param access Host backend access parameters for the alternate + /// host backend. It holds "keyword=value" pairs, separated by spaces. + /// @return true when found and removed, false when not found. + static bool delBackend(const std::string& db_type, const std::string& access); + /// @brief Delete all alternate backends. static void delAllBackends(); diff --git a/src/lib/dhcpsrv/mysql_host_data_source.cc b/src/lib/dhcpsrv/mysql_host_data_source.cc index a1c712e78a..edb60eb8f9 100644 --- a/src/lib/dhcpsrv/mysql_host_data_source.cc +++ b/src/lib/dhcpsrv/mysql_host_data_source.cc @@ -6,14 +6,19 @@ #include +#include #include #include #include #include #include +#include #include +#include #include +#include #include +#include #include #include #include @@ -1946,7 +1951,9 @@ public: /// @brief Constructor /// /// @param parameters See MySqlHostMgr constructor. - MySqlHostContext(const DatabaseConnection::ParameterMap& parameters); + MySqlHostContext(const DatabaseConnection::ParameterMap& parameters, + const isc::asiolink::IOServicePtr& io_service, + db::DbCallback callback); /// The exchange objects are used for transfer of data to/from the database. /// They are pointed-to objects as the contents may change in "const" calls, @@ -2054,11 +2061,32 @@ public: /// /// This constructor opens database connection and initializes prepared /// statements used in the queries. - MySqlHostDataSourceImpl(const MySqlConnection::ParameterMap& parameters); + MySqlHostDataSourceImpl(const DatabaseConnection::ParameterMap& parameters); /// @brief Destructor. ~MySqlHostDataSourceImpl(); + /// @brief Attempts to reconnect the server to the host DB backend manager. + /// + /// This is a self-rescheduling function that attempts to reconnect to the + /// server's host DB backends after connectivity to one or more have been + /// lost. Upon entry it will attempt to reconnect via + /// @ref HostDataSourceFactory::add. + /// If this is successful, DHCP servicing is re-enabled and server returns + /// to normal operation. + /// + /// If reconnection fails and the maximum number of retries has not been + /// exhausted, it will schedule a call to itself to occur at the + /// configured retry interval. DHCP service remains disabled. + /// + /// If the maximum number of retries has been exhausted an error is logged + /// and the server shuts down. + /// + /// @param db_reconnect_ctl pointer to the ReconnectCtl containing the + /// configured reconnect parameters. + /// @return true if connection has been recovered, false otherwise. + static bool dbReconnect(ReconnectCtlPtr db_reconnect_ctl); + /// @brief Create a new context. /// /// The database is opened with all the SQL commands pre-compiled. @@ -2690,8 +2718,10 @@ TaggedStatementArray tagged_statements = { { // MySqlHostContext Constructor -MySqlHostContext::MySqlHostContext(const DatabaseConnection::ParameterMap& parameters) - : conn_(parameters), is_readonly_(true) { +MySqlHostContext::MySqlHostContext(const DatabaseConnection::ParameterMap& parameters, + const isc::asiolink::IOServicePtr& io_service, + db::DbCallback callback) + : conn_(parameters, io_service, callback), is_readonly_(true) { } // MySqlHostContextAlloc Constructor and Destructor @@ -2730,7 +2760,7 @@ MySqlHostDataSource::MySqlHostContextAlloc::~MySqlHostContextAlloc() { // If running in single-threaded mode, there's nothing to do here. } -MySqlHostDataSourceImpl::MySqlHostDataSourceImpl(const MySqlConnection::ParameterMap& parameters) +MySqlHostDataSourceImpl::MySqlHostDataSourceImpl(const DatabaseConnection::ParameterMap& parameters) : parameters_(parameters), ip_reservations_unique_(true) { // Validate the schema version first. @@ -2748,13 +2778,26 @@ MySqlHostDataSourceImpl::MySqlHostDataSourceImpl(const MySqlConnection::Paramete // Create an initial context. pool_.reset(new MySqlHostContextPool()); pool_->pool_.push_back(createContext()); + + auto db_reconnect_ctl = pool_->pool_[0]->conn_.reconnectCtl(); + + std::string manager = "MySqlLeaseMgr["; + manager += boost::lexical_cast(reinterpret_cast(this)); + std::string timer_name = manager + "]DbReconnectTimer"; + + TimerMgr::instance()->registerTimer(timer_name, + std::bind(&MySqlHostDataSourceImpl::dbReconnect, db_reconnect_ctl), + db_reconnect_ctl->retryInterval(), + asiolink::IntervalTimer::ONE_SHOT); } // Create context. MySqlHostContextPtr MySqlHostDataSourceImpl::createContext() const { - MySqlHostContextPtr ctx(new MySqlHostContext(parameters_)); + MySqlHostContextPtr ctx(new MySqlHostContext(parameters_, + HostMgr::getIOService(), + &MySqlHostDataSourceImpl::dbReconnect)); // Open the database. ctx->conn_.openDatabase(); @@ -2787,10 +2830,74 @@ MySqlHostDataSourceImpl::createContext() const { ctx->host_ipv6_reservation_exchange_.reset(new MySqlIPv6ReservationExchange()); ctx->host_option_exchange_.reset(new MySqlOptionExchange()); + std::string manager = "MySqlHostMgr["; + manager += boost::lexical_cast(reinterpret_cast(this)); + std::string timer_name = manager + "]DbReconnectTimer"; + + ctx->conn_.makeReconnectCtl(timer_name); + return (ctx); } MySqlHostDataSourceImpl::~MySqlHostDataSourceImpl() { + std::string manager = "MySqlHostMgr["; + manager += boost::lexical_cast(reinterpret_cast(this)); + std::string timer_name = manager + "]DbReconnectTimer"; + + TimerMgr::instance()->unregisterTimer(timer_name); +} + +bool +MySqlHostDataSourceImpl::dbReconnect(ReconnectCtlPtr db_reconnect_ctl) { + MultiThreadingCriticalSection cs; + + DatabaseConnection::invokeDbLostCallback(db_reconnect_ctl); + + bool reopened = false; + + // At least one connection was lost. + try { + CfgDbAccessPtr cfg_db = CfgMgr::instance().getCurrentCfg()->getCfgDbAccess(); + std::list host_db_access_list = cfg_db->getHostDbAccessStringList(); + for (std::string& hds : host_db_access_list) { + auto parameters = DatabaseConnection::parse(hds); + if (HostMgr::delBackend("mysql", hds)) { + HostMgr::addBackend(hds); + } + } + + reopened = true; + } catch (const std::exception& ex) { + //LOG_ERROR(dhcpsrv_logger, DHCPSRV_MYSQL_DB_RECONNECT_ATTEMPT_FAILED) + // .arg(ex.what()); + } + + if (reopened) { + // Cancel the timer. + const std::string& timer_name = db_reconnect_ctl->timerName(); + TimerMgr::instance()->cancel(timer_name); + + DatabaseConnection::invokeDbRecoveredCallback(db_reconnect_ctl); + } else { + if (!db_reconnect_ctl->checkRetries()) { + // We're out of retries, log it and initiate shutdown. + //LOG_ERROR(dhcpsrv_logger, DHCPSRV_MYSQL_DB_RECONNECT_RETRIES_EXHAUSTED) + // .arg(db_reconnect_ctl->maxRetries()); + + DatabaseConnection::invokeDbFailedCallback(db_reconnect_ctl); + + return (false); + } + + //LOG_INFO(dhcpsrv_logger, DHCPSRV_MYSQL_DB_RECONNECT_ATTEMPT_SCHEDULE) + // .arg(db_reconnect_ctl->maxRetries() - db_reconnect_ctl->retriesLeft() + 1) + // .arg(db_reconnect_ctl->maxRetries()) + // .arg(db_reconnect_ctl->retryInterval()); + + TimerMgr::instance()->setup(db_reconnect_ctl->timerName()); + } + + return (true); } std::pair @@ -3023,13 +3130,18 @@ MySqlHostDataSourceImpl::checkReadOnly(MySqlHostContextPtr& ctx) const { } } -MySqlHostDataSource::MySqlHostDataSource(const MySqlConnection::ParameterMap& parameters) +MySqlHostDataSource::MySqlHostDataSource(const DatabaseConnection::ParameterMap& parameters) : impl_(new MySqlHostDataSourceImpl(parameters)) { } MySqlHostDataSource::~MySqlHostDataSource() { } +DatabaseConnection::ParameterMap +MySqlHostDataSource::getParameters() const { + return impl_->parameters_; +} + void MySqlHostDataSource::add(const HostPtr& host) { // Get a context diff --git a/src/lib/dhcpsrv/mysql_host_data_source.h b/src/lib/dhcpsrv/mysql_host_data_source.h index 0a0495d3d0..be705d2081 100644 --- a/src/lib/dhcpsrv/mysql_host_data_source.h +++ b/src/lib/dhcpsrv/mysql_host_data_source.h @@ -7,6 +7,7 @@ #ifndef MYSQL_HOST_DATA_SOURCE_H #define MYSQL_HOST_DATA_SOURCE_H +#include #include #include #include @@ -69,6 +70,13 @@ public: /// Releases prepared MySQL statements used by the backend. virtual ~MySqlHostDataSource(); + /// @brief Return backend parameters + /// + /// Returns the backend parameters + /// + /// @return Parameters of the backend. + virtual isc::db::DatabaseConnection::ParameterMap getParameters() const; + /// @brief Adds a new host to the collection. /// /// The implementations of this method should guard against duplicate diff --git a/src/lib/dhcpsrv/mysql_lease_mgr.cc b/src/lib/dhcpsrv/mysql_lease_mgr.cc index b50be15d8a..b4bd0a3158 100644 --- a/src/lib/dhcpsrv/mysql_lease_mgr.cc +++ b/src/lib/dhcpsrv/mysql_lease_mgr.cc @@ -1736,7 +1736,7 @@ bool MySqlLeaseStatsQuery::negative_count_ = false; // MySqlLeaseContext Constructor -MySqlLeaseContext::MySqlLeaseContext(const MySqlConnection::ParameterMap& parameters, +MySqlLeaseContext::MySqlLeaseContext(const DatabaseConnection::ParameterMap& parameters, const isc::asiolink::IOServicePtr& io_service, DbCallback callback) : conn_(parameters, io_service, callback) { @@ -1780,7 +1780,7 @@ MySqlLeaseMgr::MySqlLeaseContextAlloc::~MySqlLeaseContextAlloc() { // MySqlLeaseMgr Constructor and Destructor -MySqlLeaseMgr::MySqlLeaseMgr(const MySqlConnection::ParameterMap& parameters) +MySqlLeaseMgr::MySqlLeaseMgr(const DatabaseConnection::ParameterMap& parameters) : parameters_(parameters) { // Validate schema version first. diff --git a/src/lib/dhcpsrv/pgsql_host_data_source.cc b/src/lib/dhcpsrv/pgsql_host_data_source.cc index d0f3c02c8e..7033b2fb07 100644 --- a/src/lib/dhcpsrv/pgsql_host_data_source.cc +++ b/src/lib/dhcpsrv/pgsql_host_data_source.cc @@ -6,14 +6,19 @@ #include +#include #include #include #include #include #include +#include #include +#include #include +#include #include +#include #include #include #include @@ -1308,7 +1313,9 @@ public: /// @brief Constructor /// /// @param parameters See PgSqlHostMgr constructor. - PgSqlHostContext(const DatabaseConnection::ParameterMap& parameters); + PgSqlHostContext(const DatabaseConnection::ParameterMap& parameters, + const isc::asiolink::IOServicePtr& io_service, + db::DbCallback callback); /// The exchange objects are used for transfer of data to/from the database. /// They are pointed-to objects as the contents may change in "const" calls, @@ -1416,11 +1423,32 @@ public: /// /// This constructor opens database connection and initializes prepared /// statements used in the queries. - PgSqlHostDataSourceImpl(const PgSqlConnection::ParameterMap& parameters); + PgSqlHostDataSourceImpl(const DatabaseConnection::ParameterMap& parameters); /// @brief Destructor. ~PgSqlHostDataSourceImpl(); + /// @brief Attempts to reconnect the server to the host DB backend manager. + /// + /// This is a self-rescheduling function that attempts to reconnect to the + /// server's host DB backends after connectivity to one or more have been + /// lost. Upon entry it will attempt to reconnect via + /// @ref HostDataSourceFactory::add. + /// If this is successful, DHCP servicing is re-enabled and server returns + /// to normal operation. + /// + /// If reconnection fails and the maximum number of retries has not been + /// exhausted, it will schedule a call to itself to occur at the + /// configured retry interval. DHCP service remains disabled. + /// + /// If the maximum number of retries has been exhausted an error is logged + /// and the server shuts down. + /// + /// @param db_reconnect_ctl pointer to the ReconnectCtl containing the + /// configured reconnect parameters. + /// @return true if connection has been recovered, false otherwise. + static bool dbReconnect(ReconnectCtlPtr db_reconnect_ctl); + /// @brief Create a new context. /// /// The database is opened with all the SQL commands pre-compiled. @@ -1574,7 +1602,7 @@ public: std::pair getVersion() const; /// @brief The parameters - PgSqlConnection::ParameterMap parameters_; + DatabaseConnection::ParameterMap parameters_; /// @brief Holds the setting whether the IP reservations must be unique or /// may be non-unique. @@ -2131,8 +2159,10 @@ TaggedStatementArray tagged_statements = { { // PgSqlHostContext Constructor -PgSqlHostContext::PgSqlHostContext(const DatabaseConnection::ParameterMap& parameters) - : conn_(parameters), is_readonly_(true) { +PgSqlHostContext::PgSqlHostContext(const DatabaseConnection::ParameterMap& parameters, + const isc::asiolink::IOServicePtr& io_service, + db::DbCallback callback) + : conn_(parameters, io_service, callback), is_readonly_(true) { } // PgSqlHostContextAlloc Constructor and Destructor @@ -2171,7 +2201,7 @@ PgSqlHostDataSource::PgSqlHostContextAlloc::~PgSqlHostContextAlloc() { // If running in single-threaded mode, there's nothing to do here. } -PgSqlHostDataSourceImpl::PgSqlHostDataSourceImpl(const PgSqlConnection::ParameterMap& parameters) +PgSqlHostDataSourceImpl::PgSqlHostDataSourceImpl(const DatabaseConnection::ParameterMap& parameters) : parameters_(parameters), ip_reservations_unique_(true) { // Validate the schema version first. @@ -2189,13 +2219,26 @@ PgSqlHostDataSourceImpl::PgSqlHostDataSourceImpl(const PgSqlConnection::Paramete // Create an initial context. pool_.reset(new PgSqlHostContextPool()); pool_->pool_.push_back(createContext()); + + auto db_reconnect_ctl = pool_->pool_[0]->conn_.reconnectCtl(); + + std::string manager = "PgSqlLeaseMgr["; + manager += boost::lexical_cast(reinterpret_cast(this)); + std::string timer_name = manager + "]DbReconnectTimer"; + + TimerMgr::instance()->registerTimer(timer_name, + std::bind(&PgSqlHostDataSourceImpl::dbReconnect, db_reconnect_ctl), + db_reconnect_ctl->retryInterval(), + asiolink::IntervalTimer::ONE_SHOT); } // Create context. PgSqlHostContextPtr PgSqlHostDataSourceImpl::createContext() const { - PgSqlHostContextPtr ctx(new PgSqlHostContext(parameters_)); + PgSqlHostContextPtr ctx(new PgSqlHostContext(parameters_, + HostMgr::getIOService(), + &PgSqlHostDataSourceImpl::dbReconnect)); // Open the database. ctx->conn_.openDatabase(); @@ -2223,10 +2266,74 @@ PgSqlHostDataSourceImpl::createContext() const { ctx->host_ipv6_reservation_exchange_.reset(new PgSqlIPv6ReservationExchange()); ctx->host_option_exchange_.reset(new PgSqlOptionExchange()); + std::string manager = "PgSqlHostMgr["; + manager += boost::lexical_cast(reinterpret_cast(this)); + std::string timer_name = manager + "]DbReconnectTimer"; + + ctx->conn_.makeReconnectCtl(timer_name); + return (ctx); } PgSqlHostDataSourceImpl::~PgSqlHostDataSourceImpl() { + std::string manager = "PgSqlHostMgr["; + manager += boost::lexical_cast(reinterpret_cast(this)); + std::string timer_name = manager + "]DbReconnectTimer"; + + TimerMgr::instance()->unregisterTimer(timer_name); +} + +bool +PgSqlHostDataSourceImpl::dbReconnect(ReconnectCtlPtr db_reconnect_ctl) { + MultiThreadingCriticalSection cs; + + DatabaseConnection::invokeDbLostCallback(db_reconnect_ctl); + + bool reopened = false; + + // At least one connection was lost. + try { + CfgDbAccessPtr cfg_db = CfgMgr::instance().getCurrentCfg()->getCfgDbAccess(); + std::list host_db_access_list = cfg_db->getHostDbAccessStringList(); + for (std::string& hds : host_db_access_list) { + auto parameters = DatabaseConnection::parse(hds); + if (HostMgr::delBackend("postgresql", hds)) { + HostMgr::addBackend(hds); + } + } + + reopened = true; + } catch (const std::exception& ex) { + //LOG_ERROR(dhcpsrv_logger, DHCPSRV_PGSQL_DB_RECONNECT_ATTEMPT_FAILED) + // .arg(ex.what()); + } + + if (reopened) { + // Cancel the timer. + const std::string& timer_name = db_reconnect_ctl->timerName(); + TimerMgr::instance()->cancel(timer_name); + + DatabaseConnection::invokeDbRecoveredCallback(db_reconnect_ctl); + } else { + if (!db_reconnect_ctl->checkRetries()) { + // We're out of retries, log it and initiate shutdown. + //LOG_ERROR(dhcpsrv_logger, DHCPSRV_PGSQL_DB_RECONNECT_RETRIES_EXHAUSTED) + // .arg(db_reconnect_ctl->maxRetries()); + + DatabaseConnection::invokeDbFailedCallback(db_reconnect_ctl); + + return (false); + } + + //LOG_INFO(dhcpsrv_logger, DHCPSRV_PGSQL_DB_RECONNECT_ATTEMPT_SCHEDULE) + // .arg(db_reconnect_ctl->maxRetries() - db_reconnect_ctl->retriesLeft() + 1) + // .arg(db_reconnect_ctl->maxRetries()) + // .arg(db_reconnect_ctl->retryInterval()); + + TimerMgr::instance()->setup(db_reconnect_ctl->timerName()); + } + + return (true); } uint64_t @@ -2432,13 +2539,18 @@ PgSqlHostDataSourceImpl::checkReadOnly(PgSqlHostContextPtr& ctx) const { /*********** PgSqlHostDataSource *********************/ -PgSqlHostDataSource::PgSqlHostDataSource(const PgSqlConnection::ParameterMap& parameters) +PgSqlHostDataSource::PgSqlHostDataSource(const DatabaseConnection::ParameterMap& parameters) : impl_(new PgSqlHostDataSourceImpl(parameters)) { } PgSqlHostDataSource::~PgSqlHostDataSource() { } +DatabaseConnection::ParameterMap +PgSqlHostDataSource::getParameters() const { + return impl_->parameters_; +} + void PgSqlHostDataSource::add(const HostPtr& host) { // Get a context diff --git a/src/lib/dhcpsrv/pgsql_host_data_source.h b/src/lib/dhcpsrv/pgsql_host_data_source.h index 55b76afd89..aec52305a3 100644 --- a/src/lib/dhcpsrv/pgsql_host_data_source.h +++ b/src/lib/dhcpsrv/pgsql_host_data_source.h @@ -7,6 +7,7 @@ #ifndef PGSQL_HOST_DATA_SOURCE_H #define PGSQL_HOST_DATA_SOURCE_H +#include #include #include #include @@ -73,6 +74,13 @@ public: /// the destruction of member impl_. virtual ~PgSqlHostDataSource(); + /// @brief Return backend parameters + /// + /// Returns the backend parameters + /// + /// @return Parameters of the backend. + virtual isc::db::DatabaseConnection::ParameterMap getParameters() const; + /// @brief Adds a new host to the collection. /// /// The method will insert the given host and all of its children (v4 diff --git a/src/lib/dhcpsrv/pgsql_lease_mgr.cc b/src/lib/dhcpsrv/pgsql_lease_mgr.cc index c0abb42860..cae1f43faa 100644 --- a/src/lib/dhcpsrv/pgsql_lease_mgr.cc +++ b/src/lib/dhcpsrv/pgsql_lease_mgr.cc @@ -1170,7 +1170,7 @@ bool PgSqlLeaseStatsQuery::negative_count_ = false; // PgSqlLeaseContext Constructor -PgSqlLeaseContext::PgSqlLeaseContext(const PgSqlConnection::ParameterMap& parameters, +PgSqlLeaseContext::PgSqlLeaseContext(const DatabaseConnection::ParameterMap& parameters, const isc::asiolink::IOServicePtr& io_service, DbCallback callback) : conn_(parameters, io_service, callback) { @@ -1214,7 +1214,7 @@ PgSqlLeaseMgr::PgSqlLeaseContextAlloc::~PgSqlLeaseContextAlloc() { // PgSqlLeaseMgr Constructor and Destructor -PgSqlLeaseMgr::PgSqlLeaseMgr(const PgSqlConnection::ParameterMap& parameters) +PgSqlLeaseMgr::PgSqlLeaseMgr(const DatabaseConnection::ParameterMap& parameters) : parameters_(parameters) { // Validate schema version first. diff --git a/src/lib/dhcpsrv/tests/mysql_host_data_source_unittest.cc b/src/lib/dhcpsrv/tests/mysql_host_data_source_unittest.cc index a656bba515..a040b30533 100644 --- a/src/lib/dhcpsrv/tests/mysql_host_data_source_unittest.cc +++ b/src/lib/dhcpsrv/tests/mysql_host_data_source_unittest.cc @@ -118,7 +118,7 @@ public: int countRowsInTable(const std::string& table) { string query = "SELECT * FROM " + table; - MySqlConnection::ParameterMap params; + DatabaseConnection::ParameterMap params; params["name"] = "keatest"; params["user"] = "keatest"; params["password"] = "keatest"; @@ -1227,7 +1227,7 @@ TEST_F(MySqlHostDataSourceTest, testAddRollback) { // when inserting reservations or options. The simplest way to // achieve that is to simply drop one of the tables. To do so, we // connect to the database and issue a DROP query. - MySqlConnection::ParameterMap params; + DatabaseConnection::ParameterMap params; params["name"] = "keatest"; params["user"] = "keatest"; params["password"] = "keatest"; @@ -1277,7 +1277,7 @@ TEST_F(MySqlHostDataSourceTest, testAddRollbackMultiThreading) { // when inserting reservations or options. The simplest way to // achieve that is to simply drop one of the tables. To do so, we // connect to the database and issue a DROP query. - MySqlConnection::ParameterMap params; + DatabaseConnection::ParameterMap params; params["name"] = "keatest"; params["user"] = "keatest"; params["password"] = "keatest"; diff --git a/src/lib/dhcpsrv/tests/pgsql_host_data_source_unittest.cc b/src/lib/dhcpsrv/tests/pgsql_host_data_source_unittest.cc index 3ca49bc04c..32a51f6e59 100644 --- a/src/lib/dhcpsrv/tests/pgsql_host_data_source_unittest.cc +++ b/src/lib/dhcpsrv/tests/pgsql_host_data_source_unittest.cc @@ -118,7 +118,7 @@ public: int countRowsInTable(const std::string& table) { string query = "SELECT * FROM " + table; - PgSqlConnection::ParameterMap params; + DatabaseConnection::ParameterMap params; params["name"] = "keatest"; params["user"] = "keatest"; params["password"] = "keatest"; @@ -342,7 +342,7 @@ TEST(PgSqlHostDataSource, NoCallbackOnOpenFail) { createPgSQLSchema(); callback_called = false; - DatabaseConnection::db_lost_callback = db_lost_callback; + DatabaseConnection::db_lost_callback_ = db_lost_callback; HostMgr::create(); EXPECT_THROW(HostMgr::addBackend(connectionString( PGSQL_VALID_TYPE, VALID_NAME, INVALID_HOST, VALID_USER, VALID_PASSWORD)), @@ -369,7 +369,7 @@ TEST(PgSqlHostDataSource, NoCallbackOnOpenFailMultiThreading) { createPgSQLSchema(); callback_called = false; - DatabaseConnection::db_lost_callback = db_lost_callback; + DatabaseConnection::db_lost_callback_ = db_lost_callback; HostMgr::create(); EXPECT_THROW(HostMgr::addBackend(connectionString( PGSQL_VALID_TYPE, VALID_NAME, INVALID_HOST, VALID_USER, VALID_PASSWORD)), @@ -1236,7 +1236,7 @@ TEST_F(PgSqlHostDataSourceTest, testAddRollback) { // when inserting reservations or options. The simplest way to // achieve that is to simply drop one of the tables. To do so, we // connect to the database and issue a DROP query. - PgSqlConnection::ParameterMap params; + DatabaseConnection::ParameterMap params; params["name"] = "keatest"; params["user"] = "keatest"; params["password"] = "keatest"; @@ -1286,7 +1286,7 @@ TEST_F(PgSqlHostDataSourceTest, testAddRollbackMultiThreading) { // when inserting reservations or options. The simplest way to // achieve that is to simply drop one of the tables. To do so, we // connect to the database and issue a DROP query. - PgSqlConnection::ParameterMap params; + DatabaseConnection::ParameterMap params; params["name"] = "keatest"; params["user"] = "keatest"; params["password"] = "keatest"; diff --git a/src/lib/pgsql/tests/pgsql_exchange_unittest.cc b/src/lib/pgsql/tests/pgsql_exchange_unittest.cc index 173665ac94..afaf0955ff 100644 --- a/src/lib/pgsql/tests/pgsql_exchange_unittest.cc +++ b/src/lib/pgsql/tests/pgsql_exchange_unittest.cc @@ -130,7 +130,7 @@ public: /// the table (if present) and then recreates it. PgSqlBasicsTest() : expectedColNames_(NUM_BASIC_COLS) { // Create database connection parameter list - PgSqlConnection::ParameterMap params; + DatabaseConnection::ParameterMap params; params["name"] = "keatest"; params["user"] = "keatest"; params["password"] = "keatest";