Remove use of {String,UUID}Identifier
[controller.git] / opendaylight / md-sal / sal-akka-raft / src / main / java / org / opendaylight / controller / cluster / raft / RaftActorServerConfigurationSupport.java
index 09020812bd5c9212c14c90161b4d49a1be95c537..bbc692e885c66a92fdfa8c01a0423cba56a4cc26 100644 (file)
@@ -35,6 +35,8 @@ import org.opendaylight.controller.cluster.raft.messages.ServerChangeStatus;
 import org.opendaylight.controller.cluster.raft.messages.ServerRemoved;
 import org.opendaylight.controller.cluster.raft.messages.UnInitializedFollowerSnapshotReply;
 import org.opendaylight.controller.cluster.raft.protobuff.client.messages.Payload;
+import org.opendaylight.yangtools.concepts.Identifier;
+import org.opendaylight.yangtools.util.AbstractUUIDIdentifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import scala.concurrent.duration.FiniteDuration;
@@ -120,7 +122,7 @@ class RaftActorServerConfigurationSupport {
 
     private void onRemoveServer(RemoveServer removeServer, ActorRef sender) {
         LOG.debug("{}: onRemoveServer: {}, state: {}", raftContext.getId(), removeServer, currentOperationState);
-        boolean isSelf = removeServer.getServerId().equals(raftActor.getId());
+        boolean isSelf = removeServer.getServerId().equals(raftContext.getId());
         if(isSelf && !raftContext.hasFollowers()) {
             sender.tell(new RemoveServerReply(ServerChangeStatus.NOT_SUPPORTED, raftActor.getLeaderId()),
                     raftActor.getSelf());
@@ -316,7 +318,7 @@ class RaftActorServerConfigurationSupport {
             // Sanity check - we could get an ApplyState from a previous operation that timed out so make
             // sure it's meant for us.
             if(operationContext.getContextId().equals(applyState.getIdentifier())) {
-                LOG.info("{}: {} has been successfully replicated to a majority of followers", raftActor.getId(),
+                LOG.info("{}: {} has been successfully replicated to a majority of followers", raftContext.getId(),
                         applyState.getReplicatedLogEntry().getData());
 
                 timer.cancel();
@@ -522,6 +524,14 @@ class RaftActorServerConfigurationSupport {
         }
     }
 
+    private static final class ServerOperationContextIdentifier extends AbstractUUIDIdentifier<ServerOperationContextIdentifier> {
+        private static final long serialVersionUID = 1L;
+
+        ServerOperationContextIdentifier() {
+            super(UUID.randomUUID());
+        }
+    }
+
     /**
      * Stores context information for a server operation.
      *
@@ -530,15 +540,15 @@ class RaftActorServerConfigurationSupport {
     private static abstract class ServerOperationContext<T> {
         private final T operation;
         private final ActorRef clientRequestor;
-        private final String contextId;
+        private final Identifier contextId;
 
         ServerOperationContext(T operation, ActorRef clientRequestor){
             this.operation = operation;
             this.clientRequestor = clientRequestor;
-            contextId = UUID.randomUUID().toString();
+            contextId = new ServerOperationContextIdentifier();
         }
 
-        String getContextId() {
+        Identifier getContextId() {
             return contextId;
         }
 
@@ -678,28 +688,9 @@ class RaftActorServerConfigurationSupport {
             // leadership.
             boolean localServerChangedToNonVoting = Boolean.FALSE.equals(getOperation().
                     getServerVotingStatusMap().get(raftActor.getRaftActorContext().getId()));
-            if(succeeded && localServerChangedToNonVoting && raftActor.isLeader()) {
-                raftActor.initiateLeadershipTransfer(new RaftActorLeadershipTransferCohort.OnComplete() {
-                    @Override
-                    public void onSuccess(ActorRef raftActorRef, ActorRef replyTo) {
-                        LOG.debug("{}: leader transfer succeeded after change to non-voting", raftActor.persistenceId());
-                        ensureFollowerState(raftActor);
-                    }
-
-                    @Override
-                    public void onFailure(ActorRef raftActorRef, ActorRef replyTo) {
-                        LOG.debug("{}: leader transfer failed after change to non-voting", raftActor.persistenceId());
-                        ensureFollowerState(raftActor);
-                    }
-
-                    private void ensureFollowerState(RaftActor raftActor) {
-                        // Whether or not leadership transfer succeeded, we have to step down as leader and
-                        // switch to Follower so ensure that.
-                        if(raftActor.getRaftState() != RaftState.Follower) {
-                            raftActor.initializeBehavior();
-                        }
-                    }
-                });
+            if (succeeded && localServerChangedToNonVoting) {
+                LOG.debug("Leader changed to non-voting - trying leadership transfer");
+                raftActor.becomeNonVoting();
             }
         }
 
@@ -725,9 +716,7 @@ class RaftActorServerConfigurationSupport {
 
             if(tryToElectLeader) {
                 initiateLocalLeaderElection();
-            } else {
-                updateLocalPeerInfo();
-
+            } else if(updateLocalPeerInfo()) {
                 persistNewServerConfiguration(changeVotingStatusContext);
             }
         }
@@ -736,21 +725,39 @@ class RaftActorServerConfigurationSupport {
             LOG.debug("{}: Sending local ElectionTimeout to start leader election", raftContext.getId());
 
             ServerConfigurationPayload previousServerConfig = raftContext.getPeerServerInfo(true);
-            updateLocalPeerInfo();
+            if(!updateLocalPeerInfo()) {
+                return;
+            }
 
             raftContext.getActor().tell(ElectionTimeout.INSTANCE, raftContext.getActor());
 
             currentOperationState = new WaitingForLeaderElected(changeVotingStatusContext, previousServerConfig);
         }
 
-        private void updateLocalPeerInfo() {
+        private boolean updateLocalPeerInfo() {
             List<ServerInfo> newServerInfoList = newServerInfoList();
 
+            // Check if new voting state would leave us with no voting members.
+            boolean atLeastOneVoting = false;
+            for(ServerInfo info: newServerInfoList) {
+                if(info.isVoting()) {
+                    atLeastOneVoting = true;
+                    break;
+                }
+            }
+
+            if(!atLeastOneVoting) {
+                operationComplete(changeVotingStatusContext, ServerChangeStatus.INVALID_REQUEST);
+                return false;
+            }
+
             raftContext.updatePeerIds(new ServerConfigurationPayload(newServerInfoList));
             if(raftActor.getCurrentBehavior() instanceof AbstractLeader) {
                 AbstractLeader leader = (AbstractLeader) raftActor.getCurrentBehavior();
                 leader.updateMinReplicaCount();
             }
+
+            return true;
         }
 
         private List<ServerInfo> newServerInfoList() {