2 * Copyright (c) 2015 Brocade Communications Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.controller.cluster.raft;
10 import akka.actor.ActorRef;
11 import akka.actor.ActorSelection;
12 import org.opendaylight.controller.cluster.raft.FollowerLogInformation.FollowerState;
13 import org.opendaylight.controller.cluster.raft.behaviors.AbstractLeader;
14 import org.opendaylight.controller.cluster.raft.messages.AddServer;
15 import org.opendaylight.controller.cluster.raft.messages.AddServerReply;
16 import org.opendaylight.controller.cluster.raft.messages.ServerChangeStatus;
17 import org.slf4j.Logger;
18 import org.slf4j.LoggerFactory;
21 * Handles server configuration related messages for a RaftActor.
23 * @author Thomas Pantelis
25 class RaftActorServerConfigurationSupport {
26 private static final Logger LOG = LoggerFactory.getLogger(RaftActorServerConfigurationSupport.class);
28 private final RaftActorContext context;
30 RaftActorServerConfigurationSupport(RaftActorContext context) {
31 this.context = context;
34 boolean handleMessage(Object message, RaftActor raftActor, ActorRef sender) {
35 if(message instanceof AddServer) {
36 onAddServer((AddServer)message, raftActor, sender);
43 private void onAddServer(AddServer addServer, RaftActor raftActor, ActorRef sender) {
44 LOG.debug("onAddServer: {}", addServer);
46 if(noLeaderOrForwardedToLeader(addServer, raftActor, sender)) {
50 // TODO - check if a server config is in progress. If so, cache this AddServer request to be processed
51 // after the current one is done.
53 context.addToPeers(addServer.getNewServerId(), addServer.getNewServerAddress());
55 AbstractLeader leader = (AbstractLeader) raftActor.getCurrentBehavior();
56 FollowerState initialState = addServer.isVotingMember() ? FollowerState.VOTING_NOT_INITIALIZED :
57 FollowerState.NON_VOTING;
58 leader.addFollower(addServer.getNewServerId(), initialState);
61 // if initialState == FollowerState.VOTING_NOT_INITIALIZED
62 // Initiate snapshot via leader.initiateCaptureSnapshot(addServer.getNewServerId())
63 // Start a timer to abort the operation after a period of time (maybe 2 times election timeout)
64 // Set local instance state and wait for message from the AbstractLeader when install snapshot is done and return now
65 // When install snapshot message is received, go to step 1
69 // 1) tell AbstractLeader mark the follower as VOTING and recalculate minReplicationCount and
70 // minIsolatedLeaderPeerCount
71 // 2) persist and replicate ServerConfigurationPayload via
72 // raftActor.persistData(sender, uuid, newServerConfigurationPayload)
73 // 3) Wait for commit complete via ApplyState message in RaftActor or time it out. In RaftActor,
74 // on ApplyState, check if ReplicatedLogEntry payload is ServerConfigurationPayload and call
79 sender.tell(new AddServerReply(ServerChangeStatus.OK, raftActor.getLeaderId()), raftActor.self());
82 private boolean noLeaderOrForwardedToLeader(Object message, RaftActor raftActor, ActorRef sender) {
83 if (raftActor.isLeader()) {
87 ActorSelection leader = raftActor.getLeader();
89 LOG.debug("Not leader - forwarding to leader {}", leader);
90 leader.forward(message, raftActor.getContext());
92 LOG.debug("No leader - returning NO_LEADER AddServerReply");
93 sender.tell(new AddServerReply(ServerChangeStatus.NO_LEADER, null), raftActor.self());