}
ControlledDhcpv4Srv::ControlledDhcpv4Srv(uint16_t port /*= DHCP4_SERVER_PORT*/)
- : Dhcpv4Srv(port), io_service_(), timer_mgr_(TimerMgr::instance()),
- db_reconnect_ctl_(NULL) {
+ : Dhcpv4Srv(port), io_service_(), timer_mgr_(TimerMgr::instance()) {
if (getInstance()) {
isc_throw(InvalidOperation,
"There is another Dhcpv4Srv instance already.");
}
void
-ControlledDhcpv4Srv::dbReconnect() {
+ControlledDhcpv4Srv::dbReconnect(ReconnectCtlPtr db_reconnect_ctl) {
bool reopened = false;
// Re-open lease and host database with new parameters.
network_state_.enableService();
// Toss the reconnect control, we're done with it
- db_reconnect_ctl_.reset();
+ db_reconnect_ctl.reset();
} else {
- if (!db_reconnect_ctl_->checkRetries()) {
+ if (!db_reconnect_ctl->checkRetries()) {
LOG_ERROR(dhcp4_logger, DHCP4_DB_RECONNECT_RETRIES_EXHAUSTED)
- .arg(db_reconnect_ctl_->maxRetries());
+ .arg(db_reconnect_ctl->maxRetries());
shutdown();
return;
}
LOG_INFO(dhcp4_logger, DHCP4_DB_RECONNECT_ATTEMPT_SCHEDULE)
- .arg(db_reconnect_ctl_->maxRetries() - db_reconnect_ctl_->retriesLeft() + 1)
- .arg(db_reconnect_ctl_->maxRetries())
- .arg(db_reconnect_ctl_->retryInterval());
+ .arg(db_reconnect_ctl->maxRetries() - db_reconnect_ctl->retriesLeft() + 1)
+ .arg(db_reconnect_ctl->maxRetries())
+ .arg(db_reconnect_ctl->retryInterval());
if (!TimerMgr::instance()->isTimerRegistered("Dhcp4DbReconnectTimer")) {
TimerMgr::instance()->registerTimer("Dhcp4DbReconnectTimer",
- boost::bind(&ControlledDhcpv4Srv::dbReconnect, this),
- db_reconnect_ctl_->retryInterval() * 1000,
+ boost::bind(&ControlledDhcpv4Srv::dbReconnect, this,
+ db_reconnect_ctl),
+ db_reconnect_ctl->retryInterval() * 1000,
asiolink::IntervalTimer::ONE_SHOT);
}
return(false);
}
- // Save the reconnect control
- db_reconnect_ctl_ = db_reconnect_ctl;
-
// Invoke reconnect method
- dbReconnect();
+ dbReconnect(db_reconnect_ctl);
return(true);
}
void deleteExpiredReclaimedLeases(const uint32_t secs);
/// @brief Attempts to reconnect the server to the DB backend managers
- void dbReconnect();
+ ///
+ /// This is a self-rescheduling function that attempts to reconnect to the
+ /// server's DB backends after connectivity to one or more have been
+ /// lost. Upon entry it will attempt to reconnect via @ref CfgDdbAccess::
+ /// createManagers. If this is succesful, 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
+ ///
+ void dbReconnect(ReconnectCtlPtr db_reconnect_ctl);
/// @brief Callback DB backends should invoke upon loss of connectivity
+ ///
+ /// This function is invoked by DB backends when they detect a loss of
+ /// connectivity. The parameter, db_reconnect_ctl, conveys the configured
+ /// maximum number of reconnect retries as well as the interval to wait
+ /// between retry attempts.
+ ///
+ /// If either value is zero, reconnect is presumed to be disabled and
+ /// the function will returns false. This instructs the DB backend
+ /// layer (the caller) to treat the connectivity loss as fatal.
+ ///
+ /// Otherwise, the function saves db_reconnect_ctl and invokes
+ /// dbReconnect to initiate the reconnect process.
+ ///
+ /// @param db_reconnect_ctl pointer to the ReconnectCtl containing the
+ /// configured reconnect parameters
+ ///
+ /// @return false if reconnect is not configured, true otherwise
bool dbLostCallback(ReconnectCtlPtr db_reconnect_ctl);
/// @brief Static pointer to the sole instance of the DHCP server.
/// Shared pointer to the instance of timer @c TimerMgr is held here to
/// make sure that the @c TimerMgr outlives instance of this class.
TimerMgrPtr timer_mgr_;
-
- /// @brief Pointer the current DB reconnect control values
- ReconnectCtlPtr db_reconnect_ctl_;
};
}; // namespace isc::dhcp
}
ControlledDhcpv6Srv::ControlledDhcpv6Srv(uint16_t port)
- : Dhcpv6Srv(port), io_service_(), timer_mgr_(TimerMgr::instance()),
- db_reconnect_ctl_(NULL) {
+ : Dhcpv6Srv(port), io_service_(), timer_mgr_(TimerMgr::instance()) {
if (server_) {
isc_throw(InvalidOperation,
"There is another Dhcpv6Srv instance already.");
}
void
-ControlledDhcpv6Srv::dbReconnect() {
+ControlledDhcpv6Srv::dbReconnect(ReconnectCtlPtr db_reconnect_ctl) {
bool reopened = false;
// Re-open lease and host database with new parameters.
network_state_.enableService();
// Toss the reconnct control, we're done with it
- db_reconnect_ctl_.reset();
+ db_reconnect_ctl.reset();
} else {
- if (!db_reconnect_ctl_->checkRetries()) {
+ if (!db_reconnect_ctl->checkRetries()) {
LOG_ERROR(dhcp6_logger, DHCP6_DB_RECONNECT_RETRIES_EXHAUSTED)
- .arg(db_reconnect_ctl_->maxRetries());
+ .arg(db_reconnect_ctl->maxRetries());
shutdown();
return;
}
LOG_INFO(dhcp6_logger, DHCP6_DB_RECONNECT_ATTEMPT_SCHEDULE)
- .arg(db_reconnect_ctl_->maxRetries() - db_reconnect_ctl_->retriesLeft() + 1)
- .arg(db_reconnect_ctl_->maxRetries())
- .arg(db_reconnect_ctl_->retryInterval());
+ .arg(db_reconnect_ctl->maxRetries() - db_reconnect_ctl->retriesLeft() + 1)
+ .arg(db_reconnect_ctl->maxRetries())
+ .arg(db_reconnect_ctl->retryInterval());
if (!TimerMgr::instance()->isTimerRegistered("Dhcp6DbReconnectTimer")) {
TimerMgr::instance()->registerTimer("Dhcp6DbReconnectTimer",
- boost::bind(&ControlledDhcpv6Srv::dbReconnect, this),
- db_reconnect_ctl_->retryInterval() * 1000,
+ boost::bind(&ControlledDhcpv6Srv::dbReconnect, this,
+ db_reconnect_ctl),
+ db_reconnect_ctl->retryInterval() * 1000,
asiolink::IntervalTimer::ONE_SHOT);
}
return(false);
}
- // Save the reconnect control
- db_reconnect_ctl_ = db_reconnect_ctl;
-
// Invoke reconnect method
- dbReconnect();
+ dbReconnect(db_reconnect_ctl);
return(true);
}
void deleteExpiredReclaimedLeases(const uint32_t secs);
/// @brief Attempts to reconnect the server to the DB backend managers
- void dbReconnect();
+ ///
+ /// This is a self-rescheduling function that attempts to reconnect to the
+ /// server's DB backends after connectivity to one or more have been
+ /// lost. Upon entry it will attempt to reconnect via @ref CfgDdbAccess::
+ /// createManagers. If this is succesful, 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
+ ///
+ void dbReconnect(ReconnectCtlPtr db_reconnect_ctl);
/// @brief Callback DB backends should invoke upon loss of connectivity
+ ///
+ /// This function is invoked by DB backends when they detect a loss of
+ /// connectivity. The parameter, db_reconnect_ctl, conveys the configured
+ /// maximum number of reconnect retries as well as the interval to wait
+ /// between retry attempts.
+ ///
+ /// If either value is zero, reconnect is presumed to be disabled and
+ /// the function will returns false. This instructs the DB backend
+ /// layer (the caller) to treat the connectivity loss as fatal.
+ ///
+ /// Otherwise, the function saves db_reconnect_ctl and invokes
+ /// dbReconnect to initiate the reconnect process.
+ ///
+ /// @param db_reconnect_ctl pointer to the ReconnectCtl containing the
+ /// configured reconnect parameters
bool dbLostCallback(ReconnectCtlPtr db_reconnect_ctl);
/// @brief Static pointer to the sole instance of the DHCP server.
/// Shared pointer to the instance of timer @c TimerMgr is held here to
/// make sure that the @c TimerMgr outlives instance of this class.
TimerMgrPtr timer_mgr_;
-
- /// @brief Pointer the current DB reconnect control values
- ReconnectCtlPtr db_reconnect_ctl_;
};
}; // namespace isc::dhcp
void
-CfgDbAccess::createManagers(DatabaseConnection::Callback db_lost_callback) const {
+CfgDbAccess::createManagers(DatabaseConnection::DbLostCallback db_lost_callback) const {
// Recreate lease manager.
LeaseMgrFactory::destroy();
LeaseMgrFactory::create(getLeaseDbAccessString(), db_lost_callback);
/// @param db_lost_callback function to invoke if connectivity to
/// either the lease or host managers, once established, is subsequently
/// lost.
- void createManagers(DatabaseConnection::Callback db_lost_callback = NULL) const;
+ void createManagers(DatabaseConnection::DbLostCallback db_lost_callback = NULL) const;
/// @brief Unparse an access string
///
typedef std::map<std::string, std::string> ParameterMap;
/// @brief Defines a callback prototype for propogating events upward
- /// typedef boost::function<bool (const ParameterMap& parameters)> Callback;
- typedef boost::function<bool (ReconnectCtlPtr db_retry)> Callback;
+ typedef boost::function<bool (ReconnectCtlPtr db_retry)> DbLostCallback;
/// @brief Constructor
///
/// @param db_lost_callback Optional call back function to invoke if a
/// successfully open connection subsequently fails
DatabaseConnection(const ParameterMap& parameters,
- Callback db_lost_callback = NULL)
+ DbLostCallback db_lost_callback = NULL)
:parameters_(parameters), db_lost_callback_(db_lost_callback) {
}
protected:
/// @brief Optional function to invoke if the connectivity is lost
- Callback db_lost_callback_;
+ DbLostCallback db_lost_callback_;
};
}; // end of isc::dhcp namespace
void
HostDataSourceFactory::create(const std::string& dbaccess,
- DatabaseConnection::Callback db_lost_callback) {
+ DatabaseConnection::DbLostCallback db_lost_callback) {
// Parse the access string and create a redacted string for logging.
DatabaseConnection::ParameterMap parameters =
DatabaseConnection::parse(dbaccess);
/// @throw isc::dhcp::InvalidType The "type" keyword in dbaccess does not
/// identify a supported backend.
static void create(const std::string& dbaccess,
- DatabaseConnection::Callback db_lost_callback = NULL);
+ DatabaseConnection::DbLostCallback db_lost_callback = NULL);
/// @brief Destroy host data source
///
void
HostMgr::create(const std::string& access,
- DatabaseConnection::Callback db_lost_callback) {
+ DatabaseConnection::DbLostCallback db_lost_callback) {
getHostMgrPtr().reset(new HostMgr());
if (!access.empty()) {
/// @param db_lost_callback function to invoke if connectivity to
/// the host database is lost.
static void create(const std::string& access = "",
- DatabaseConnection::Callback db_lost_callback = NULL);
+ DatabaseConnection::DbLostCallback db_lost_callback = NULL);
/// @brief Returns a sole instance of the @c HostMgr.
///
void
LeaseMgrFactory::create(const std::string& dbaccess,
- DatabaseConnection::Callback db_lost_callback) {
+ DatabaseConnection::DbLostCallback db_lost_callback) {
const std::string type = "type";
// Parse the access string and create a redacted string for logging.
/// @throw isc::dhcp::InvalidType The "type" keyword in dbaccess does not
/// identify a supported backend.
static void create(const std::string& dbaccess,
- DatabaseConnection::Callback db_lost_callback = NULL);
+ DatabaseConnection::DbLostCallback db_lost_callback = NULL);
/// @brief Destroy lease manager
///
}
PgSqlConnection(const ParameterMap& parameters,
- Callback db_lost_callback)
+ DbLostCallback db_lost_callback)
: DatabaseConnection(parameters, db_lost_callback) {
}
/// This constructor opens database connection and initializes prepared
/// statements used in the queries.
PgSqlHostDataSourceImpl(const PgSqlConnection::ParameterMap& parameters,
- DatabaseConnection::Callback db_lost_callback);
+ DatabaseConnection::DbLostCallback db_lost_callback);
/// @brief Destructor.
~PgSqlHostDataSourceImpl();
PgSqlHostDataSourceImpl::
PgSqlHostDataSourceImpl(const PgSqlConnection::ParameterMap& parameters,
- DatabaseConnection::Callback db_lost_callback)
+ DatabaseConnection::DbLostCallback db_lost_callback)
: host_exchange_(new PgSqlHostWithOptionsExchange(PgSqlHostWithOptionsExchange::DHCP4_ONLY)),
host_ipv6_exchange_(new PgSqlHostIPv6Exchange(PgSqlHostWithOptionsExchange::DHCP6_ONLY)),
host_ipv46_exchange_(new PgSqlHostIPv6Exchange(PgSqlHostWithOptionsExchange::
PgSqlHostDataSource::
PgSqlHostDataSource(const PgSqlConnection::ParameterMap& parameters,
- DatabaseConnection::Callback db_lost_callback)
+ DatabaseConnection::DbLostCallback db_lost_callback)
: impl_(new PgSqlHostDataSourceImpl(parameters, db_lost_callback)) {
}
/// @throw isc::dhcp::DbOperationError An operation on the open database has
/// failed.
PgSqlHostDataSource(const DatabaseConnection::ParameterMap& parameters,
- DatabaseConnection::Callback db_lost_callback = NULL);
+ DatabaseConnection::DbLostCallback db_lost_callback = NULL);
/// @brief Virtual destructor.
/// Frees database resources and closes the database connection through
};
PgSqlLeaseMgr::PgSqlLeaseMgr(const DatabaseConnection::ParameterMap& parameters,
- DatabaseConnection::Callback db_lost_callback)
+ DatabaseConnection::DbLostCallback db_lost_callback)
: LeaseMgr(), exchange4_(new PgSqlLease4Exchange()),
exchange6_(new PgSqlLease6Exchange()), conn_(parameters, db_lost_callback) {
conn_.openDatabase();
/// @throw isc::dhcp::DbOperationError An operation on the open database has
/// failed.
PgSqlLeaseMgr(const DatabaseConnection::ParameterMap& parameters,
- DatabaseConnection::Callback db_lost_callback = NULL);
+ DatabaseConnection::DbLostCallback db_lost_callback = NULL);
/// @brief Destructor (closes database)
virtual ~PgSqlLeaseMgr();
using namespace isc::dhcp;
+/// @brief Test fixture for excersizing DbLostCallback invocation
class DatabaseConnectionCallbackTest : public ::testing::Test {
public:
+ /// Constructor
DatabaseConnectionCallbackTest()
: db_reconnect_ctl_(0) {
}
- bool dbLostCallback(ReconnectCtlPtr db_conn_retry) {
- if (!db_conn_retry) {
- isc_throw(isc::BadValue, "db_conn_retry should not null");
+ /// @brief Callback to register with a DatabaseConnection
+ ///
+ /// @param db_reconnect_ctl ReconnectCtl containing reconnect
+ /// parameters
+ bool dbLostCallback(ReconnectCtlPtr db_reconnect_ctl) {
+ if (!db_reconnect_ctl) {
+ isc_throw(isc::BadValue, "db_reconnect_ctl should not null");
}
- db_reconnect_ctl_ = db_conn_retry;
+ db_reconnect_ctl_ = db_reconnect_ctl;
return (true);
}
+ /// @brief Retainer for the control passed into the callback
ReconnectCtlPtr db_reconnect_ctl_;
};
EXPECT_THROW(datasrc.getParameter("param3"), isc::BadValue);
}
+/// @brief NoDbLostCallback
+///
+/// This test verifies that DatabaseConnection::invokeDbLostCallback
+/// returns a false if there is connection has no registered
+/// DbLostCallback.
TEST_F(DatabaseConnectionCallbackTest, NoDbLostCallback) {
DatabaseConnection::ParameterMap pmap;
pmap[std::string("max-reconnect-tries")] = std::string("3");
EXPECT_FALSE(db_reconnect_ctl_);
}
+
+/// @brief NoDbLostCallback
+///
+/// This test verifies that DatabaseConnection::invokeDbLostCallback
+/// safely invokes the registered DbLostCallback. It also tests
+/// operation of DbReconnectCtl retry accounting methods.
TEST_F(DatabaseConnectionCallbackTest, dbLostCallback) {
+ /// Create a Database configuration that includes the reconnect
+ /// control parameters.
DatabaseConnection::ParameterMap pmap;
pmap[std::string("max-reconnect-tries")] = std::string("3");
pmap[std::string("reconnect-wait-time")] = std::string("60");
+
+ /// Create the connection with a DbLostCallback.
DatabaseConnection datasrc(pmap, boost::bind(&DatabaseConnectionCallbackTest
::dbLostCallback, this, _1));
+
+ /// We should be able to invoke the callback and glean
+ /// the correct reconnect contorl parameters from it.
bool ret;
ASSERT_NO_THROW(ret = datasrc.invokeDbLostCallback());
EXPECT_TRUE(ret);
ASSERT_EQ(3, db_reconnect_ctl_->retriesLeft());
EXPECT_EQ(60, db_reconnect_ctl_->retryInterval());
+ /// Verify that checkRetries() correctly decrements
+ /// down to zero, and that retriesLeft() returns
+ /// the correct value.
for (int i = 3; i > 1 ; --i) {
ASSERT_EQ(i, db_reconnect_ctl_->retriesLeft());
ASSERT_TRUE(db_reconnect_ctl_->checkRetries());
}
+ /// Retries are exhausted, verify that's reflected.
EXPECT_FALSE(db_reconnect_ctl_->checkRetries());
EXPECT_EQ(0, db_reconnect_ctl_->retriesLeft());
EXPECT_EQ(3, db_reconnect_ctl_->maxRetries());