summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/bin/dhcp4/ctrl_dhcp4_srv.cc6
-rw-r--r--src/bin/dhcp4/json_config_parser.cc12
-rw-r--r--src/bin/dhcp6/ctrl_dhcp6_srv.cc6
-rw-r--r--src/bin/dhcp6/json_config_parser.cc12
-rw-r--r--src/hooks/dhcp/mysql_cb/mysql_cb_dhcp4.cc4
-rw-r--r--src/hooks/dhcp/mysql_cb/mysql_cb_dhcp6.cc4
-rw-r--r--src/lib/dhcpsrv/mysql_host_data_source.cc29
-rw-r--r--src/lib/dhcpsrv/mysql_lease_mgr.cc29
-rw-r--r--src/lib/dhcpsrv/pgsql_host_data_source.cc29
-rw-r--r--src/lib/dhcpsrv/pgsql_lease_mgr.cc29
-rw-r--r--src/lib/dhcpsrv/tests/generic_lease_mgr_unittest.cc203
-rw-r--r--src/lib/dhcpsrv/tests/generic_lease_mgr_unittest.h84
-rw-r--r--src/lib/dhcpsrv/tests/host_mgr_unittest.cc1
-rw-r--r--src/lib/dhcpsrv/tests/mysql_lease_mgr_unittest.cc44
-rw-r--r--src/lib/dhcpsrv/tests/pgsql_lease_mgr_unittest.cc44
15 files changed, 423 insertions, 113 deletions
diff --git a/src/bin/dhcp4/ctrl_dhcp4_srv.cc b/src/bin/dhcp4/ctrl_dhcp4_srv.cc
index 81f8bc3df4..324b6dea6e 100644
--- a/src/bin/dhcp4/ctrl_dhcp4_srv.cc
+++ b/src/bin/dhcp4/ctrl_dhcp4_srv.cc
@@ -1117,12 +1117,6 @@ ControlledDhcpv4Srv::~ControlledDhcpv4Srv() {
CommandMgr::instance().deregisterCommand("status-get");
CommandMgr::instance().deregisterCommand("version-get");
- // TimerMgr uses IO service to run asynchronous timers.
- TimerMgr::instance()->setIOService(IOServicePtr());
-
- // CommandMgr uses IO service to run asynchronous socket operations.
- CommandMgr::instance().setIOService(IOServicePtr());
-
// LeaseMgr uses IO service to run asynchronous timers.
LeaseMgr::setIOService(IOServicePtr());
diff --git a/src/bin/dhcp4/json_config_parser.cc b/src/bin/dhcp4/json_config_parser.cc
index 48cdcd85b0..6099e74426 100644
--- a/src/bin/dhcp4/json_config_parser.cc
+++ b/src/bin/dhcp4/json_config_parser.cc
@@ -339,18 +339,6 @@ configureDhcp4Server(Dhcpv4Srv& server, isc::data::ConstElementPtr config_set,
// Close DHCP sockets and remove any existing timers.
if (!check_only) {
- // If mysql or postgresql lease and host managers were configured, they
- // need to be destroy before calling unregisterTimers as they are
- // responsible for unregistering own connection timers. A memfile lease
- // manager and an empty host manager will be created instead.
- auto running_cfg = CfgMgr::instance().getCurrentCfg();
- auto parameters = DatabaseConnection::parse(running_cfg->getCfgDbAccess()->getLeaseDbAccessString());
- if (parameters["type"] != "memfile") {
- CfgDbAccess cfg_db;
- cfg_db.setAppendedParameters("universe=4");
- LeaseMgrFactory::create(cfg_db.getLeaseDbAccessString());
- }
- HostMgr::create();
IfaceMgr::instance().closeSockets();
TimerMgr::instance()->unregisterTimers();
server.discardPackets();
diff --git a/src/bin/dhcp6/ctrl_dhcp6_srv.cc b/src/bin/dhcp6/ctrl_dhcp6_srv.cc
index eb8317051f..654347ed49 100644
--- a/src/bin/dhcp6/ctrl_dhcp6_srv.cc
+++ b/src/bin/dhcp6/ctrl_dhcp6_srv.cc
@@ -1136,12 +1136,6 @@ ControlledDhcpv6Srv::~ControlledDhcpv6Srv() {
CommandMgr::instance().deregisterCommand("status-get");
CommandMgr::instance().deregisterCommand("version-get");
- // TimerMgr uses IO service to run asynchronous timers.
- TimerMgr::instance()->setIOService(IOServicePtr());
-
- // CommandMgr uses IO service to run asynchronous socket operations.
- CommandMgr::instance().setIOService(IOServicePtr());
-
// LeaseMgr uses IO service to run asynchronous timers.
LeaseMgr::setIOService(IOServicePtr());
diff --git a/src/bin/dhcp6/json_config_parser.cc b/src/bin/dhcp6/json_config_parser.cc
index 7022aeda86..1394f048ff 100644
--- a/src/bin/dhcp6/json_config_parser.cc
+++ b/src/bin/dhcp6/json_config_parser.cc
@@ -442,18 +442,6 @@ configureDhcp6Server(Dhcpv6Srv& server, isc::data::ConstElementPtr config_set,
// Close DHCP sockets and remove any existing timers.
if (!check_only) {
- // If mysql or postgresql lease and host managers were configured, they
- // need to be destroy before calling unregisterTimers as they are
- // responsible for unregistering own connection timers. A memfile lease
- // manager and an empty host manager will be created instead.
- auto running_cfg = CfgMgr::instance().getCurrentCfg();
- auto parameters = DatabaseConnection::parse(running_cfg->getCfgDbAccess()->getLeaseDbAccessString());
- if (parameters["type"] != "memfile") {
- CfgDbAccess cfg_db;
- cfg_db.setAppendedParameters("universe=6");
- LeaseMgrFactory::create(cfg_db.getLeaseDbAccessString());
- }
- HostMgr::create();
IfaceMgr::instance().closeSockets();
TimerMgr::instance()->unregisterTimers();
server.discardPackets();
diff --git a/src/hooks/dhcp/mysql_cb/mysql_cb_dhcp4.cc b/src/hooks/dhcp/mysql_cb/mysql_cb_dhcp4.cc
index 97c1ffd1d3..df142266a8 100644
--- a/src/hooks/dhcp/mysql_cb/mysql_cb_dhcp4.cc
+++ b/src/hooks/dhcp/mysql_cb/mysql_cb_dhcp4.cc
@@ -2341,8 +2341,7 @@ public:
if (reopened) {
// Cancel the timer.
- const std::string& timer_name = db_reconnect_ctl->timerName();
- TimerMgr::instance()->cancel(timer_name);
+ TimerMgr::instance()->cancel(db_reconnect_ctl->timerName());
DatabaseConnection::invokeDbRecoveredCallback(db_reconnect_ctl);
} else {
@@ -2361,6 +2360,7 @@ public:
.arg(db_reconnect_ctl->maxRetries())
.arg(db_reconnect_ctl->retryInterval());
+ // Start the timer.
TimerMgr::instance()->setup(db_reconnect_ctl->timerName());
}
diff --git a/src/hooks/dhcp/mysql_cb/mysql_cb_dhcp6.cc b/src/hooks/dhcp/mysql_cb/mysql_cb_dhcp6.cc
index 9c56999794..103da095c7 100644
--- a/src/hooks/dhcp/mysql_cb/mysql_cb_dhcp6.cc
+++ b/src/hooks/dhcp/mysql_cb/mysql_cb_dhcp6.cc
@@ -2784,8 +2784,7 @@ public:
if (reopened) {
// Cancel the timer.
- const std::string& timer_name = db_reconnect_ctl->timerName();
- TimerMgr::instance()->cancel(timer_name);
+ TimerMgr::instance()->cancel(db_reconnect_ctl->timerName());
DatabaseConnection::invokeDbRecoveredCallback(db_reconnect_ctl);
} else {
@@ -2804,6 +2803,7 @@ public:
.arg(db_reconnect_ctl->maxRetries())
.arg(db_reconnect_ctl->retryInterval());
+ // Start the timer.
TimerMgr::instance()->setup(db_reconnect_ctl->timerName());
}
diff --git a/src/lib/dhcpsrv/mysql_host_data_source.cc b/src/lib/dhcpsrv/mysql_host_data_source.cc
index 4393e0ee88..63c987239d 100644
--- a/src/lib/dhcpsrv/mysql_host_data_source.cc
+++ b/src/lib/dhcpsrv/mysql_host_data_source.cc
@@ -2794,13 +2794,6 @@ MySqlHostDataSourceImpl::MySqlHostDataSourceImpl(const DatabaseConnection::Param
// Create an initial context.
pool_.reset(new MySqlHostContextPool());
pool_->pool_.push_back(createContext());
-
- auto db_reconnect_ctl = pool_->pool_[0]->conn_.reconnectCtl();
-
- TimerMgr::instance()->registerTimer(timer_name_,
- std::bind(&MySqlHostDataSourceImpl::dbReconnect, db_reconnect_ctl),
- db_reconnect_ctl->retryInterval(),
- asiolink::IntervalTimer::ONE_SHOT);
}
// Create context.
@@ -2848,7 +2841,6 @@ MySqlHostDataSourceImpl::createContext() const {
}
MySqlHostDataSourceImpl::~MySqlHostDataSourceImpl() {
- TimerMgr::instance()->unregisterTimer(timer_name_);
}
bool
@@ -2859,6 +2851,8 @@ MySqlHostDataSourceImpl::dbReconnect(ReconnectCtlPtr db_reconnect_ctl) {
bool reopened = false;
+ const std::string timer_name = db_reconnect_ctl->timerName();
+
// At least one connection was lost.
try {
CfgDbAccessPtr cfg_db = CfgMgr::instance().getCurrentCfg()->getCfgDbAccess();
@@ -2878,8 +2872,9 @@ MySqlHostDataSourceImpl::dbReconnect(ReconnectCtlPtr db_reconnect_ctl) {
if (reopened) {
// Cancel the timer.
- const std::string& timer_name = db_reconnect_ctl->timerName();
- TimerMgr::instance()->cancel(timer_name);
+ if (TimerMgr::instance()->isTimerRegistered(timer_name)) {
+ TimerMgr::instance()->unregisterTimer(timer_name);
+ }
DatabaseConnection::invokeDbRecoveredCallback(db_reconnect_ctl);
} else {
@@ -2888,6 +2883,11 @@ MySqlHostDataSourceImpl::dbReconnect(ReconnectCtlPtr db_reconnect_ctl) {
LOG_ERROR(dhcpsrv_logger, DHCPSRV_MYSQL_HOST_DB_RECONNECT_FAILED)
.arg(db_reconnect_ctl->maxRetries());
+ // Cancel the timer.
+ if (TimerMgr::instance()->isTimerRegistered(timer_name)) {
+ TimerMgr::instance()->unregisterTimer(timer_name);
+ }
+
DatabaseConnection::invokeDbFailedCallback(db_reconnect_ctl);
return (false);
@@ -2898,7 +2898,14 @@ MySqlHostDataSourceImpl::dbReconnect(ReconnectCtlPtr db_reconnect_ctl) {
.arg(db_reconnect_ctl->maxRetries())
.arg(db_reconnect_ctl->retryInterval());
- TimerMgr::instance()->setup(db_reconnect_ctl->timerName());
+ // Start the timer.
+ if (!TimerMgr::instance()->isTimerRegistered(timer_name)) {
+ TimerMgr::instance()->registerTimer(timer_name,
+ std::bind(&MySqlHostDataSourceImpl::dbReconnect, db_reconnect_ctl),
+ db_reconnect_ctl->retryInterval(),
+ asiolink::IntervalTimer::ONE_SHOT);
+ }
+ TimerMgr::instance()->setup(timer_name);
}
return (true);
diff --git a/src/lib/dhcpsrv/mysql_lease_mgr.cc b/src/lib/dhcpsrv/mysql_lease_mgr.cc
index 8cf06ad4f9..38f120a1c8 100644
--- a/src/lib/dhcpsrv/mysql_lease_mgr.cc
+++ b/src/lib/dhcpsrv/mysql_lease_mgr.cc
@@ -1802,17 +1802,9 @@ MySqlLeaseMgr::MySqlLeaseMgr(const DatabaseConnection::ParameterMap& parameters)
// Create an initial context.
pool_.reset(new MySqlLeaseContextPool());
pool_->pool_.push_back(createContext());
-
- auto db_reconnect_ctl = pool_->pool_[0]->conn_.reconnectCtl();
-
- TimerMgr::instance()->registerTimer(timer_name_,
- std::bind(&MySqlLeaseMgr::dbReconnect, db_reconnect_ctl),
- db_reconnect_ctl->retryInterval(),
- asiolink::IntervalTimer::ONE_SHOT);
}
MySqlLeaseMgr::~MySqlLeaseMgr() {
- TimerMgr::instance()->unregisterTimer(timer_name_);
}
bool
@@ -1823,6 +1815,8 @@ MySqlLeaseMgr::dbReconnect(ReconnectCtlPtr db_reconnect_ctl) {
bool reopened = false;
+ const std::string timer_name = db_reconnect_ctl->timerName();
+
// At least one connection was lost.
try {
CfgDbAccessPtr cfg_db = CfgMgr::instance().getCurrentCfg()->getCfgDbAccess();
@@ -1837,8 +1831,9 @@ MySqlLeaseMgr::dbReconnect(ReconnectCtlPtr db_reconnect_ctl) {
if (reopened) {
// Cancel the timer.
- const std::string& timer_name = db_reconnect_ctl->timerName();
- TimerMgr::instance()->cancel(timer_name);
+ if (TimerMgr::instance()->isTimerRegistered(timer_name)) {
+ TimerMgr::instance()->unregisterTimer(timer_name);
+ }
DatabaseConnection::invokeDbRecoveredCallback(db_reconnect_ctl);
} else {
@@ -1847,6 +1842,11 @@ MySqlLeaseMgr::dbReconnect(ReconnectCtlPtr db_reconnect_ctl) {
LOG_ERROR(dhcpsrv_logger, DHCPSRV_MYSQL_LEASE_DB_RECONNECT_FAILED)
.arg(db_reconnect_ctl->maxRetries());
+ // Cancel the timer.
+ if (TimerMgr::instance()->isTimerRegistered(timer_name)) {
+ TimerMgr::instance()->unregisterTimer(timer_name);
+ }
+
DatabaseConnection::invokeDbFailedCallback(db_reconnect_ctl);
return (false);
@@ -1857,7 +1857,14 @@ MySqlLeaseMgr::dbReconnect(ReconnectCtlPtr db_reconnect_ctl) {
.arg(db_reconnect_ctl->maxRetries())
.arg(db_reconnect_ctl->retryInterval());
- TimerMgr::instance()->setup(db_reconnect_ctl->timerName());
+ // Start the timer.
+ if (!TimerMgr::instance()->isTimerRegistered(timer_name)) {
+ TimerMgr::instance()->registerTimer(timer_name,
+ std::bind(&MySqlLeaseMgr::dbReconnect, db_reconnect_ctl),
+ db_reconnect_ctl->retryInterval(),
+ asiolink::IntervalTimer::ONE_SHOT);
+ }
+ TimerMgr::instance()->setup(timer_name);
}
return (true);
diff --git a/src/lib/dhcpsrv/pgsql_host_data_source.cc b/src/lib/dhcpsrv/pgsql_host_data_source.cc
index ea7ef6bf3e..7f0a30cf50 100644
--- a/src/lib/dhcpsrv/pgsql_host_data_source.cc
+++ b/src/lib/dhcpsrv/pgsql_host_data_source.cc
@@ -2235,13 +2235,6 @@ PgSqlHostDataSourceImpl::PgSqlHostDataSourceImpl(const DatabaseConnection::Param
// Create an initial context.
pool_.reset(new PgSqlHostContextPool());
pool_->pool_.push_back(createContext());
-
- auto db_reconnect_ctl = pool_->pool_[0]->conn_.reconnectCtl();
-
- TimerMgr::instance()->registerTimer(timer_name_,
- std::bind(&PgSqlHostDataSourceImpl::dbReconnect, db_reconnect_ctl),
- db_reconnect_ctl->retryInterval(),
- asiolink::IntervalTimer::ONE_SHOT);
}
// Create context.
@@ -2284,7 +2277,6 @@ PgSqlHostDataSourceImpl::createContext() const {
}
PgSqlHostDataSourceImpl::~PgSqlHostDataSourceImpl() {
- TimerMgr::instance()->unregisterTimer(timer_name_);
}
bool
@@ -2295,6 +2287,8 @@ PgSqlHostDataSourceImpl::dbReconnect(ReconnectCtlPtr db_reconnect_ctl) {
bool reopened = false;
+ const std::string timer_name = db_reconnect_ctl->timerName();
+
// At least one connection was lost.
try {
CfgDbAccessPtr cfg_db = CfgMgr::instance().getCurrentCfg()->getCfgDbAccess();
@@ -2314,8 +2308,9 @@ PgSqlHostDataSourceImpl::dbReconnect(ReconnectCtlPtr db_reconnect_ctl) {
if (reopened) {
// Cancel the timer.
- const std::string& timer_name = db_reconnect_ctl->timerName();
- TimerMgr::instance()->cancel(timer_name);
+ if (TimerMgr::instance()->isTimerRegistered(timer_name)) {
+ TimerMgr::instance()->unregisterTimer(timer_name);
+ }
DatabaseConnection::invokeDbRecoveredCallback(db_reconnect_ctl);
} else {
@@ -2324,6 +2319,11 @@ PgSqlHostDataSourceImpl::dbReconnect(ReconnectCtlPtr db_reconnect_ctl) {
LOG_ERROR(dhcpsrv_logger, DHCPSRV_PGSQL_HOST_DB_RECONNECT_FAILED)
.arg(db_reconnect_ctl->maxRetries());
+ // Cancel the timer.
+ if (TimerMgr::instance()->isTimerRegistered(timer_name)) {
+ TimerMgr::instance()->unregisterTimer(timer_name);
+ }
+
DatabaseConnection::invokeDbFailedCallback(db_reconnect_ctl);
return (false);
@@ -2334,7 +2334,14 @@ PgSqlHostDataSourceImpl::dbReconnect(ReconnectCtlPtr db_reconnect_ctl) {
.arg(db_reconnect_ctl->maxRetries())
.arg(db_reconnect_ctl->retryInterval());
- TimerMgr::instance()->setup(db_reconnect_ctl->timerName());
+ // Start the timer.
+ if (!TimerMgr::instance()->isTimerRegistered(timer_name)) {
+ TimerMgr::instance()->registerTimer(timer_name,
+ std::bind(&PgSqlHostDataSourceImpl::dbReconnect, db_reconnect_ctl),
+ db_reconnect_ctl->retryInterval(),
+ asiolink::IntervalTimer::ONE_SHOT);
+ }
+ TimerMgr::instance()->setup(timer_name);
}
return (true);
diff --git a/src/lib/dhcpsrv/pgsql_lease_mgr.cc b/src/lib/dhcpsrv/pgsql_lease_mgr.cc
index 54aa910a5c..4ed51ad5fe 100644
--- a/src/lib/dhcpsrv/pgsql_lease_mgr.cc
+++ b/src/lib/dhcpsrv/pgsql_lease_mgr.cc
@@ -1236,17 +1236,9 @@ PgSqlLeaseMgr::PgSqlLeaseMgr(const DatabaseConnection::ParameterMap& parameters)
// Create an initial context.
pool_.reset(new PgSqlLeaseContextPool());
pool_->pool_.push_back(createContext());
-
- auto db_reconnect_ctl = pool_->pool_[0]->conn_.reconnectCtl();
-
- TimerMgr::instance()->registerTimer(timer_name_,
- std::bind(&PgSqlLeaseMgr::dbReconnect, db_reconnect_ctl),
- db_reconnect_ctl->retryInterval(),
- asiolink::IntervalTimer::ONE_SHOT);
}
PgSqlLeaseMgr::~PgSqlLeaseMgr() {
- TimerMgr::instance()->unregisterTimer(timer_name_);
}
bool
@@ -1255,6 +1247,8 @@ PgSqlLeaseMgr::dbReconnect(ReconnectCtlPtr db_reconnect_ctl) {
DatabaseConnection::invokeDbLostCallback(db_reconnect_ctl);
+ const std::string timer_name = db_reconnect_ctl->timerName();
+
bool reopened = false;
// At least one connection was lost.
@@ -1271,8 +1265,9 @@ PgSqlLeaseMgr::dbReconnect(ReconnectCtlPtr db_reconnect_ctl) {
if (reopened) {
// Cancel the timer.
- const std::string& timer_name = db_reconnect_ctl->timerName();
- TimerMgr::instance()->cancel(timer_name);
+ if (TimerMgr::instance()->isTimerRegistered(timer_name)) {
+ TimerMgr::instance()->unregisterTimer(timer_name);
+ }
DatabaseConnection::invokeDbRecoveredCallback(db_reconnect_ctl);
} else {
@@ -1281,6 +1276,11 @@ PgSqlLeaseMgr::dbReconnect(ReconnectCtlPtr db_reconnect_ctl) {
LOG_ERROR(dhcpsrv_logger, DHCPSRV_PGSQL_LEASE_DB_RECONNECT_FAILED)
.arg(db_reconnect_ctl->maxRetries());
+ // Cancel the timer.
+ if (TimerMgr::instance()->isTimerRegistered(timer_name)) {
+ TimerMgr::instance()->unregisterTimer(timer_name);
+ }
+
DatabaseConnection::invokeDbFailedCallback(db_reconnect_ctl);
return (false);
@@ -1291,7 +1291,14 @@ PgSqlLeaseMgr::dbReconnect(ReconnectCtlPtr db_reconnect_ctl) {
.arg(db_reconnect_ctl->maxRetries())
.arg(db_reconnect_ctl->retryInterval());
- TimerMgr::instance()->setup(db_reconnect_ctl->timerName());
+ // Start the timer.
+ if (!TimerMgr::instance()->isTimerRegistered(timer_name)) {
+ TimerMgr::instance()->registerTimer(timer_name,
+ std::bind(&PgSqlLeaseMgr::dbReconnect, db_reconnect_ctl),
+ db_reconnect_ctl->retryInterval(),
+ asiolink::IntervalTimer::ONE_SHOT);
+ }
+ TimerMgr::instance()->setup(timer_name);
}
return (true);
diff --git a/src/lib/dhcpsrv/tests/generic_lease_mgr_unittest.cc b/src/lib/dhcpsrv/tests/generic_lease_mgr_unittest.cc
index 38da5a309c..b52301e3e7 100644
--- a/src/lib/dhcpsrv/tests/generic_lease_mgr_unittest.cc
+++ b/src/lib/dhcpsrv/tests/generic_lease_mgr_unittest.cc
@@ -3274,37 +3274,85 @@ LeaseMgrDbLostCallbackTest::testNoCallbackOnOpenFailure() {
DatabaseConnection::db_lost_callback_ =
std::bind(&LeaseMgrDbLostCallbackTest::db_lost_callback, this, ph::_1);
- callback_called_ = false;
ASSERT_THROW(LeaseMgrFactory::create(invalidConnectString()),
DbOpenError);
io_service_->poll();
- EXPECT_FALSE(callback_called_);
+ EXPECT_EQ(0, db_lost_callback_called_);
+ EXPECT_EQ(0, db_recovered_callback_called_);
+ EXPECT_EQ(0, db_failed_callback_called_);
}
void
-LeaseMgrDbLostCallbackTest::testDbLostCallback() {
+LeaseMgrDbLostCallbackTest::testDbLostAndRecoveredCallback() {
// Set the connectivity lost callback.
DatabaseConnection::db_lost_callback_ =
std::bind(&LeaseMgrDbLostCallbackTest::db_lost_callback, this, ph::_1);
- // Find the most recently opened socket. Our SQL client's socket should
- // be the next one.
- int last_open_socket = findLastSocketFd();
+ // Set the connectivity recovered callback.
+ DatabaseConnection::db_recovered_callback_ =
+ std::bind(&LeaseMgrDbLostCallbackTest::db_recovered_callback, this, ph::_1);
- // Fill holes.
- FillFdHoles holes(last_open_socket);
+ // Set the connectivity failed callback.
+ DatabaseConnection::db_failed_callback_ =
+ std::bind(&LeaseMgrDbLostCallbackTest::db_failed_callback, this, ph::_1);
+
+ std::string access = validConnectString();
+ CfgMgr::instance().getCurrentCfg()->getCfgDbAccess()->setLeaseDbAccessString(access);
// Connect to the lease backend.
- ASSERT_NO_THROW(LeaseMgrFactory::create(validConnectString()));
+ ASSERT_NO_THROW(LeaseMgrFactory::create(access));
// The most recently opened socket should be for our SQL client.
int sql_socket = test::findLastSocketFd();
ASSERT_TRUE(sql_socket > -1);
- // Clear the callback invocation marker.
- callback_called_ = false;
+ // Verify we can execute a query. We do not care if
+ // we find a lease or not.
+ LeaseMgr& lm = LeaseMgrFactory::instance();
+
+ Lease4Ptr lease;
+ ASSERT_NO_THROW(lease = lm.getLease4(IOAddress("192.0.1.0")));
+
+ // Now close the sql socket out from under backend client
+ ASSERT_EQ(0, close(sql_socket));
+
+ // A query should fail with DbConnectionUnusable.
+ ASSERT_THROW(lease = lm.getLease4(IOAddress("192.0.1.0")),
+ DbConnectionUnusable);
+
+ io_service_->poll();
+
+ // Our lost and recovered connectivity callback should have been invoked.
+ EXPECT_EQ(1, db_lost_callback_called_);
+ EXPECT_EQ(1, db_recovered_callback_called_);
+ EXPECT_EQ(0, db_failed_callback_called_);
+}
+
+void
+LeaseMgrDbLostCallbackTest::testDbLostAndFailedCallback() {
+ // Set the connectivity lost callback.
+ DatabaseConnection::db_lost_callback_ =
+ std::bind(&LeaseMgrDbLostCallbackTest::db_lost_callback, this, ph::_1);
+
+ // Set the connectivity recovered callback.
+ DatabaseConnection::db_recovered_callback_ =
+ std::bind(&LeaseMgrDbLostCallbackTest::db_recovered_callback, this, ph::_1);
+
+ // Set the connectivity failed callback.
+ DatabaseConnection::db_failed_callback_ =
+ std::bind(&LeaseMgrDbLostCallbackTest::db_failed_callback, this, ph::_1);
+
+ std::string access = validConnectString();
+ CfgMgr::instance().getCurrentCfg()->getCfgDbAccess()->setLeaseDbAccessString(access);
+
+ // Connect to the lease backend.
+ ASSERT_NO_THROW(LeaseMgrFactory::create(access));
+
+ // The most recently opened socket should be for our SQL client.
+ int sql_socket = test::findLastSocketFd();
+ ASSERT_TRUE(sql_socket > -1);
// Verify we can execute a query. We do not care if
// we find a lease or not.
@@ -3313,6 +3361,126 @@ LeaseMgrDbLostCallbackTest::testDbLostCallback() {
Lease4Ptr lease;
ASSERT_NO_THROW(lease = lm.getLease4(IOAddress("192.0.1.0")));
+ access = invalidConnectString();
+ CfgMgr::instance().getCurrentCfg()->getCfgDbAccess()->setLeaseDbAccessString(access);
+
+ // Now close the sql socket out from under backend client
+ ASSERT_EQ(0, close(sql_socket));
+
+ // A query should fail with DbConnectionUnusable.
+ ASSERT_THROW(lease = lm.getLease4(IOAddress("192.0.1.0")),
+ DbConnectionUnusable);
+
+ io_service_->poll();
+
+ // Our lost and failed connectivity callback should have been invoked.
+ EXPECT_EQ(1, db_lost_callback_called_);
+ EXPECT_EQ(0, db_recovered_callback_called_);
+ EXPECT_EQ(1, db_failed_callback_called_);
+}
+
+void
+LeaseMgrDbLostCallbackTest::testDbLostAndRecoveredAfterTimeoutCallback() {
+ // Set the connectivity lost callback.
+ DatabaseConnection::db_lost_callback_ =
+ std::bind(&LeaseMgrDbLostCallbackTest::db_lost_callback, this, ph::_1);
+
+ // Set the connectivity recovered callback.
+ DatabaseConnection::db_recovered_callback_ =
+ std::bind(&LeaseMgrDbLostCallbackTest::db_recovered_callback, this, ph::_1);
+
+ // Set the connectivity failed callback.
+ DatabaseConnection::db_failed_callback_ =
+ std::bind(&LeaseMgrDbLostCallbackTest::db_failed_callback, this, ph::_1);
+
+ std::string access = validConnectString();
+ std::string extra = " max-reconnect-tries=2 reconnect-wait-time=1";
+ access += extra;
+ CfgMgr::instance().getCurrentCfg()->getCfgDbAccess()->setLeaseDbAccessString(access);
+
+ // Connect to the lease backend.
+ ASSERT_NO_THROW(LeaseMgrFactory::create(access));
+
+ // The most recently opened socket should be for our SQL client.
+ int sql_socket = test::findLastSocketFd();
+ ASSERT_TRUE(sql_socket > -1);
+
+ // Verify we can execute a query. We do not care if
+ // we find a lease or not.
+ LeaseMgr& lm = LeaseMgrFactory::instance();
+
+ Lease4Ptr lease;
+ ASSERT_NO_THROW(lease = lm.getLease4(IOAddress("192.0.1.0")));
+
+ access = invalidConnectString();
+ access += extra;
+ CfgMgr::instance().getCurrentCfg()->getCfgDbAccess()->setLeaseDbAccessString(access);
+
+ // Now close the sql socket out from under backend client
+ ASSERT_EQ(0, close(sql_socket));
+
+ // A query should fail with DbConnectionUnusable.
+ ASSERT_THROW(lease = lm.getLease4(IOAddress("192.0.1.0")),
+ DbConnectionUnusable);
+
+ io_service_->poll();
+
+ // Our lost connectivity callback should have been invoked.
+ EXPECT_EQ(1, db_lost_callback_called_);
+ EXPECT_EQ(0, db_recovered_callback_called_);
+ EXPECT_EQ(0, db_failed_callback_called_);
+
+ access = validConnectString();
+ access += extra;
+ CfgMgr::instance().getCurrentCfg()->getCfgDbAccess()->setLeaseDbAccessString(access);
+
+ sleep(1);
+
+ io_service_->poll();
+
+ // Our recovered connectivity callback should have been invoked.
+ EXPECT_EQ(2, db_lost_callback_called_);
+ EXPECT_EQ(1, db_recovered_callback_called_);
+ EXPECT_EQ(0, db_failed_callback_called_);
+}
+
+void
+LeaseMgrDbLostCallbackTest::testDbLostAndFailedAfterTimeoutCallback() {
+ // Set the connectivity lost callback.
+ DatabaseConnection::db_lost_callback_ =
+ std::bind(&LeaseMgrDbLostCallbackTest::db_lost_callback, this, ph::_1);
+
+ // Set the connectivity recovered callback.
+ DatabaseConnection::db_recovered_callback_ =
+ std::bind(&LeaseMgrDbLostCallbackTest::db_recovered_callback, this, ph::_1);
+
+ // Set the connectivity failed callback.
+ DatabaseConnection::db_failed_callback_ =
+ std::bind(&LeaseMgrDbLostCallbackTest::db_failed_callback, this, ph::_1);
+
+ std::string access = validConnectString();
+ std::string extra = " max-reconnect-tries=2 reconnect-wait-time=1";
+ access += extra;
+ CfgMgr::instance().getCurrentCfg()->getCfgDbAccess()->setLeaseDbAccessString(access);
+
+ // Connect to the lease backend.
+ ASSERT_NO_THROW(LeaseMgrFactory::create(access));
+
+ // The most recently opened socket should be for our SQL client.
+ int sql_socket = test::findLastSocketFd();
+ ASSERT_TRUE(sql_socket > -1);
+
+ // Verify we can execute a query. We do not care if
+ // we find a lease or not.
+ LeaseMgr& lm = LeaseMgrFactory::instance();
+
+ Lease4Ptr lease;
+ ASSERT_NO_THROW(lease = lm.getLease4(IOAddress("192.0.1.0")));
+
+ access = invalidConnectString();
+ access += extra;
+ CfgMgr::instance().getCurrentCfg()->getCfgDbAccess()->setLeaseDbAccessString(access);
+
// Now close the sql socket out from under backend client
ASSERT_EQ(0, close(sql_socket));
@@ -3323,7 +3491,18 @@ LeaseMgrDbLostCallbackTest::testDbLostCallback() {
io_service_->poll();
// Our lost connectivity callback should have been invoked.
- EXPECT_TRUE(callback_called_);
+ EXPECT_EQ(1, db_lost_callback_called_);
+ EXPECT_EQ(0, db_recovered_callback_called_);
+ EXPECT_EQ(0, db_failed_callback_called_);
+
+ sleep(1);
+
+ io_service_->poll();
+
+ // Our failed connectivity callback should have been invoked.
+ EXPECT_EQ(2, db_lost_callback_called_);
+ EXPECT_EQ(0, db_recovered_callback_called_);
+ EXPECT_EQ(1, db_failed_callback_called_);
}
void
diff --git a/src/lib/dhcpsrv/tests/generic_lease_mgr_unittest.h b/src/lib/dhcpsrv/tests/generic_lease_mgr_unittest.h
index 5f29872788..292356dbe9 100644
--- a/src/lib/dhcpsrv/tests/generic_lease_mgr_unittest.h
+++ b/src/lib/dhcpsrv/tests/generic_lease_mgr_unittest.h
@@ -9,6 +9,7 @@
#include <asiolink/io_service.h>
#include <dhcpsrv/lease_mgr.h>
+#include <dhcpsrv/timer_mgr.h>
#include <gtest/gtest.h>
@@ -526,15 +527,22 @@ public:
class LeaseMgrDbLostCallbackTest : public ::testing::Test {
public:
LeaseMgrDbLostCallbackTest()
- : callback_called_(false),
+ : db_lost_callback_called_(0), db_recovered_callback_called_(0),
+ db_failed_callback_called_(0),
io_service_(boost::make_shared<isc::asiolink::IOService>()) {
db::DatabaseConnection::db_lost_callback_ = 0;
+ db::DatabaseConnection::db_recovered_callback_ = 0;
+ db::DatabaseConnection::db_failed_callback_ = 0;
LeaseMgr::setIOService(io_service_);
+ TimerMgr::instance()->setIOService(io_service_);
}
virtual ~LeaseMgrDbLostCallbackTest() {
db::DatabaseConnection::db_lost_callback_ = 0;
+ db::DatabaseConnection::db_recovered_callback_ = 0;
+ db::DatabaseConnection::db_failed_callback_ = 0;
LeaseMgr::setIOService(isc::asiolink::IOServicePtr());
+ TimerMgr::instance()->unregisterTimers();
}
/// @brief Prepares the class for a test.
@@ -549,10 +557,10 @@ public:
/// we created and toss our lease manager.
virtual void TearDown();
- /// @brief Abstract method for destroying the back end specific shcema
+ /// @brief Abstract method for destroying the back end specific schema
virtual void destroySchema() = 0;
- /// @brief Abstract method for creating the back end specific shcema
+ /// @brief Abstract method for creating the back end specific schema
virtual void createSchema() = 0;
/// @brief Abstract method which returns the back end specific connection
@@ -570,25 +578,83 @@ public:
/// open should be handled directly by the application layer.
void testNoCallbackOnOpenFailure();
- /// @brief Verifies the host manager's behavior if DB connection is lost
+ /// @brief Verifies the lease manager's behavior if DB connection is lost
///
/// This function creates a lease manager with an back end that
/// supports connectivity lost callback (currently only MySQL and
/// PostgreSQL currently). It verifies connectivity by issuing a known
/// valid query. Next it simulates connectivity lost by identifying and
- /// closing the socket connection to the host backend. It then reissues
+ /// closing the socket connection to the lease backend. It then reissues
/// the query and verifies that:
/// -# The Query throws DbOperationError (rather than exiting)
/// -# The registered DbLostCallback was invoked
- void testDbLostCallback();
+ /// -# The registered DbRecoveredCallback was invoked
+ void testDbLostAndRecoveredCallback();
- /// @brief Callback function registered with the host manager
+ /// @brief Verifies the lease manager's behavior if DB connection is lost
+ ///
+ /// This function creates a lease manager with an back end that
+ /// supports connectivity lost callback (currently only MySQL and
+ /// PostgreSQL currently). It verifies connectivity by issuing a known
+ /// valid query. Next it simulates connectivity lost by identifying and
+ /// closing the socket connection to the lease backend. It then reissues
+ /// the query and verifies that:
+ /// -# The Query throws DbOperationError (rather than exiting)
+ /// -# The registered DbLostCallback was invoked
+ /// -# The registered DbFailedCallback was invoked
+ void testDbLostAndFailedCallback();
+
+ /// @brief Verifies the lease manager's behavior if DB connection is lost
+ ///
+ /// This function creates a lease manager with an back end that
+ /// supports connectivity lost callback (currently only MySQL and
+ /// PostgreSQL currently). It verifies connectivity by issuing a known
+ /// valid query. Next it simulates connectivity lost by identifyingLost and
+ /// closing the socket connection to the lease backend. It then reissues
+ /// the query and verifies that:
+ /// -# The Query throws DbOperationError (rather than exiting)
+ /// -# The registered DbLostCallback was invoked
+ /// -# The registered DbRecoveredCallback was invoked after two reconnect
+ /// attempts (once failing and second triggered by timer)
+ void testDbLostAndRecoveredAfterTimeoutCallback();
+
+ /// @brief Verifies the lease manager's behavior if DB connection is lost
+ ///
+ /// This function creates a lease manager with an back end that
+ /// supports connectivity lost callback (currently only MySQL and
+ /// PostgreSQL currently). It verifies connectivity by issuing a known
+ /// valid query. Next it simulates connectivity lost by identifyingLost and
+ /// closing the socket connection to the lease backend. It then reissues
+ /// the query and verifies that:
+ /// -# The Query throws DbOperationError (rather than exiting)
+ /// -# The registered DbLostCallback was invoked
+ /// -# The registered DbFailedCallback was invoked after two reconnect
+ /// attempts (once failing and second triggered by timer)
+ void testDbLostAndFailedAfterTimeoutCallback();
+
+ /// @brief Callback function registered with the lease manager
bool db_lost_callback(db::ReconnectCtlPtr /* not_used */) {
- return (callback_called_ = true);
+ return (++db_lost_callback_called_);
}
/// @brief Flag used to detect calls to db_lost_callback function
- bool callback_called_;
+ uint32_t db_lost_callback_called_;
+
+ /// @brief Callback function registered with the lease manager
+ bool db_recovered_callback(db::ReconnectCtlPtr /* not_used */) {
+ return (++db_recovered_callback_called_);
+ }
+
+ /// @brief Flag used to detect calls to db_recovered_callback function
+ uint32_t db_recovered_callback_called_;
+
+ /// @brief Callback function registered with the lease manager
+ bool db_failed_callback(db::ReconnectCtlPtr /* not_used */) {
+ return (++db_failed_callback_called_);
+ }
+
+ /// @brief Flag used to detect calls to db_failed_callback function
+ uint32_t db_failed_callback_called_;
/// The IOService object, used for all ASIO operations.
isc::asiolink::IOServicePtr io_service_;
diff --git a/src/lib/dhcpsrv/tests/host_mgr_unittest.cc b/src/lib/dhcpsrv/tests/host_mgr_unittest.cc
index 8e3c235e9c..b5522b2fd4 100644
--- a/src/lib/dhcpsrv/tests/host_mgr_unittest.cc
+++ b/src/lib/dhcpsrv/tests/host_mgr_unittest.cc
@@ -1837,6 +1837,7 @@ TEST_F(PostgreSQLHostMgrTest, setIPReservationUnique) {
TEST_F(PostgreSQLHostMgrDbLostCallbackTest, testDbLostCallback) {
testDbLostCallback();
}
+
#endif
// The following tests require Cassandra enabled.
diff --git a/src/lib/dhcpsrv/tests/mysql_lease_mgr_unittest.cc b/src/lib/dhcpsrv/tests/mysql_lease_mgr_unittest.cc
index 88aa540004..731257262d 100644
--- a/src/lib/dhcpsrv/tests/mysql_lease_mgr_unittest.cc
+++ b/src/lib/dhcpsrv/tests/mysql_lease_mgr_unittest.cc
@@ -981,15 +981,51 @@ TEST_F(MySQLLeaseMgrDbLostCallbackTest, testNoCallbackOnOpenFailureMultiThreadin
}
/// @brief Verifies that loss of connectivity to MySQL is handled correctly.
-TEST_F(MySQLLeaseMgrDbLostCallbackTest, testDbLostCallback) {
+TEST_F(MySQLLeaseMgrDbLostCallbackTest, testDbLostAndRecoveredCallback) {
MultiThreadingTest mt(false);
- testDbLostCallback();
+ testDbLostAndRecoveredCallback();
}
/// @brief Verifies that loss of connectivity to MySQL is handled correctly.
-TEST_F(MySQLLeaseMgrDbLostCallbackTest, testDbLostCallbackMultiThreading) {
+TEST_F(MySQLLeaseMgrDbLostCallbackTest, testDbLostAndRecoveredCallbackMultiThreading) {
MultiThreadingTest mt(true);
- testDbLostCallback();
+ testDbLostAndRecoveredCallback();
+}
+
+/// @brief Verifies that loss of connectivity to MySQL is handled correctly.
+TEST_F(MySQLLeaseMgrDbLostCallbackTest, testDbLostAndFailedCallback) {
+ MultiThreadingTest mt(false);
+ testDbLostAndFailedCallback();
+}
+
+/// @brief Verifies that loss of connectivity to MySQL is handled correctly.
+TEST_F(MySQLLeaseMgrDbLostCallbackTest, testDbLostAndFailedCallbackMultiThreading) {
+ MultiThreadingTest mt(true);
+ testDbLostAndFailedCallback();
+}
+
+/// @brief Verifies that loss of connectivity to MySQL is handled correctly.
+TEST_F(MySQLLeaseMgrDbLostCallbackTest, testDbLostAndRecoveredAfterTimeoutCallback) {
+ MultiThreadingTest mt(false);
+ testDbLostAndRecoveredAfterTimeoutCallback();
+}
+
+/// @brief Verifies that loss of connectivity to MySQL is handled correctly.
+TEST_F(MySQLLeaseMgrDbLostCallbackTest, testDbLostAndRecoveredAfterTimeoutCallbackMultiThreading) {
+ MultiThreadingTest mt(true);
+ testDbLostAndRecoveredAfterTimeoutCallback();
+}
+
+/// @brief Verifies that loss of connectivity to MySQL is handled correctly.
+TEST_F(MySQLLeaseMgrDbLostCallbackTest, testDbLostAndFailedAfterTimeoutCallback) {
+ MultiThreadingTest mt(false);
+ testDbLostAndFailedAfterTimeoutCallback();
+}
+
+/// @brief Verifies that loss of connectivity to MySQL is handled correctly.
+TEST_F(MySQLLeaseMgrDbLostCallbackTest, testDbLostAndFailedAfterTimeoutCallbackMultiThreading) {
+ MultiThreadingTest mt(true);
+ testDbLostAndFailedAfterTimeoutCallback();
}
/// @brief Tests v4 lease stats query variants.
diff --git a/src/lib/dhcpsrv/tests/pgsql_lease_mgr_unittest.cc b/src/lib/dhcpsrv/tests/pgsql_lease_mgr_unittest.cc
index 988ea8895e..a28bf23ea8 100644
--- a/src/lib/dhcpsrv/tests/pgsql_lease_mgr_unittest.cc
+++ b/src/lib/dhcpsrv/tests/pgsql_lease_mgr_unittest.cc
@@ -937,15 +937,51 @@ TEST_F(PgSqlLeaseMgrDbLostCallbackTest, testNoCallbackOnOpenFailureMultiThreadin
}
/// @brief Verifies that loss of connectivity to PostgreSQL is handled correctly.
-TEST_F(PgSqlLeaseMgrDbLostCallbackTest, testDbLostCallback) {
+TEST_F(PgSqlLeaseMgrDbLostCallbackTest, testDbLostAndRecoveredCallback) {
MultiThreadingTest mt(false);
- testDbLostCallback();
+ testDbLostAndRecoveredCallback();
}
/// @brief Verifies that loss of connectivity to PostgreSQL is handled correctly.
-TEST_F(PgSqlLeaseMgrDbLostCallbackTest, testDbLostCallbackMultiThreading) {
+TEST_F(PgSqlLeaseMgrDbLostCallbackTest, testDbLostAndRecoveredCallbackMultiThreading) {
MultiThreadingTest mt(true);
- testDbLostCallback();
+ testDbLostAndRecoveredCallback();
+}
+
+/// @brief Verifies that loss of connectivity to PostgreSQL is handled correctly.
+TEST_F(PgSqlLeaseMgrDbLostCallbackTest, testDbLostAndFailedCallback) {
+ MultiThreadingTest mt(false);
+ testDbLostAndFailedCallback();
+}
+
+/// @brief Verifies that loss of connectivity to PostgreSQL is handled correctly.
+TEST_F(PgSqlLeaseMgrDbLostCallbackTest, testDbLostAndFailedCallbackMultiThreading) {
+ MultiThreadingTest mt(true);
+ testDbLostAndFailedCallback();
+}
+
+/// @brief Verifies that loss of connectivity to PostgreSQL is handled correctly.
+TEST_F(PgSqlLeaseMgrDbLostCallbackTest, testDbLostAndRecoveredAfterTimeoutCallback) {
+ MultiThreadingTest mt(false);
+ testDbLostAndRecoveredAfterTimeoutCallback();
+}
+
+/// @brief Verifies that loss of connectivity to PostgreSQL is handled correctly.
+TEST_F(PgSqlLeaseMgrDbLostCallbackTest, testDbLostAndRecoveredAfterTimeoutCallbackMultiThreading) {
+ MultiThreadingTest mt(true);
+ testDbLostAndRecoveredAfterTimeoutCallback();
+}
+
+/// @brief Verifies that loss of connectivity to PostgreSQL is handled correctly.
+TEST_F(PgSqlLeaseMgrDbLostCallbackTest, testDbLostAndFailedAfterTimeoutCallback) {
+ MultiThreadingTest mt(false);
+ testDbLostAndFailedAfterTimeoutCallback();
+}
+
+/// @brief Verifies that loss of connectivity to PostgreSQL is handled correctly.
+TEST_F(PgSqlLeaseMgrDbLostCallbackTest, testDbLostAndFailedAfterTimeoutCallbackMultiThreading) {
+ MultiThreadingTest mt(true);
+ testDbLostAndFailedAfterTimeoutCallback();
}
/// @brief Tests v4 lease stats query variants.