// Disable service until the connection is recovered.
if (db_reconnect_ctl->retriesLeft() == db_reconnect_ctl->maxRetries() &&
db_reconnect_ctl->alterServiceState()) {
- network_state_->disableService(NetworkState::DB_CONNECTION);
+ network_state_->disableService(NetworkState::DB_CONNECTION + db_reconnect_ctl->id());
}
LOG_INFO(dhcp4_logger, DHCP4_DB_RECONNECT_LOST_CONNECTION);
}
// Enable service after the connection is recovered.
- if (db_reconnect_ctl->alterServiceState()) {
- network_state_->enableService(NetworkState::DB_CONNECTION);
+ if (db_reconnect_ctl->retriesLeft() != db_reconnect_ctl->maxRetries() &&
+ db_reconnect_ctl->alterServiceState()) {
+ network_state_->enableService(NetworkState::DB_CONNECTION + db_reconnect_ctl->id());
}
LOG_INFO(dhcp4_logger, DHCP4_DB_RECONNECT_SUCCEEDED);
// Disable service until the connection is recovered.
if (db_reconnect_ctl->retriesLeft() == db_reconnect_ctl->maxRetries() &&
db_reconnect_ctl->alterServiceState()) {
- network_state_->disableService(NetworkState::DB_CONNECTION);
+ network_state_->disableService(NetworkState::DB_CONNECTION + db_reconnect_ctl->id());
}
LOG_INFO(dhcp6_logger, DHCP6_DB_RECONNECT_LOST_CONNECTION);
}
// Enable service after the connection is recovered.
- if (db_reconnect_ctl->alterServiceState()) {
- network_state_->enableService(NetworkState::DB_CONNECTION);
+ if (db_reconnect_ctl->retriesLeft() != db_reconnect_ctl->maxRetries() &&
+ db_reconnect_ctl->alterServiceState()) {
+ network_state_->enableService(NetworkState::DB_CONNECTION + db_reconnect_ctl->id());
}
LOG_INFO(dhcp6_logger, DHCP6_DB_RECONNECT_SUCCEEDED);
bool do_exit = false;
const std::string timer_name = db_reconnect_ctl->timerName();
+ bool check = db_reconnect_ctl->checkRetries();
// At least one connection was lost.
try {
return (false);
}
} else {
- if (!db_reconnect_ctl->checkRetries()) {
+ if (!check) {
// We're out of retries, log it and initiate shutdown.
LOG_ERROR(mysql_cb_logger, MYSQL_CB_RECONNECT_FAILED4)
.arg(db_reconnect_ctl->maxRetries());
bool do_exit = false;
const std::string timer_name = db_reconnect_ctl->timerName();
+ bool check = db_reconnect_ctl->checkRetries();
// At least one connection was lost.
try {
return (false);
}
} else {
- if (!db_reconnect_ctl->checkRetries()) {
+ if (!check) {
// We're out of retries, log it and initiate shutdown.
LOG_ERROR(mysql_cb_logger, MYSQL_CB_RECONNECT_FAILED6)
.arg(db_reconnect_ctl->maxRetries());
#include <asiolink/io_address.h>
#include <config_backend/constants.h>
#include <dhcp/option_space.h>
+#include <dhcpsrv/network_state.h>
#include <dhcpsrv/timer_mgr.h>
#include <util/buffer.h>
MySqlConnection::ensureSchemaVersion(parameters, db_reconnect_callback, timer_name_);
// Create ReconnectCtl for this connection.
- conn_.makeReconnectCtl(timer_name_);
+ conn_.makeReconnectCtl(timer_name_, NetworkState::DB_CONNECTION + 21);
// Open the database.
conn_.openDatabase();
#include <dhcpsrv/cfgmgr.h>
#include <dhcpsrv/dhcpsrv_log.h>
#include <dhcpsrv/host_mgr.h>
+#include <dhcpsrv/network_state.h>
+#include <dhcpsrv/timer_mgr.h>
#include <mysql_hb_log.h>
#include <mysql_host_data_source.h>
-#include <dhcpsrv/timer_mgr.h>
#include <util/buffer.h>
#include <util/multi_threading_mgr.h>
#include <util/optional.h>
ctx->host_option_exchange_.reset(new MySqlOptionExchange());
// Create ReconnectCtl for this connection.
- ctx->conn_.makeReconnectCtl(timer_name_);
+ ctx->conn_.makeReconnectCtl(timer_name_, NetworkState::DB_CONNECTION + 11);
return (ctx);
}
bool reopened = false;
const std::string timer_name = db_reconnect_ctl->timerName();
+ bool check = db_reconnect_ctl->checkRetries();
// At least one connection was lost.
try {
return (false);
}
} else {
- if (!db_reconnect_ctl->checkRetries()) {
+ if (!check) {
// We're out of retries, log it and initiate shutdown.
LOG_ERROR(mysql_hb_logger, MYSQL_HB_DB_RECONNECT_FAILED)
.arg(db_reconnect_ctl->maxRetries());
IOServiceAccessorPtr ac(new IOServiceAccessor(&DatabaseConnection::getIOService));
DbCallback cb(&MySqlHostDataSourceImpl::dbReconnect);
- return (MySqlConnection::getVersion(parameters_, ac, cb, timer_name));
+ return (MySqlConnection::getVersion(parameters_, ac, cb, timer_name, NetworkState::DB_CONNECTION + 11));
}
void
std::pair<uint32_t, uint32_t>
MySqlHostDataSource::getVersion(const std::string& timer_name) const {
- return(impl_->getVersion(timer_name));
+ return (impl_->getVersion(timer_name));
}
void
#include <dhcpsrv/cfgmgr.h>
#include <dhcpsrv/dhcpsrv_log.h>
#include <dhcpsrv/lease_mgr_factory.h>
+#include <dhcpsrv/network_state.h>
#include <dhcpsrv/timer_mgr.h>
#include <mysql_lb_log.h>
#include <mysql_lease_mgr.h>
bool reopened = false;
const std::string timer_name = db_reconnect_ctl->timerName();
+ bool check = db_reconnect_ctl->checkRetries();
// At least one connection was lost.
try {
return (false);
}
} else {
- if (!db_reconnect_ctl->checkRetries()) {
+ if (!check) {
// We're out of retries, log it and initiate shutdown.
LOG_ERROR(mysql_lb_logger, MYSQL_LB_DB_RECONNECT_FAILED)
.arg(db_reconnect_ctl->maxRetries());
&MySqlLeaseMgr::dbReconnect));
// Create ReconnectCtl for this connection.
- ctx->conn_.makeReconnectCtl(timer_name_);
+ ctx->conn_.makeReconnectCtl(timer_name_, NetworkState::DB_CONNECTION + 1);
// Open the database.
ctx->conn_.openDatabase();
IOServiceAccessorPtr ac(new IOServiceAccessor(&DatabaseConnection::getIOService));
DbCallback cb(&MySqlLeaseMgr::dbReconnect);
- return (MySqlConnection::getVersion(parameters_, ac, cb, timer_name));
+ return (MySqlConnection::getVersion(parameters_, ac, cb, timer_name, NetworkState::DB_CONNECTION + 1));
}
void
bool do_exit = false;
const std::string timer_name = db_reconnect_ctl->timerName();
+ bool check = db_reconnect_ctl->checkRetries();
// At least one connection was lost.
try {
return (false);
}
} else {
- if (!db_reconnect_ctl->checkRetries()) {
+ if (!check) {
// We're out of retries, log it and initiate shutdown.
LOG_ERROR(pgsql_cb_logger, PGSQL_CB_RECONNECT_FAILED4)
.arg(db_reconnect_ctl->maxRetries());
bool do_exit = false;
const std::string timer_name = db_reconnect_ctl->timerName();
+ bool check = db_reconnect_ctl->checkRetries();
// At least one connection was lost.
try {
return (false);
}
} else {
- if (!db_reconnect_ctl->checkRetries()) {
+ if (!check) {
// We're out of retries, log it and initiate shutdown.
LOG_ERROR(pgsql_cb_logger, PGSQL_CB_RECONNECT_FAILED6)
.arg(db_reconnect_ctl->maxRetries());
#include <config_backend/constants.h>
#include <database/db_exceptions.h>
#include <dhcp/option_space.h>
+#include <dhcpsrv/network_state.h>
#include <dhcpsrv/timer_mgr.h>
#include <pgsql/pgsql_exchange.h>
#include <util/buffer.h>
PgSqlConnection::ensureSchemaVersion(parameters, db_reconnect_callback, timer_name_);
// Create ReconnectCtl for this connection.
- conn_.makeReconnectCtl(timer_name_);
+ conn_.makeReconnectCtl(timer_name_, NetworkState::DB_CONNECTION + 22);
// Open the database.
conn_.openDatabase();
#include <dhcpsrv/cfgmgr.h>
#include <dhcpsrv/dhcpsrv_log.h>
#include <dhcpsrv/host_mgr.h>
+#include <dhcpsrv/network_state.h>
+#include <dhcpsrv/timer_mgr.h>
#include <pgsql_hb_log.h>
#include <pgsql_host_data_source.h>
-#include <dhcpsrv/timer_mgr.h>
#include <util/buffer.h>
#include <util/multi_threading_mgr.h>
#include <util/optional.h>
ctx->host_option_exchange_.reset(new PgSqlOptionExchange());
// Create ReconnectCtl for this connection.
- ctx->conn_.makeReconnectCtl(timer_name_);
+ ctx->conn_.makeReconnectCtl(timer_name_, NetworkState::DB_CONNECTION + 12);
return (ctx);
}
bool reopened = false;
const std::string timer_name = db_reconnect_ctl->timerName();
+ bool check = db_reconnect_ctl->checkRetries();
// At least one connection was lost.
try {
return (false);
}
} else {
- if (!db_reconnect_ctl->checkRetries()) {
+ if (!check) {
// We're out of retries, log it and initiate shutdown.
LOG_ERROR(pgsql_hb_logger, PGSQL_HB_DB_RECONNECT_FAILED)
.arg(db_reconnect_ctl->maxRetries());
IOServiceAccessorPtr ac(new IOServiceAccessor(&DatabaseConnection::getIOService));
DbCallback cb(&PgSqlHostDataSourceImpl::dbReconnect);
- return (PgSqlConnection::getVersion(parameters_, ac, cb, timer_name));
+ return (PgSqlConnection::getVersion(parameters_, ac, cb, timer_name, NetworkState::DB_CONNECTION + 12));
}
void
std::pair<uint32_t, uint32_t>
PgSqlHostDataSource::getVersion(const std::string& timer_name) const {
- return(impl_->getVersion(timer_name));
+ return (impl_->getVersion(timer_name));
}
void
#include <dhcpsrv/dhcpsrv_log.h>
#include <dhcpsrv/dhcpsrv_exceptions.h>
#include <dhcpsrv/lease_mgr_factory.h>
+#include <dhcpsrv/network_state.h>
#include <pgsql_lb_log.h>
#include <pgsql_lease_mgr.h>
#include <dhcpsrv/timer_mgr.h>
bool reopened = false;
const std::string timer_name = db_reconnect_ctl->timerName();
+ bool check = db_reconnect_ctl->checkRetries();
// At least one connection was lost.
try {
return (false);
}
} else {
- if (!db_reconnect_ctl->checkRetries()) {
+ if (!check) {
// We're out of retries, log it and initiate shutdown.
LOG_ERROR(pgsql_lb_logger, PGSQL_LB_DB_RECONNECT_FAILED)
.arg(db_reconnect_ctl->maxRetries());
&PgSqlLeaseMgr::dbReconnect));
// Create ReconnectCtl for this connection.
- ctx->conn_.makeReconnectCtl(timer_name_);
+ ctx->conn_.makeReconnectCtl(timer_name_, NetworkState::DB_CONNECTION + 2);
// Open the database.
ctx->conn_.openDatabase();
IOServiceAccessorPtr ac(new IOServiceAccessor(&DatabaseConnection::getIOService));
DbCallback cb(&PgSqlLeaseMgr::dbReconnect);
- return (PgSqlConnection::getVersion(parameters_, ac, cb, timer_name));
+ return (PgSqlConnection::getVersion(parameters_, ac, cb, timer_name, NetworkState::DB_CONNECTION + 2));
}
void
}
void
-DatabaseConnection::makeReconnectCtl(const std::string& timer_name) {
+DatabaseConnection::makeReconnectCtl(const std::string& timer_name, unsigned int id) {
string type = "unknown";
unsigned int retries = 0;
unsigned int interval = 0;
}
reconnect_ctl_ = boost::make_shared<ReconnectCtl>(type, timer_name, retries,
- interval, action);
+ interval, action, id);
}
bool
/// reconnect parameters
///
/// @param timer_name of the timer used for the ReconnectCtl object.
- virtual void makeReconnectCtl(const std::string& timer_name);
+ virtual void makeReconnectCtl(const std::string& timer_name, unsigned int id);
/// @brief The reconnect settings.
///
pmap[std::string("max-reconnect-tries")] = std::string("3");
pmap[std::string("reconnect-wait-time")] = std::string("60000");
DatabaseConnection datasrc(pmap);
- datasrc.makeReconnectCtl("timer");
+ datasrc.makeReconnectCtl("timer", 0);
bool ret = false;
ASSERT_NO_THROW(ret = DatabaseConnection::invokeDbLostCallback(datasrc.reconnectCtl()));
pmap[std::string("max-reconnect-tries")] = std::string("3");
pmap[std::string("reconnect-wait-time")] = std::string("60000");
DatabaseConnection datasrc(pmap);
- datasrc.makeReconnectCtl("timer");
+ datasrc.makeReconnectCtl("timer", 0);
bool ret = false;
ASSERT_NO_THROW(ret = DatabaseConnection::invokeDbRecoveredCallback(datasrc.reconnectCtl()));
pmap[std::string("max-reconnect-tries")] = std::string("3");
pmap[std::string("reconnect-wait-time")] = std::string("60000");
DatabaseConnection datasrc(pmap);
- datasrc.makeReconnectCtl("timer");
+ datasrc.makeReconnectCtl("timer", 0);
bool ret = false;
ASSERT_NO_THROW(ret = DatabaseConnection::invokeDbFailedCallback(datasrc.reconnectCtl()));
std::bind(&DatabaseConnectionCallbackTest::dbLostCallback, this, ph::_1);
/// Create the connection..
DatabaseConnection datasrc(pmap);
- datasrc.makeReconnectCtl("timer");
+ datasrc.makeReconnectCtl("timer", 0);
bool ret = false;
/// We should be able to invoke the callback and get
std::bind(&DatabaseConnectionCallbackTest::dbRecoveredCallback, this, ph::_1);
/// Create the connection..
DatabaseConnection datasrc(pmap);
- datasrc.makeReconnectCtl("timer");
+ datasrc.makeReconnectCtl("timer", 0);
bool ret = false;
/// We should be able to invoke the callback and get
std::bind(&DatabaseConnectionCallbackTest::dbFailedCallback, this, ph::_1);
/// Create the connection..
DatabaseConnection datasrc(pmap);
- datasrc.makeReconnectCtl("timer");
+ datasrc.makeReconnectCtl("timer", 0);
bool ret = false;
/// We should be able to invoke the callback and get
auto reconnect_ctl = boost::make_shared<ReconnectCtl>("Socket", timer_name,
CfgIface::getServiceSocketsMaxRetries(),
CfgIface::getServiceSocketsRetryWaitTime(),
- on_fail_action);
+ on_fail_action, 0);
return (reconnect_ctl);
}
/// @brief Constructor.
NetworkStateImpl() : globally_disabled_(false), disabled_subnets_(),
disabled_networks_(), timer_mgr_(TimerMgr::instance()),
- disabled_by_origin_(), disabled_by_db_connection_(0) {
+ disabled_by_origin_() {
}
/// @brief Destructor.
if (disable) {
// Disable the service for any flag.
globally_disabled_ = true;
- if (origin == NetworkState::DB_CONNECTION) {
- ++disabled_by_db_connection_;
- } else {
- disabled_by_origin_.insert(origin);
- }
+ disabled_by_origin_.insert(origin);
} else {
- if (origin == NetworkState::DB_CONNECTION) {
- // Never go below 0 (using unsigned type).
- // This should never happen anyway.
- if (disabled_by_db_connection_) {
- --disabled_by_db_connection_;
- }
- } else {
- disabled_by_origin_.erase(origin);
- }
+ disabled_by_origin_.erase(origin);
// Enable the service only if all flags have been cleared.
- if (disabled_by_origin_.empty() && disabled_by_db_connection_ == 0) {
+ if (disabled_by_origin_.empty()) {
globally_disabled_ = false;
}
}
///
/// @note The dhcp service will remain disabled until all flags are cleared.
void resetForDbConnection() {
- disabled_by_db_connection_ = 0;
+ auto disabled_by_origin = disabled_by_origin_;
+ for (auto const& origin : disabled_by_origin) {
+ if (origin >= NetworkState::DB_CONNECTION) {
+ disabled_by_origin_.erase(origin);
+ }
+ }
if (disabled_by_origin_.empty()) {
globally_disabled_ = false;
}
disabled_by_origin_.erase(origin);
}
}
- if (disabled_by_origin_.empty() && disabled_by_db_connection_ == 0) {
+ if (disabled_by_origin_.empty()) {
globally_disabled_ = false;
}
}
disabled_by_origin_.erase(origin);
}
}
- if (disabled_by_origin_.empty() && disabled_by_db_connection_ == 0) {
+ if (disabled_by_origin_.empty()) {
globally_disabled_ = false;
}
}
/// @param origin The origin of the state transition.
void createTimer(const unsigned int seconds, unsigned int origin) {
destroyTimer(origin);
- if (origin == NetworkState::DB_CONNECTION) {
+ if (origin >= NetworkState::DB_CONNECTION) {
isc_throw(BadValue, "DB connection does not support delayed enable");
}
auto timer_name = getTimerName(origin);
///
/// @param origin The origin of the state transition.
void destroyTimer(unsigned int origin) {
- if (origin == NetworkState::DB_CONNECTION) {
+ if (origin >= NetworkState::DB_CONNECTION) {
return;
}
auto timer_name = getTimerName(origin);
virtual ElementPtr toElement() const {
ElementPtr result = Element::createMap();
result->set("globally-disabled", Element::create(globally_disabled_));
- result->set("disabled-by-db-connection", Element::create(disabled_by_db_connection_ != 0));
bool disabled_by_user = false;
ElementPtr local_origin = Element::createList();
ElementPtr remote_origin = Element::createList();
+ ElementPtr db_origin = Element::createList();
std::set<unsigned int> ordered(disabled_by_origin_.begin(), disabled_by_origin_.end());
for (auto const& origin : ordered) {
if (origin == NetworkState::USER_COMMAND) {
if (origin >= NetworkState::HA_REMOTE_COMMAND && origin < NetworkState::DB_CONNECTION) {
remote_origin->add(Element::create(origin));
}
+ if (origin >= NetworkState::DB_CONNECTION) {
+ db_origin->add(Element::create(origin));
+ }
}
result->set("disabled-by-user", Element::create(disabled_by_user));
result->set("disabled-by-local-command", local_origin);
result->set("disabled-by-remote-command", remote_origin);
+ result->set("disabled-by-db-connection", db_origin);
return (result);
}
/// @brief A set of requests to disable the service by origin.
std::unordered_set<unsigned int> disabled_by_origin_;
-
- /// @brief Flag which indicates the state has been disabled by a DB
- /// connection loss.
- uint32_t disabled_by_db_connection_;
};
NetworkState::NetworkState()
///
/// The DHCP state can also be altered by the database recovery mechanism, which
/// disables the service on connection loss and re-enables it after the connection
-/// is restored. Unlike in HA, this is implemented using an internal counter. In
-/// this case, there is one origin for all database connections. The requests for
-/// the @c NetworkState::DB_CONNECTION are counted, and the DHCP service is
-/// re-enabled when the counter reaches 0.
+/// is restored.
///
/// @todo We should consider migrating the database recovery to the same mechanism
/// we use for the HA. The reference counting works because the database connection
MySqlConnection::getVersion(const ParameterMap& parameters,
const IOServiceAccessorPtr& ac,
const DbCallback& cb,
- const string& timer_name) {
+ const string& timer_name,
+ unsigned int id) {
// Get a connection.
MySqlConnection conn(parameters, ac, cb);
if (!timer_name.empty()) {
- conn.makeReconnectCtl(timer_name);
+ conn.makeReconnectCtl(timer_name, id);
}
// Open the database.
getVersion(const ParameterMap& parameters,
const IOServiceAccessorPtr& ac = IOServiceAccessorPtr(),
const DbCallback& cb = DbCallback(),
- const std::string& timer_name = std::string());
+ const std::string& timer_name = std::string(),
+ unsigned int id = 0);
/// @brief Retrieve schema version, validate it against the hardcoded
/// version, and attempt to initialize the schema if there is an
PgSqlConnection::getVersion(const ParameterMap& parameters,
const IOServiceAccessorPtr& ac,
const DbCallback& cb,
- const string& timer_name) {
+ const string& timer_name,
+ unsigned int id) {
// Get a connection.
PgSqlConnection conn(parameters, ac, cb);
if (!timer_name.empty()) {
- conn.makeReconnectCtl(timer_name);
+ conn.makeReconnectCtl(timer_name, id);
}
// Open the database.
getVersion(const ParameterMap& parameters,
const IOServiceAccessorPtr& ac = IOServiceAccessorPtr(),
const DbCallback& cb = DbCallback(),
- const std::string& timer_name = std::string());
+ const std::string& timer_name = std::string(),
+ unsigned int id = 0);
/// @brief Retrieve schema version, validate it against the hardcoded
/// version, and attempt to initialize the schema if there is an
/// @param action which should be taken on connection loss.
ReconnectCtl(const std::string& backend_type, const std::string& timer_name,
unsigned int max_retries, unsigned int retry_interval,
- OnFailAction action) :
+ OnFailAction action, unsigned int id) :
backend_type_(backend_type), timer_name_(timer_name),
max_retries_(max_retries), retries_left_(max_retries),
- retry_interval_(retry_interval), action_(action) {}
+ retry_interval_(retry_interval), action_(action), id_(id) {
+ }
/// @brief Returns the type of the caller backend.
std::string backendType() const {
return (backend_type_);
}
+ /// @brief Returns the ID of the manager.
+ unsigned int id() const {
+ return (id_);
+ }
+
/// @brief Returns the associated timer name.
///
/// @return the associated timer.
/// @brief Action to take on connection loss.
OnFailAction action_;
+
+ /// @brief The ID of the backend.
+ unsigned int id_;
};
/// @brief Pointer to an instance of ReconnectCtl