Set to non-voting if not in server confguration 90/32390/2
authorTom Pantelis <tpanteli@brocade.com>
Tue, 12 Jan 2016 06:07:35 +0000 (01:07 -0500)
committerGerrit Code Review <gerrit@opendaylight.org>
Fri, 15 Jan 2016 13:15:29 +0000 (13:15 +0000)
On recovery, if a RaftActor is not in its own recovered
ServerConfigurationPayload list, then set itself to a non-voting member
so it stays at Follower and doesn't try to start an election.

This scenario is an edge case for Shards as, normally, when a server is
removed, it self-destructs and is removed from the ShardManager. However
there is a small window where disconnect or shutdown could prevent
ShardManager removal from occurring. This patch protects against a server
restart causing disruption after removal.

Change-Id: I64ecd89cddec7a4e1711e0d8d17c7ea6b36e29a0
Signed-off-by: Tom Pantelis <tpanteli@brocade.com>
opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/RaftActorContextImpl.java
opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/RaftActorContextImplTest.java

index 4677ea9..0bf71ab 100644 (file)
@@ -192,9 +192,11 @@ public class RaftActorContextImpl implements RaftActorContext {
     @Override
     public void updatePeerIds(ServerConfigurationPayload serverConfig){
         votingMember = true;
+        boolean foundSelf = false;
         Set<String> currentPeers = new HashSet<>(this.getPeerIds());
         for(ServerInfo server: serverConfig.getServerConfig()) {
             if(getId().equals(server.getId())) {
+                foundSelf = true;
                 if(!server.isVoting()) {
                     votingMember = false;
                 }
@@ -212,6 +214,11 @@ public class RaftActorContextImpl implements RaftActorContext {
         for(String peerIdToRemove: currentPeers) {
             this.removePeer(peerIdToRemove);
         }
+
+        if(!foundSelf) {
+            votingMember = false;
+        }
+
         setDynamicServerConfigurationInUse();
     }
 
index f290398..a879fd7 100644 (file)
@@ -8,6 +8,8 @@
 package org.opendaylight.controller.cluster.raft;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
@@ -18,11 +20,13 @@ import akka.actor.Props;
 import akka.testkit.TestActorRef;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Maps;
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Map;
 import org.junit.After;
 import org.junit.Test;
 import org.opendaylight.controller.cluster.NonPersistentDataProvider;
+import org.opendaylight.controller.cluster.raft.ServerConfigurationPayload.ServerInfo;
 import org.opendaylight.controller.cluster.raft.utils.DoNothingActor;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -86,4 +90,42 @@ public class RaftActorContextImplTest extends AbstractActorTest {
         context.setPeerAddress("peer2", "peerAddress2");
         assertEquals("getPeerAddress", null, context.getPeerAddress("peer2"));
     }
+
+    @Test
+    public void testUpdatePeerIds() {
+        RaftActorContextImpl context = new RaftActorContextImpl(actor, actor.underlyingActor().getContext(),
+                "self", new ElectionTermImpl(new NonPersistentDataProvider(), "test", log), -1, -1,
+                Maps.newHashMap(ImmutableMap.<String, String>of("peer1", "peerAddress1")),
+                new DefaultConfigParamsImpl(), new NonPersistentDataProvider(), log);
+
+        context.updatePeerIds(new ServerConfigurationPayload(Arrays.asList(new ServerInfo("self", false),
+                new ServerInfo("peer2", true), new ServerInfo("peer3", false))));
+        verifyPeerInfo(context, "peer1", null);
+        verifyPeerInfo(context, "peer2", true);
+        verifyPeerInfo(context, "peer3", false);
+        assertEquals("isVotingMember", false, context.isVotingMember());
+
+        context.updatePeerIds(new ServerConfigurationPayload(Arrays.asList(new ServerInfo("self", true),
+                new ServerInfo("peer2", true), new ServerInfo("peer3", true))));
+        verifyPeerInfo(context, "peer2", true);
+        verifyPeerInfo(context, "peer3", true);
+        assertEquals("isVotingMember", true, context.isVotingMember());
+
+        context.updatePeerIds(new ServerConfigurationPayload(Arrays.asList(new ServerInfo("peer2", true),
+                new ServerInfo("peer3", true))));
+        verifyPeerInfo(context, "peer2", true);
+        verifyPeerInfo(context, "peer3", true);
+        assertEquals("isVotingMember", false, context.isVotingMember());
+    }
+
+    private void verifyPeerInfo(RaftActorContextImpl context, String peerId, Boolean voting) {
+        PeerInfo peerInfo = context.getPeerInfo(peerId);
+        if(voting != null) {
+            assertNotNull("Expected peer " + peerId, peerInfo);
+            assertEquals("getVotingState for " + peerId, voting.booleanValue() ? VotingState.VOTING : VotingState.NON_VOTING,
+                    peerInfo.getVotingState());
+        } else {
+            assertNull("Unexpected peer " + peerId, peerInfo);
+        }
+    }
 }