X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=opendaylight%2Fmd-sal%2Fsal-akka-raft%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fcontroller%2Fcluster%2Fraft%2FRaftActorServerConfigurationSupport.java;h=2fa700256a598834f5b63050f9242eb6f027a679;hb=a7740542c8ce1985c0a35767966c781805dfad84;hp=46fe6269e37a907db36fe3d0ca7a5b9b9b52bd58;hpb=d639c62a1e743ec846b15bf755b830b00f4cc7eb;p=controller.git diff --git a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/RaftActorServerConfigurationSupport.java b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/RaftActorServerConfigurationSupport.java index 46fe6269e3..2fa700256a 100644 --- a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/RaftActorServerConfigurationSupport.java +++ b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/RaftActorServerConfigurationSupport.java @@ -20,10 +20,9 @@ import java.util.Map; import java.util.Queue; import java.util.UUID; import javax.annotation.Nullable; -import org.opendaylight.controller.cluster.raft.ServerConfigurationPayload.ServerInfo; import org.opendaylight.controller.cluster.raft.base.messages.ApplyState; -import org.opendaylight.controller.cluster.raft.base.messages.ElectionTimeout; import org.opendaylight.controller.cluster.raft.base.messages.SnapshotComplete; +import org.opendaylight.controller.cluster.raft.base.messages.TimeoutNow; import org.opendaylight.controller.cluster.raft.behaviors.AbstractLeader; import org.opendaylight.controller.cluster.raft.messages.AddServer; import org.opendaylight.controller.cluster.raft.messages.AddServerReply; @@ -34,7 +33,11 @@ import org.opendaylight.controller.cluster.raft.messages.ServerChangeReply; 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.persisted.ServerConfigurationPayload; +import org.opendaylight.controller.cluster.raft.persisted.ServerInfo; 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; @@ -522,6 +525,14 @@ class RaftActorServerConfigurationSupport { } } + private static final class ServerOperationContextIdentifier extends AbstractUUIDIdentifier { + private static final long serialVersionUID = 1L; + + ServerOperationContextIdentifier() { + super(UUID.randomUUID()); + } + } + /** * Stores context information for a server operation. * @@ -530,15 +541,15 @@ class RaftActorServerConfigurationSupport { private static abstract class ServerOperationContext { 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; } @@ -679,7 +690,8 @@ class RaftActorServerConfigurationSupport { boolean localServerChangedToNonVoting = Boolean.FALSE.equals(getOperation(). getServerVotingStatusMap().get(raftActor.getRaftActorContext().getId())); if (succeeded && localServerChangedToNonVoting) { - raftActor.becomeNonVoting(); + LOG.debug("Leader changed to non-voting - trying leadership transfer"); + raftActor.becomeNonVoting(); } } @@ -705,9 +717,7 @@ class RaftActorServerConfigurationSupport { if(tryToElectLeader) { initiateLocalLeaderElection(); - } else { - updateLocalPeerInfo(); - + } else if(updateLocalPeerInfo()) { persistNewServerConfiguration(changeVotingStatusContext); } } @@ -716,21 +726,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()); + raftContext.getActor().tell(TimeoutNow.INSTANCE, raftContext.getActor()); currentOperationState = new WaitingForLeaderElected(changeVotingStatusContext, previousServerConfig); } - private void updateLocalPeerInfo() { + private boolean updateLocalPeerInfo() { List 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 newServerInfoList() { @@ -764,6 +792,10 @@ class RaftActorServerConfigurationSupport { @Override void onNewLeader(String newLeader) { + if(newLeader == null) { + return; + } + LOG.debug("{}: New leader {} elected", raftContext.getId(), newLeader); timer.cancel();