Commit 6fb64283 authored by Marcin Siodelski's avatar Marcin Siodelski

[5674] Implemented HA pause for ordinary states.

Currently it excludes terminated and syncing states.
parent 247f42ab
......@@ -45,7 +45,7 @@ HAService::HAService(const IOServicePtr& io_service, const NetworkStatePtr& netw
const HAConfigPtr& config, const HAServerType& server_type)
: io_service_(io_service), network_state_(network_state), config_(config),
server_type_(server_type), client_(*io_service), communication_state_(),
query_filter_(config), pending_requests_() {
query_filter_(config), state_machine_control_(config), pending_requests_() {
if (server_type == HAServerType::DHCPv4) {
communication_state_.reset(new CommunicationState4(io_service_, config));
......@@ -130,10 +130,16 @@ HAService::normalStateHandler() {
if (doOnEntry()) {
query_filter_.serveDefaultScopes();
adjustNetworkState();
state_machine_control_.notify(getCurrState());
}
scheduleHeartbeat();
if (state_machine_control_.amPaused()) {
postNextEvent(NOP_EVT);
return;
}
// Check if the clock skew is still acceptable. If not, transition to
// the terminated state.
if (shouldTerminate()) {
......@@ -180,10 +186,17 @@ HAService::partnerDownStateHandler() {
query_filter_.serveDefaultScopes();
}
adjustNetworkState();
state_machine_control_.notify(getCurrState());
}
scheduleHeartbeat();
if (state_machine_control_.amPaused()) {
postNextEvent(NOP_EVT);
return;
}
// Check if the clock skew is still acceptable. If not, transition to
// the terminated state.
if (shouldTerminate()) {
......@@ -220,10 +233,16 @@ HAService::readyStateHandler() {
if (doOnEntry()) {
query_filter_.serveNoScopes();
adjustNetworkState();
state_machine_control_.notify(getCurrState());
}
scheduleHeartbeat();
if (state_machine_control_.amPaused()) {
postNextEvent(NOP_EVT);
return;
}
// Check if the clock skew is still acceptable. If not, transition to
// the terminated state.
if (shouldTerminate()) {
......@@ -361,6 +380,17 @@ HAService::waitingStateHandler() {
if (doOnEntry()) {
query_filter_.serveNoScopes();
adjustNetworkState();
state_machine_control_.notify(getCurrState());
}
// Only schedule the heartbeat for non-backup servers.
if (config_->getThisServerConfig()->getRole() != HAConfig::PeerConfig::BACKUP) {
scheduleHeartbeat();
}
if (state_machine_control_.amPaused()) {
postNextEvent(NOP_EVT);
return;
}
// Backup server must remain in its own state.
......@@ -369,8 +399,6 @@ HAService::waitingStateHandler() {
return;
}
scheduleHeartbeat();
// Check if the clock skew is still acceptable. If not, transition to
// the terminated state.
if (shouldTerminate()) {
......@@ -477,6 +505,11 @@ HAService::verboseTransition(const unsigned state) {
}
}
void
HAService::unpause() {
state_machine_control_.unpause();
}
void
HAService::serveDefaultScopes() {
query_filter_.serveDefaultScopes();
......
......@@ -10,6 +10,7 @@
#include <communication_state.h>
#include <ha_config.h>
#include <ha_server_type.h>
#include <ha_state_machine_control.h>
#include <query_filter.h>
#include <asiolink/io_service.h>
#include <cc/data.h>
......@@ -246,6 +247,13 @@ protected:
public:
/// @brief Un-pauses the state machine.
///
/// This is method is invoked when the server receives the 'ha-continue'
/// command which instructs the server to unblock the HA state machine
/// so as it may transition to a next state.
void unpause();
/// @brief Instructs the HA service to serve default scopes.
///
/// This method is mostly useful for unit testing. The scopes need to be
......@@ -635,6 +643,9 @@ protected:
/// @brief Selects queries to be processed/dropped.
QueryFilter query_filter_;
/// @brief Controls state machine pausing and unpausing.
HAStateMachineControl state_machine_control_;
/// @brief Map holding a number of scheduled requests for a given packet.
///
/// A single callout may send multiple requests at the same time, e.g.
......
......@@ -8,6 +8,7 @@
#define HA_STATE_MACHINE_CONTROL_H
#include <ha_config.h>
#include <boost/shared_ptr.hpp>
#include <set>
namespace isc {
......@@ -73,6 +74,9 @@ private:
std::set<int> visited_states_;
};
/// @brief Shared pointer to the @c HAStateMachineControl.
typedef boost::shared_ptr<HAStateMachineControl> HAStateMachineControlPtr;
} // end of namespace isc::ha
} // end of namespace isc
......
......@@ -3547,6 +3547,71 @@ TEST_F(HAServiceStateMachineTest, syncingTransitionsLoadBalancing) {
EXPECT_EQ(HAService::HA_SYNCING_SUCCEEDED_EVT, service_->getLastEvent());
}
// This test verifies that the HA state machine can be paused in certain states
// when the server is operating in load balancing mode.
TEST_F(HAServiceStateMachineTest, stateTransitionsLoadBalancingPause) {
partner_->startup();
HAConfigPtr valid_config = createValidConfiguration();
auto state_configs = valid_config->getStateMachineConfig();
for (auto cfg = state_configs.begin(); cfg != state_configs.end(); ++cfg) {
cfg->second->setPausing("always");
}
startService(valid_config);
{
SCOPED_TRACE("LOAD BALANCING state transitions");
testTransition(MyState(HA_LOAD_BALANCING_ST), PartnerState(HA_TERMINATED_ST),
FinalState(HA_LOAD_BALANCING_ST));
service_->unpause();
testTransition(MyState(HA_LOAD_BALANCING_ST), PartnerState(HA_TERMINATED_ST),
FinalState(HA_TERMINATED_ST));
}
{
SCOPED_TRACE("PARTNER DOWN state transitions");
testTransition(MyState(HA_PARTNER_DOWN_ST), PartnerState(HA_LOAD_BALANCING_ST),
FinalState(HA_PARTNER_DOWN_ST));
service_->unpause();
testTransition(MyState(HA_PARTNER_DOWN_ST), PartnerState(HA_LOAD_BALANCING_ST),
FinalState(HA_WAITING_ST));
}
{
SCOPED_TRACE("READY state transitions");
testTransition(MyState(HA_READY_ST), PartnerState(HA_LOAD_BALANCING_ST),
FinalState(HA_READY_ST));
service_->unpause();
testTransition(MyState(HA_READY_ST), PartnerState(HA_LOAD_BALANCING_ST),
FinalState(HA_LOAD_BALANCING_ST));
}
{
SCOPED_TRACE("WAITING state transitions");
testTransition(MyState(HA_WAITING_ST), PartnerState(HA_LOAD_BALANCING_ST),
FinalState(HA_WAITING_ST));
service_->unpause();
testTransition(MyState(HA_WAITING_ST), PartnerState(HA_LOAD_BALANCING_ST),
FinalState(HA_SYNCING_ST));
}
}
// This test verifies that the server takes ownership of the given scopes
// and whether the DHCP service is disabled or enabled in certain states.
TEST_F(HAServiceStateMachineTest, scopesServingLoadBalancing) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment