void
HAService::maintainedStateHandler() {
+ // If we are transitioning from another state, we have to define new
+ // serving scopes appropriate for the new state. We don't do it if
+ // we remain in this state.
+ if (doOnEntry()) {
+ // In this state the server remains silent and waits for being
+ // shutdown.
+ query_filter_.serveNoScopes();
+ adjustNetworkState();
+
+ // Log if the state machine is paused.
+ conditionalLogPausedState();
+ }
+
+ scheduleHeartbeat();
+
+ // We don't transition out of this state unless explicitly mandated
+ // by the administrator via a dedicated command which cancels
+ // the maintenance.
postNextEvent(NOP_EVT);
}
void
HAService::partnerMaintainedStateHandler() {
- postNextEvent(NOP_EVT);
+ // If we are transitioning from another state, we have to define new
+ // serving scopes appropriate for the new state. We don't do it if
+ // we remain in this state.
+ if (doOnEntry()) {
+ // It may be administratively disabled to handle partner's scope
+ // in case of failure. If this is the case we'll just handle our
+ // default scope (or no scope at all). The user will need to
+ // manually enable this server to handle partner's scope.
+ if (config_->getThisServerConfig()->isAutoFailover()) {
+ query_filter_.serveFailoverScopes();
+ } else {
+ query_filter_.serveDefaultScopes();
+ }
+ adjustNetworkState();
+
+ // Log if the state machine is paused.
+ conditionalLogPausedState();
+ }
+
+ scheduleHeartbeat();
+
+ if (isModelPaused()) {
+ postNextEvent(NOP_EVT);
+ return;
+ }
+
+ // Check if the clock skew is still acceptable. If not, transition to
+ // the terminated state.
+ if (shouldTerminate()) {
+ verboseTransition(HA_TERMINATED_ST);
+ return;
+ }
+
+ switch (communication_state_->getPartnerState()) {
+ case HA_UNAVAILABLE_ST:
+ verboseTransition(HA_PARTNER_DOWN_ST);
+
+ default:
+ postNextEvent(NOP_EVT);
+ }
}
void
const bool should_enable = ((getCurrState() == HA_LOAD_BALANCING_ST) ||
(getCurrState() == HA_HOT_STANDBY_ST) ||
(getCurrState() == HA_PARTNER_DOWN_ST) ||
+ (getCurrState() == HA_PARTNER_MAINTAINED_ST) ||
(getCurrState() == HA_TERMINATED_ST));
if (!should_enable && network_state_->isServiceEnabled()) {
switch (getCurrState()) {
case HA_HOT_STANDBY_ST:
case HA_LOAD_BALANCING_ST:
+ case HA_PARTNER_MAINTAINED_ST:
return (true);
default:
expectScopes(MyState(HA_LOAD_BALANCING_ST), { "server1" }, true);
expectScopes(MyState(HA_TERMINATED_ST), { "server1" }, true);
- // PARTNER DOWN: serving both scopes.
+ // PARTNER DOWN and PARTNER MAINTAINED: serving both scopes.
expectScopes(MyState(HA_PARTNER_DOWN_ST), { "server1", "server2" }, true);
+ expectScopes(MyState(HA_PARTNER_MAINTAINED_ST), { "server1", "server2" }, true);
- // READY & WAITING: serving no scopes.
+ // MAINTAINED, READY & WAITING: serving no scopes.
+ expectScopes(MyState(HA_MAINTAINED_ST), { }, false);
expectScopes(MyState(HA_READY_ST), { }, false);
expectScopes(MyState(HA_WAITING_ST), { }, false);
}
expectScopes(MyState(HA_LOAD_BALANCING_ST), { "server1" }, true);
expectScopes(MyState(HA_TERMINATED_ST), { "server1" }, true);
- // PARTNER DOWN: still serving my own scope because auto-failover
- // is disabled.
+ // PARTNER MAINTAINED & PARTNER DOWN: still serving my own scope
+ // because auto-failover is disabled.
expectScopes(MyState(HA_PARTNER_DOWN_ST), { "server1" }, true);
+ expectScopes(MyState(HA_PARTNER_MAINTAINED_ST), { "server1" }, true);
- // READY & WAITING: serving no scopes.
+ // MAINTAINED, READY & WAITING: serving no scopes.
+ expectScopes(MyState(HA_MAINTAINED_ST), { }, false);
expectScopes(MyState(HA_READY_ST), { }, false);
expectScopes(MyState(HA_WAITING_ST), { }, false);
}
HAConfig::PeerConfigPtr peer_config = valid_config->getFailoverPeerConfig();
EXPECT_TRUE(expectLeaseUpdates(MyState(HA_LOAD_BALANCING_ST), peer_config));
+ EXPECT_FALSE(expectLeaseUpdates(MyState(HA_MAINTAINED_ST), peer_config));
EXPECT_FALSE(expectLeaseUpdates(MyState(HA_PARTNER_DOWN_ST), peer_config));
+ EXPECT_TRUE(expectLeaseUpdates(MyState(HA_PARTNER_MAINTAINED_ST), peer_config));
EXPECT_FALSE(expectLeaseUpdates(MyState(HA_READY_ST), peer_config));
EXPECT_FALSE(expectLeaseUpdates(MyState(HA_SYNCING_ST), peer_config));
EXPECT_FALSE(expectLeaseUpdates(MyState(HA_TERMINATED_ST), peer_config));
HAConfig::PeerConfigPtr peer_config = valid_config->getFailoverPeerConfig();
EXPECT_FALSE(expectLeaseUpdates(MyState(HA_LOAD_BALANCING_ST), peer_config));
+ EXPECT_FALSE(expectLeaseUpdates(MyState(HA_MAINTAINED_ST), peer_config));
EXPECT_FALSE(expectLeaseUpdates(MyState(HA_PARTNER_DOWN_ST), peer_config));
+ EXPECT_FALSE(expectLeaseUpdates(MyState(HA_PARTNER_MAINTAINED_ST), peer_config));
EXPECT_FALSE(expectLeaseUpdates(MyState(HA_READY_ST), peer_config));
EXPECT_FALSE(expectLeaseUpdates(MyState(HA_SYNCING_ST), peer_config));
EXPECT_FALSE(expectLeaseUpdates(MyState(HA_TERMINATED_ST), peer_config));
startService(valid_config);
EXPECT_TRUE(expectHeartbeat(MyState(HA_LOAD_BALANCING_ST)));
+ EXPECT_TRUE(expectHeartbeat(MyState(HA_MAINTAINED_ST)));
EXPECT_TRUE(expectHeartbeat(MyState(HA_PARTNER_DOWN_ST)));
+ EXPECT_TRUE(expectHeartbeat(MyState(HA_PARTNER_MAINTAINED_ST)));
EXPECT_TRUE(expectHeartbeat(MyState(HA_READY_ST)));
EXPECT_FALSE(expectHeartbeat(MyState(HA_TERMINATED_ST)));
EXPECT_TRUE(expectHeartbeat(MyState(HA_WAITING_ST)));
expectScopes(MyState(HA_HOT_STANDBY_ST), { "server1" }, true);
expectScopes(MyState(HA_TERMINATED_ST), { "server1" }, true);
- // PARTNER DOWN: still serving my own scope.
+ // PARTNER DOWN and PARTNER MAINTAINED: still serving my own scope.
expectScopes(MyState(HA_PARTNER_DOWN_ST), { "server1" }, true);
+ expectScopes(MyState(HA_PARTNER_MAINTAINED_ST), { "server1" }, true);
- // READY & WAITING: serving no scopes.
+ // MAINTAINED, READY & WAITING: serving no scopes.
+ expectScopes(MyState(HA_MAINTAINED_ST), { }, false);
expectScopes(MyState(HA_READY_ST), { }, false);
expectScopes(MyState(HA_WAITING_ST), { }, false);
}
expectScopes(MyState(HA_HOT_STANDBY_ST), { "server1" }, true);
expectScopes(MyState(HA_TERMINATED_ST), { "server1" }, true);
- // PARTNER DOWN: still serving my own scope.
+ // PARTNER MAINTAINED & PARTNER DOWN: still serving my own scope.
expectScopes(MyState(HA_PARTNER_DOWN_ST), { "server1" }, true);
+ expectScopes(MyState(HA_PARTNER_MAINTAINED_ST), { "server1" }, true);
- // READY & WAITING: serving no scopes.
+ // MAINTAINED, READY & WAITING: serving no scopes.
+ expectScopes(MyState(HA_MAINTAINED_ST), { }, false);
expectScopes(MyState(HA_READY_ST), { }, false);
expectScopes(MyState(HA_WAITING_ST), { }, false);
}
HAConfig::PeerConfigPtr peer_config = valid_config->getFailoverPeerConfig();
EXPECT_TRUE(expectLeaseUpdates(MyState(HA_HOT_STANDBY_ST), peer_config));
+ EXPECT_FALSE(expectLeaseUpdates(MyState(HA_MAINTAINED_ST), peer_config));
EXPECT_FALSE(expectLeaseUpdates(MyState(HA_PARTNER_DOWN_ST), peer_config));
+ EXPECT_TRUE(expectLeaseUpdates(MyState(HA_PARTNER_MAINTAINED_ST), peer_config));
EXPECT_FALSE(expectLeaseUpdates(MyState(HA_READY_ST), peer_config));
EXPECT_FALSE(expectLeaseUpdates(MyState(HA_SYNCING_ST), peer_config));
EXPECT_FALSE(expectLeaseUpdates(MyState(HA_TERMINATED_ST), peer_config));
// This test verifies if the server would send heartbeat to the partner
// while being in various states. The HA configuration is hot standby.
-TEST_F(HAServiceStateMachineTest, heartbeatHotstandby) {
+TEST_F(HAServiceStateMachineTest, heartbeatHotStandby) {
HAConfigPtr valid_config = createValidConfiguration();
// Turn it into hot-standby configuration.
startService(valid_config);
EXPECT_TRUE(expectHeartbeat(MyState(HA_HOT_STANDBY_ST)));
+ EXPECT_TRUE(expectHeartbeat(MyState(HA_MAINTAINED_ST)));
EXPECT_TRUE(expectHeartbeat(MyState(HA_PARTNER_DOWN_ST)));
+ EXPECT_TRUE(expectHeartbeat(MyState(HA_PARTNER_MAINTAINED_ST)));
EXPECT_TRUE(expectHeartbeat(MyState(HA_READY_ST)));
EXPECT_FALSE(expectHeartbeat(MyState(HA_TERMINATED_ST)));
EXPECT_TRUE(expectHeartbeat(MyState(HA_WAITING_ST)));
// TERMINATED: serving no scopes because the primary is active.
expectScopes(MyState(HA_TERMINATED_ST), { }, true);
- // PARTNER DOWN: serving server1's scope.
+ // PARTNER MAINTAINED & PARTNER DOWN: serving server1's scope.
expectScopes(MyState(HA_PARTNER_DOWN_ST), { "server1" }, true);
+ expectScopes(MyState(HA_PARTNER_MAINTAINED_ST), { "server1" }, true);
- // READY & WAITING: serving no scopes.
+ // MAINTAINED, READY & WAITING: serving no scopes.
+ expectScopes(MyState(HA_MAINTAINED_ST), { }, false);
expectScopes(MyState(HA_READY_ST), { }, false);
expectScopes(MyState(HA_WAITING_ST), { }, false);
}
// TERMINATED: serving no scopes because the primary is active.
expectScopes(MyState(HA_TERMINATED_ST), { }, true);
- // PARTNER DOWN: still serving no scopes because auto-failover is
+ // PARTNER MAINTAINED & PARTNER DOWN: still serving no scopes because auto-failover is
// set to false.
expectScopes(MyState(HA_PARTNER_DOWN_ST), { }, true);
+ expectScopes(MyState(HA_PARTNER_MAINTAINED_ST), { }, true);
- // READY & WAITING: serving no scopes.
+ // MAINTAINED, READY & WAITING: serving no scopes.
+ expectScopes(MyState(HA_MAINTAINED_ST), { }, false);
expectScopes(MyState(HA_READY_ST), { }, false);
expectScopes(MyState(HA_WAITING_ST), { }, false);
}
HAConfig::PeerConfigPtr peer_config = valid_config->getFailoverPeerConfig();
EXPECT_TRUE(expectLeaseUpdates(MyState(HA_HOT_STANDBY_ST), peer_config));
+ EXPECT_FALSE(expectLeaseUpdates(MyState(HA_MAINTAINED_ST), peer_config));
EXPECT_FALSE(expectLeaseUpdates(MyState(HA_PARTNER_DOWN_ST), peer_config));
+ EXPECT_TRUE(expectLeaseUpdates(MyState(HA_PARTNER_MAINTAINED_ST), peer_config));
EXPECT_FALSE(expectLeaseUpdates(MyState(HA_READY_ST), peer_config));
EXPECT_FALSE(expectLeaseUpdates(MyState(HA_SYNCING_ST), peer_config));
EXPECT_FALSE(expectLeaseUpdates(MyState(HA_TERMINATED_ST), peer_config));