} else if (message instanceof RoleChangeNotification notification) {
// called by the Notifier
LOG.info("Role Change Notification received for member:{}, old role:{}, new role:{}",
- notification.getMemberId(), notification.getOldRole(), notification.getNewRole());
+ notification.memberId(), notification.oldRole(), notification.newRole());
// the apps dependent on such notifications can be called here
//TODO: add implementation here
-
}
}
package org.opendaylight.controller.cluster.notifications;
+import static java.util.Objects.requireNonNull;
+
import java.io.Serializable;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+import org.opendaylight.controller.cluster.raft.RaftState;
/**
* Notification message representing a Role change of a cluster member.
* Roles generally are Leader, Follower and Candidate. But can be based on the consensus strategy/implementation.
* The Listener could be in a separate ActorSystem and hence this message needs to be Serializable.
*/
-public class RoleChangeNotification implements Serializable {
+@NonNullByDefault
+public record RoleChangeNotification(String memberId, @Nullable String oldRole, String newRole)
+ implements Serializable {
+ @java.io.Serial
private static final long serialVersionUID = -2873869509490117116L;
- private final String memberId;
- private final String oldRole;
- private final String newRole;
-
- public RoleChangeNotification(String memberId, String oldRole, String newRole) {
- this.memberId = memberId;
- this.oldRole = oldRole;
- this.newRole = newRole;
- }
-
- public String getMemberId() {
- return memberId;
- }
- public String getOldRole() {
- return oldRole;
+ public RoleChangeNotification {
+ requireNonNull(memberId);
+ requireNonNull(newRole);
}
- public String getNewRole() {
- return newRole;
+ public RoleChangeNotification(final String memberId, final RaftState newRole, final @Nullable RaftState oldRole) {
+ this(memberId, oldRole != null ? oldRole.name() : null, newRole.name());
}
}
LOG.info("RoleChangeNotifier for {} , received role change from {} to {}", memberId,
roleChanged.oldRole(), roleChanged.newRole());
- latestRoleChangeNotification = new RoleChangeNotification(roleChanged.memberId(), roleChanged.oldRole(),
- roleChanged.newRole());
+ latestRoleChangeNotification = new RoleChangeNotification(roleChanged.memberId(), roleChanged.newRole(),
+ roleChanged.oldRole());
for (var listener : registeredListeners.values()) {
listener.tell(latestRoleChangeNotification, self());
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
+import org.opendaylight.controller.cluster.raft.RaftState;
/**
* Role Change message initiated internally from the Raft Actor when a the behavior/role changes.
* Since its internal, need not be serialized.
*/
@NonNullByDefault
-public record RoleChanged(String memberId, @Nullable String oldRole, String newRole) implements MemberNotication {
+public record RoleChanged(String memberId, RaftState newRole, @Nullable RaftState oldRole) implements MemberNotication {
public RoleChanged {
requireNonNull(memberId);
requireNonNull(newRole);
}
+
+ public RoleChanged(final String memberId, final RaftState newRole) {
+ this(memberId, newRole, null);
+ }
}
}
private void handleBehaviorChange(final BehaviorState oldBehaviorState, final RaftActorBehavior currentBehavior) {
- RaftActorBehavior oldBehavior = oldBehaviorState.getBehavior();
-
+ final var 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();
+ final var lastLeaderId = oldBehavior == null ? null : oldBehaviorState.getLastLeaderId();
+ final var lastValidLeaderId = oldBehavior == null ? null : oldBehaviorState.getLastValidLeaderId();
// it can happen that the state has not changed but the leader has changed.
final var leaderId = currentBehavior.getLeaderId();
serverConfigurationSupport.onNewLeader(leaderId);
}
- if (roleChangeNotifier != null && (oldBehavior == null || oldBehavior.state() != currentBehavior.state())) {
- roleChangeNotifier.tell(new RoleChanged(memberId(), oldBehaviorStateName,
- currentBehavior.state().name()), self());
+ if (roleChangeNotifier != null) {
+ notifyRoleChange(roleChangeNotifier, currentBehavior.state(), oldBehavior);
+ }
+ }
+
+ @NonNullByDefault
+ private void notifyRoleChange(final ActorRef target, final RaftState newState,
+ final @Nullable RaftActorBehavior oldBehavior) {
+ final RaftState oldState;
+ if (oldBehavior != null) {
+ oldState = oldBehavior.state();
+ if (newState.equals(oldState)) {
+ return;
+ }
+ } else {
+ oldState = null;
}
+ target.tell(new RoleChanged(memberId(), newState, oldState), self());
}
private void handleApplyState(final ApplyState applyState) {
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*/
-
package org.opendaylight.controller.cluster.raft;
public enum RaftState {
// The leader should transition to IsolatedLeader.
expectFirstMatching(leaderNotifierActor, RoleChanged.class,
- rc -> rc.newRole().equals(RaftState.IsolatedLeader.name()));
+ rc -> rc.newRole().equals(RaftState.IsolatedLeader));
forceElectionOnFollower1();
// Previous leader should switch to follower b/c it will receive either an AppendEntries or AppendEntriesReply
// with a higher term.
- expectFirstMatching(leaderNotifierActor, RoleChanged.class,
- rc -> rc.newRole().equals(RaftState.Follower.name()));
+ expectFirstMatching(leaderNotifierActor, RoleChanged.class, rc -> rc.newRole().equals(RaftState.Follower));
// The previous leader has a conflicting log entry at index 2 with a different term which should get
// replaced by the new leader's index 1 entry.
// The leader should transition to IsolatedLeader.
expectFirstMatching(leaderNotifierActor, RoleChanged.class,
- rc -> rc.newRole().equals(RaftState.IsolatedLeader.name()));
+ rc -> rc.newRole().equals(RaftState.IsolatedLeader));
forceElectionOnFollower1();
// Previous leader should switch to follower b/c it will receive either an AppendEntries or AppendEntriesReply
// with a higher term.
- expectFirstMatching(leaderNotifierActor, RoleChanged.class,
- rc -> rc.newRole().equals(RaftState.Follower.name()));
+ expectFirstMatching(leaderNotifierActor, RoleChanged.class, rc -> rc.newRole().equals(RaftState.Follower));
// The previous leader has a conflicting log entry at index 2 with a different term which should get
// replaced by the new leader's entry.
// The leader should transition to IsolatedLeader.
expectFirstMatching(leaderNotifierActor, RoleChanged.class,
- rc -> rc.newRole().equals(RaftState.IsolatedLeader.name()));
+ rc -> rc.newRole().equals(RaftState.IsolatedLeader));
forceElectionOnFollower1();
// Previous leader should switch to follower b/c it will receive either an AppendEntries or AppendEntriesReply
// with a higher term.
- expectFirstMatching(leaderNotifierActor, RoleChanged.class,
- rc -> rc.newRole().equals(RaftState.Follower.name()));
+ expectFirstMatching(leaderNotifierActor, RoleChanged.class, rc -> rc.newRole().equals(RaftState.Follower));
// The previous leader has conflicting log entries starting at index 2 with different terms which should get
// replaced by the new leader's entries.
follower1Actor.tell(TimeoutNow.INSTANCE, ActorRef.noSender());
- expectFirstMatching(follower1NotifierActor, RoleChanged.class,
- rc -> rc.newRole().equals(RaftState.Leader.name()));
+ expectFirstMatching(follower1NotifierActor, RoleChanged.class, rc -> rc.newRole().equals(RaftState.Leader));
currentTerm = follower1Context.currentTerm();
}
// 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).newRole());
- assertEquals("Role change 2", RaftState.PreLeader.name(), roleChange.get(1).newRole());
- assertEquals("Role change 3", RaftState.Leader.name(), roleChange.get(2).newRole());
+ assertEquals("Role change 1", RaftState.Candidate, roleChange.get(0).newRole());
+ assertEquals("Role change 2", RaftState.PreLeader, roleChange.get(1).newRole());
+ assertEquals("Role change 3", RaftState.Leader, roleChange.get(2).newRole());
final long previousTerm = currentTerm;
currentTerm = follower1Context.currentTerm();
RoleChanged raftRoleChanged = matches.get(0);
assertEquals(persistenceId, raftRoleChanged.memberId());
assertNull(raftRoleChanged.oldRole());
- assertEquals(RaftState.Follower.name(), raftRoleChanged.newRole());
+ assertEquals(RaftState.Follower, raftRoleChanged.newRole());
// check if the notifier got a role change from Follower to Candidate
raftRoleChanged = matches.get(1);
assertEquals(persistenceId, raftRoleChanged.memberId());
- assertEquals(RaftState.Follower.name(), raftRoleChanged.oldRole());
- assertEquals(RaftState.Candidate.name(), raftRoleChanged.newRole());
+ assertEquals(RaftState.Follower, raftRoleChanged.oldRole());
+ assertEquals(RaftState.Candidate, raftRoleChanged.newRole());
// check if the notifier got a role change from Candidate to Leader
raftRoleChanged = matches.get(2);
assertEquals(persistenceId, raftRoleChanged.memberId());
- assertEquals(RaftState.Candidate.name(), raftRoleChanged.oldRole());
- assertEquals(RaftState.Leader.name(), raftRoleChanged.newRole());
+ assertEquals(RaftState.Candidate, raftRoleChanged.oldRole());
+ assertEquals(RaftState.Leader, raftRoleChanged.newRole());
LeaderStateChanged leaderStateChange = MessageCollectorActor.expectFirstMatching(
notifierActor, LeaderStateChanged.class);
assertNull(leaderStateChange.leaderId());
raftRoleChanged = MessageCollectorActor.expectFirstMatching(notifierActor, RoleChanged.class);
- assertEquals(RaftState.Leader.name(), raftRoleChanged.oldRole());
- assertEquals(RaftState.Follower.name(), raftRoleChanged.newRole());
+ assertEquals(RaftState.Leader, raftRoleChanged.oldRole());
+ assertEquals(RaftState.Follower, raftRoleChanged.newRole());
MessageCollectorActor.clearMessages(notifierActor);
RoleChanged raftRoleChanged = matches.get(0);
assertEquals(persistenceId, raftRoleChanged.memberId());
assertNull(raftRoleChanged.oldRole());
- assertEquals(RaftState.Follower.name(), raftRoleChanged.newRole());
+ assertEquals(RaftState.Follower, raftRoleChanged.newRole());
// check if the notifier got a role change from Follower to Candidate
raftRoleChanged = matches.get(1);
assertEquals(persistenceId, raftRoleChanged.memberId());
- assertEquals(RaftState.Follower.name(), raftRoleChanged.oldRole());
- assertEquals(RaftState.Candidate.name(), raftRoleChanged.newRole());
+ assertEquals(RaftState.Follower, raftRoleChanged.oldRole());
+ assertEquals(RaftState.Candidate, raftRoleChanged.newRole());
}
@Test
}
private void onRoleChangeNotification(final RoleChangeNotification roleChanged) {
- LOG.info("{}: Received role changed for {} from {} to {}", logName(), roleChanged.getMemberId(),
- roleChanged.getOldRole(), roleChanged.getNewRole());
+ LOG.info("{}: Received role changed for {} from {} to {}", logName(), roleChanged.memberId(),
+ roleChanged.oldRole(), roleChanged.newRole());
- ShardInformation shardInformation = findShardInformation(roleChanged.getMemberId());
+ ShardInformation shardInformation = findShardInformation(roleChanged.memberId());
if (shardInformation != null) {
- shardInformation.setRole(roleChanged.getNewRole());
+ shardInformation.setRole(roleChanged.newRole());
checkReady();
shardManagerMBean.setSyncStatus(isInSync());
}
}
-
private ShardInformation findShardInformation(final String memberId) {
for (ShardInformation info : localShards.values()) {
if (info.getShardId().toString().equals(memberId)) {
TestActorRef<RoleChangeNotifier> notifierTestActorRef = TestActorRef.create(getSystem(),
RoleChangeNotifier.getProps(memberId), memberId);
- notifierTestActorRef.tell(
- new RoleChanged(memberId, RaftState.Candidate.name(), RaftState.Leader.name()), shardActor);
+ notifierTestActorRef.tell(new RoleChanged(memberId, RaftState.Leader, RaftState.Candidate), shardActor);
// no notification should be sent as listener has not yet
// registered
RoleChangeNotification notification = MessageCollectorActor.getFirstMatching(listenerActor,
RoleChangeNotification.class);
assertNotNull(notification);
- assertEquals(RaftState.Candidate.name(), notification.getOldRole());
- assertEquals(RaftState.Leader.name(), notification.getNewRole());
+ assertEquals(RaftState.Candidate.name(), notification.oldRole());
+ assertEquals(RaftState.Leader.name(), notification.newRole());
}
@Test