use of org.opendaylight.controller.cluster.notifications.RoleChanged in project controller by opendaylight.
the class RaftActorTest method testRaftRoleChangeNotifierWhenRaftActorHasPeers.
@Test
public void testRaftRoleChangeNotifierWhenRaftActorHasPeers() throws Exception {
ActorRef notifierActor = factory.createActor(MessageCollectorActor.props());
MessageCollectorActor.waitUntilReady(notifierActor);
DefaultConfigParamsImpl config = new DefaultConfigParamsImpl();
long heartBeatInterval = 100;
config.setHeartBeatInterval(FiniteDuration.create(heartBeatInterval, TimeUnit.MILLISECONDS));
config.setElectionTimeoutFactor(1);
String persistenceId = factory.generateActorId("notifier-");
factory.createActor(MockRaftActor.builder().id(persistenceId).peerAddresses(ImmutableMap.of("leader", "fake/path")).config(config).roleChangeNotifier(notifierActor).props());
List<RoleChanged> matches = null;
for (int i = 0; i < 5000 / heartBeatInterval; i++) {
matches = MessageCollectorActor.getAllMatching(notifierActor, RoleChanged.class);
assertNotNull(matches);
if (matches.size() == 3) {
break;
}
Uninterruptibles.sleepUninterruptibly(heartBeatInterval, TimeUnit.MILLISECONDS);
}
assertNotNull(matches);
assertEquals(2, matches.size());
// check if the notifier got a role change from null to Follower
RoleChanged raftRoleChanged = matches.get(0);
assertEquals(persistenceId, raftRoleChanged.getMemberId());
assertNull(raftRoleChanged.getOldRole());
assertEquals(RaftState.Follower.name(), raftRoleChanged.getNewRole());
// check if the notifier got a role change from Follower to Candidate
raftRoleChanged = matches.get(1);
assertEquals(persistenceId, raftRoleChanged.getMemberId());
assertEquals(RaftState.Follower.name(), raftRoleChanged.getOldRole());
assertEquals(RaftState.Candidate.name(), raftRoleChanged.getNewRole());
}
use of org.opendaylight.controller.cluster.notifications.RoleChanged in project controller by opendaylight.
the class PreLeaderScenarioTest method testUnComittedEntryOnLeaderChange.
@Test
public void testUnComittedEntryOnLeaderChange() throws Exception {
testLog.info("testUnComittedEntryOnLeaderChange starting");
createRaftActors();
// Drop AppendEntriesReply to the leader so it doesn't commit the payload entry.
leaderActor.underlyingActor().startDropMessages(AppendEntriesReply.class);
follower2Actor.underlyingActor().startDropMessages(AppendEntries.class);
// Send a payload and verify AppendEntries is received in follower1.
MockPayload payload0 = sendPayloadData(leaderActor, "zero");
AppendEntries appendEntries = expectFirstMatching(follower1CollectorActor, AppendEntries.class);
assertEquals("AppendEntries - # entries", 1, appendEntries.getEntries().size());
verifyReplicatedLogEntry(appendEntries.getEntries().get(0), currentTerm, 0, payload0);
// Kill the leader actor.
killActor(leaderActor);
// At this point, the payload entry is in follower1's log but is uncommitted. follower2 has not
// received the payload entry yet.
assertEquals("Follower 1 journal log size", 1, follower1Context.getReplicatedLog().size());
assertEquals("Follower 1 journal last index", 0, follower1Context.getReplicatedLog().lastIndex());
assertEquals("Follower 1 commit index", -1, follower1Context.getCommitIndex());
assertEquals("Follower 1 last applied index", -1, follower1Context.getLastApplied());
assertEquals("Follower 2 journal log size", 0, follower2Context.getReplicatedLog().size());
follower2Actor.underlyingActor().stopDropMessages(AppendEntries.class);
clearMessages(follower1NotifierActor);
// Force follower1 to start an election. It should win since it's journal is more up-to-date than
// follower2's journal.
follower1Actor.tell(TimeoutNow.INSTANCE, ActorRef.noSender());
// Verify the expected raft state changes. It should go to PreLeader since it has an uncommitted entry.
List<RoleChanged> roleChange = expectMatching(follower1NotifierActor, RoleChanged.class, 3);
assertEquals("Role change 1", RaftState.Candidate.name(), roleChange.get(0).getNewRole());
assertEquals("Role change 2", RaftState.PreLeader.name(), roleChange.get(1).getNewRole());
assertEquals("Role change 3", RaftState.Leader.name(), roleChange.get(2).getNewRole());
final long previousTerm = currentTerm;
currentTerm = follower1Context.getTermInformation().getCurrentTerm();
// Since it went to Leader, it should've appended and successfully replicated a NoopPaylod with the
// new term to follower2 and committed both entries, including the first payload from the previous term.
assertEquals("Follower 1 journal log size", 2, follower1Context.getReplicatedLog().size());
assertEquals("Follower 1 journal last index", 1, follower1Context.getReplicatedLog().lastIndex());
assertEquals("Follower 1 commit index", 1, follower1Context.getCommitIndex());
verifyReplicatedLogEntry(follower1Context.getReplicatedLog().get(0), previousTerm, 0, payload0);
verifyReplicatedLogEntry(follower1Context.getReplicatedLog().get(1), currentTerm, 1, NoopPayload.INSTANCE);
// Both entries should be applied to the state.
expectMatching(follower1CollectorActor, ApplyState.class, 2);
expectMatching(follower2CollectorActor, ApplyState.class, 2);
assertEquals("Follower 1 last applied index", 1, follower1Context.getLastApplied());
// Verify follower2's journal matches follower1's.
assertEquals("Follower 2 journal log size", 2, follower2Context.getReplicatedLog().size());
assertEquals("Follower 2 journal last index", 1, follower2Context.getReplicatedLog().lastIndex());
assertEquals("Follower 2 commit index", 1, follower2Context.getCommitIndex());
assertEquals("Follower 2 last applied index", 1, follower2Context.getLastApplied());
verifyReplicatedLogEntry(follower2Context.getReplicatedLog().get(0), previousTerm, 0, payload0);
verifyReplicatedLogEntry(follower2Context.getReplicatedLog().get(1), currentTerm, 1, NoopPayload.INSTANCE);
// Reinstate follower1.
killActor(follower1Actor);
follower1Actor = newTestRaftActor(follower1Id, TestRaftActor.newBuilder().peerAddresses(ImmutableMap.of(leaderId, testActorPath(leaderId), follower2Id, testActorPath(follower2Id))).config(followerConfigParams));
follower1Actor.underlyingActor().waitForRecoveryComplete();
follower1Context = follower1Actor.underlyingActor().getRaftActorContext();
// Verify follower1's journal was persisted and recovered correctly.
assertEquals("Follower 1 journal log size", 2, follower1Context.getReplicatedLog().size());
assertEquals("Follower 1 journal last index", 1, follower1Context.getReplicatedLog().lastIndex());
assertEquals("Follower 1 commit index", 1, follower1Context.getCommitIndex());
assertEquals("Follower 1 last applied index", 1, follower1Context.getLastApplied());
verifyReplicatedLogEntry(follower1Context.getReplicatedLog().get(0), previousTerm, 0, payload0);
verifyReplicatedLogEntry(follower1Context.getReplicatedLog().get(1), currentTerm, 1, NoopPayload.INSTANCE);
testLog.info("testUnComittedEntryOnLeaderChange ending");
}
use of org.opendaylight.controller.cluster.notifications.RoleChanged in project controller by opendaylight.
the class RaftActorTest method testRaftRoleChangeNotifierWhenRaftActorHasNoPeers.
@Test
public void testRaftRoleChangeNotifierWhenRaftActorHasNoPeers() throws Exception {
ActorRef notifierActor = factory.createActor(MessageCollectorActor.props());
MessageCollectorActor.waitUntilReady(notifierActor);
DefaultConfigParamsImpl config = new DefaultConfigParamsImpl();
long heartBeatInterval = 100;
config.setHeartBeatInterval(FiniteDuration.create(heartBeatInterval, TimeUnit.MILLISECONDS));
config.setElectionTimeoutFactor(20);
String persistenceId = factory.generateActorId("notifier-");
final TestActorRef<MockRaftActor> raftActorRef = factory.createTestActor(MockRaftActor.builder().id(persistenceId).config(config).roleChangeNotifier(notifierActor).dataPersistenceProvider(createProvider()).props().withDispatcher(Dispatchers.DefaultDispatcherId()), persistenceId);
List<RoleChanged> matches = MessageCollectorActor.expectMatching(notifierActor, RoleChanged.class, 3);
// check if the notifier got a role change from null to Follower
RoleChanged raftRoleChanged = matches.get(0);
assertEquals(persistenceId, raftRoleChanged.getMemberId());
assertNull(raftRoleChanged.getOldRole());
assertEquals(RaftState.Follower.name(), raftRoleChanged.getNewRole());
// check if the notifier got a role change from Follower to Candidate
raftRoleChanged = matches.get(1);
assertEquals(persistenceId, raftRoleChanged.getMemberId());
assertEquals(RaftState.Follower.name(), raftRoleChanged.getOldRole());
assertEquals(RaftState.Candidate.name(), raftRoleChanged.getNewRole());
// check if the notifier got a role change from Candidate to Leader
raftRoleChanged = matches.get(2);
assertEquals(persistenceId, raftRoleChanged.getMemberId());
assertEquals(RaftState.Candidate.name(), raftRoleChanged.getOldRole());
assertEquals(RaftState.Leader.name(), raftRoleChanged.getNewRole());
LeaderStateChanged leaderStateChange = MessageCollectorActor.expectFirstMatching(notifierActor, LeaderStateChanged.class);
assertEquals(raftRoleChanged.getMemberId(), leaderStateChange.getLeaderId());
assertEquals(MockRaftActor.PAYLOAD_VERSION, leaderStateChange.getLeaderPayloadVersion());
MessageCollectorActor.clearMessages(notifierActor);
MockRaftActor raftActor = raftActorRef.underlyingActor();
final String newLeaderId = "new-leader";
final short newLeaderVersion = 6;
Follower follower = new Follower(raftActor.getRaftActorContext()) {
@Override
public RaftActorBehavior handleMessage(final ActorRef sender, final Object message) {
setLeaderId(newLeaderId);
setLeaderPayloadVersion(newLeaderVersion);
return this;
}
};
raftActor.newBehavior(follower);
leaderStateChange = MessageCollectorActor.expectFirstMatching(notifierActor, LeaderStateChanged.class);
assertEquals(persistenceId, leaderStateChange.getMemberId());
assertEquals(null, leaderStateChange.getLeaderId());
raftRoleChanged = MessageCollectorActor.expectFirstMatching(notifierActor, RoleChanged.class);
assertEquals(RaftState.Leader.name(), raftRoleChanged.getOldRole());
assertEquals(RaftState.Follower.name(), raftRoleChanged.getNewRole());
MessageCollectorActor.clearMessages(notifierActor);
raftActor.handleCommand("any");
leaderStateChange = MessageCollectorActor.expectFirstMatching(notifierActor, LeaderStateChanged.class);
assertEquals(persistenceId, leaderStateChange.getMemberId());
assertEquals(newLeaderId, leaderStateChange.getLeaderId());
assertEquals(newLeaderVersion, leaderStateChange.getLeaderPayloadVersion());
MessageCollectorActor.clearMessages(notifierActor);
raftActor.handleCommand("any");
Uninterruptibles.sleepUninterruptibly(505, TimeUnit.MILLISECONDS);
leaderStateChange = MessageCollectorActor.getFirstMatching(notifierActor, LeaderStateChanged.class);
assertNull(leaderStateChange);
}
use of org.opendaylight.controller.cluster.notifications.RoleChanged in project controller by opendaylight.
the class RaftActor method handleBehaviorChange.
private void handleBehaviorChange(final BehaviorState oldBehaviorState, final RaftActorBehavior currentBehavior) {
RaftActorBehavior oldBehavior = oldBehaviorState.getBehavior();
if (oldBehavior != currentBehavior) {
onStateChanged();
}
String lastLeaderId = oldBehavior == null ? null : oldBehaviorState.getLastLeaderId();
String lastValidLeaderId = oldBehavior == null ? null : oldBehaviorState.getLastValidLeaderId();
String oldBehaviorStateName = oldBehavior == null ? null : oldBehavior.state().name();
// it can happen that the state has not changed but the leader has changed.
Optional<ActorRef> roleChangeNotifier = getRoleChangeNotifier();
if (!Objects.equals(lastLeaderId, currentBehavior.getLeaderId()) || oldBehaviorState.getLeaderPayloadVersion() != currentBehavior.getLeaderPayloadVersion()) {
if (roleChangeNotifier.isPresent()) {
roleChangeNotifier.get().tell(newLeaderStateChanged(getId(), currentBehavior.getLeaderId(), currentBehavior.getLeaderPayloadVersion()), getSelf());
}
onLeaderChanged(lastValidLeaderId, currentBehavior.getLeaderId());
RaftActorLeadershipTransferCohort leadershipTransferInProgress = context.getRaftActorLeadershipTransferCohort();
if (leadershipTransferInProgress != null) {
leadershipTransferInProgress.onNewLeader(currentBehavior.getLeaderId());
}
serverConfigurationSupport.onNewLeader(currentBehavior.getLeaderId());
}
if (roleChangeNotifier.isPresent() && (oldBehavior == null || oldBehavior.state() != currentBehavior.state())) {
roleChangeNotifier.get().tell(new RoleChanged(getId(), oldBehaviorStateName, currentBehavior.state().name()), getSelf());
}
}
use of org.opendaylight.controller.cluster.notifications.RoleChanged in project controller by opendaylight.
the class RoleChangeNotifierTest method testHandleRaftRoleChanged.
@Test
public void testHandleRaftRoleChanged() throws Exception {
new TestKit(getSystem()) {
{
String memberId = "testHandleRegisterRoleChangeListenerWithNotificationSet";
ActorRef listenerActor = getSystem().actorOf(MessageCollectorActor.props());
ActorRef shardActor = getTestActor();
TestActorRef<RoleChangeNotifier> notifierTestActorRef = TestActorRef.create(getSystem(), RoleChangeNotifier.getProps(memberId), memberId);
notifierTestActorRef.tell(new RoleChanged(memberId, RaftState.Candidate.name(), RaftState.Leader.name()), shardActor);
// no notification should be sent as listener has not yet
// registered
assertNull(MessageCollectorActor.getFirstMatching(listenerActor, RoleChangeNotification.class));
// listener registers after role has been changed, ensure we
// sent the latest role change after a reply
notifierTestActorRef.tell(new RegisterRoleChangeListener(), listenerActor);
RegisterRoleChangeListenerReply reply = MessageCollectorActor.getFirstMatching(listenerActor, RegisterRoleChangeListenerReply.class);
assertNotNull(reply);
RoleChangeNotification notification = MessageCollectorActor.getFirstMatching(listenerActor, RoleChangeNotification.class);
assertNotNull(notification);
assertEquals(RaftState.Candidate.name(), notification.getOldRole());
assertEquals(RaftState.Leader.name(), notification.getNewRole());
}
};
}
Aggregations