d7a8d5abb35bdb258633b65a783aed9e0aa9677d
[controller.git] / opendaylight / md-sal / sal-akka-raft / src / main / java / org / opendaylight / controller / cluster / raft / behaviors / AbstractRaftActorBehavior.java
1 /*
2  * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8
9 package org.opendaylight.controller.cluster.raft.behaviors;
10
11 import akka.actor.ActorRef;
12 import org.opendaylight.controller.cluster.raft.RaftActorContext;
13 import org.opendaylight.controller.cluster.raft.RaftState;
14 import org.opendaylight.controller.cluster.raft.messages.AppendEntries;
15 import org.opendaylight.controller.cluster.raft.messages.AppendEntriesReply;
16 import org.opendaylight.controller.cluster.raft.messages.RaftRPC;
17 import org.opendaylight.controller.cluster.raft.messages.RequestVote;
18 import org.opendaylight.controller.cluster.raft.messages.RequestVoteReply;
19
20 /**
21  * Abstract class that represents the behavior of a RaftActor
22  * <p/>
23  * All Servers:
24  * <ul>
25  * <li> If commitIndex > lastApplied: increment lastApplied, apply
26  * log[lastApplied] to state machine (§5.3)
27  * <li> If RPC request or response contains term T > currentTerm:
28  * set currentTerm = T, convert to follower (§5.1)
29  */
30 public abstract class AbstractRaftActorBehavior implements RaftActorBehavior {
31
32     /**
33      * Information about the RaftActor whose behavior this class represents
34      */
35     protected final RaftActorContext context;
36
37
38     protected AbstractRaftActorBehavior(RaftActorContext context) {
39         this.context = context;
40     }
41
42     /**
43      * Derived classes should not directly handle AppendEntries messages it
44      * should let the base class handle it first. Once the base class handles
45      * the AppendEntries message and does the common actions that are applicable
46      * in all RaftState's it will delegate the handling of the AppendEntries
47      * message to the derived class to do more state specific handling by calling
48      * this method
49      *
50      * @param sender         The actor that sent this message
51      * @param appendEntries  The AppendEntries message
52      * @param suggestedState The state that the RaftActor should be in based
53      *                       on the base class's processing of the AppendEntries
54      *                       message
55      * @return
56      */
57     protected abstract RaftState handleAppendEntries(ActorRef sender,
58         AppendEntries appendEntries, RaftState suggestedState);
59
60     /**
61      * Derived classes should not directly handle AppendEntriesReply messages it
62      * should let the base class handle it first. Once the base class handles
63      * the AppendEntriesReply message and does the common actions that are
64      * applicable in all RaftState's it will delegate the handling of the
65      * AppendEntriesReply message to the derived class to do more state specific
66      * handling by calling this method
67      *
68      * @param sender             The actor that sent this message
69      * @param appendEntriesReply The AppendEntriesReply message
70      * @param suggestedState     The state that the RaftActor should be in based
71      *                           on the base class's processing of the
72      *                           AppendEntriesReply message
73      * @return
74      */
75
76     protected abstract RaftState handleAppendEntriesReply(ActorRef sender,
77         AppendEntriesReply appendEntriesReply, RaftState suggestedState);
78
79     /**
80      * Derived classes should not directly handle RequestVote messages it
81      * should let the base class handle it first. Once the base class handles
82      * the RequestVote message and does the common actions that are applicable
83      * in all RaftState's it will delegate the handling of the RequestVote
84      * message to the derived class to do more state specific handling by calling
85      * this method
86      *
87      * @param sender         The actor that sent this message
88      * @param requestVote    The RequestVote message
89      * @param suggestedState The state that the RaftActor should be in based
90      *                       on the base class's processing of the RequestVote
91      *                       message
92      * @return
93      */
94     protected abstract RaftState handleRequestVote(ActorRef sender,
95         RequestVote requestVote, RaftState suggestedState);
96
97     /**
98      * Derived classes should not directly handle RequestVoteReply messages it
99      * should let the base class handle it first. Once the base class handles
100      * the RequestVoteReply message and does the common actions that are
101      * applicable in all RaftState's it will delegate the handling of the
102      * RequestVoteReply message to the derived class to do more state specific
103      * handling by calling this method
104      *
105      * @param sender           The actor that sent this message
106      * @param requestVoteReply The RequestVoteReply message
107      * @param suggestedState   The state that the RaftActor should be in based
108      *                         on the base class's processing of the RequestVote
109      *                         message
110      * @return
111      */
112
113     protected abstract RaftState handleRequestVoteReply(ActorRef sender,
114         RequestVoteReply requestVoteReply, RaftState suggestedState);
115
116     /**
117      * @return The derived class should return the state that corresponds to
118      * it's behavior
119      */
120     protected abstract RaftState state();
121
122     @Override
123     public RaftState handleMessage(ActorRef sender, Object message) {
124         RaftState raftState = state();
125         if (message instanceof RaftRPC) {
126             raftState = applyTerm((RaftRPC) message);
127         }
128         if (message instanceof AppendEntries) {
129             AppendEntries appendEntries = (AppendEntries) message;
130             if (appendEntries.getLeaderCommit() > context.getLastApplied()
131                 .get()) {
132                 applyLogToStateMachine(appendEntries.getLeaderCommit());
133             }
134             raftState = handleAppendEntries(sender, appendEntries, raftState);
135         } else if (message instanceof AppendEntriesReply) {
136             raftState =
137                 handleAppendEntriesReply(sender, (AppendEntriesReply) message,
138                     raftState);
139         } else if (message instanceof RequestVote) {
140             raftState =
141                 handleRequestVote(sender, (RequestVote) message, raftState);
142         } else if (message instanceof RequestVoteReply) {
143             raftState =
144                 handleRequestVoteReply(sender, (RequestVoteReply) message,
145                     raftState);
146         }
147         return raftState;
148     }
149
150     private RaftState applyTerm(RaftRPC rpc) {
151         if (rpc.getTerm() > context.getTermInformation().getCurrentTerm()
152             .get()) {
153             context.getTermInformation().update(rpc.getTerm(), null);
154             return RaftState.Follower;
155         }
156         return state();
157     }
158
159     private void applyLogToStateMachine(long index) {
160         context.getLastApplied().set(index);
161     }
162 }