902b9a03b757930ccceeb07c4eb621bab2dbeb78
[controller.git] / opendaylight / md-sal / sal-akka-raft / src / main / java / org / opendaylight / controller / cluster / raft / messages / AppendEntriesReply.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.messages;
10
11 import com.google.common.annotations.VisibleForTesting;
12 import java.io.Externalizable;
13 import java.io.IOException;
14 import java.io.ObjectInput;
15 import java.io.ObjectOutput;
16 import org.opendaylight.controller.cluster.raft.RaftVersions;
17
18 /**
19  * Reply for the AppendEntries message.
20  */
21 public class AppendEntriesReply extends AbstractRaftRPC {
22     private static final long serialVersionUID = -7487547356392536683L;
23
24     // true if follower contained entry matching
25     // prevLogIndex and prevLogTerm
26     private final boolean success;
27
28     // The index of the last entry in the followers log
29     // This will be used to set the matchIndex for the follower on the
30     // Leader
31     private final long logLastIndex;
32
33     private final long logLastTerm;
34
35     // The followerId - this will be used to figure out which follower is
36     // responding
37     private final String followerId;
38
39     private final short payloadVersion;
40
41     private final short raftVersion;
42
43     private final boolean forceInstallSnapshot;
44
45     private final boolean needsLeaderAddress;
46
47     private final short recipientRaftVersion;
48
49     @VisibleForTesting
50     public AppendEntriesReply(String followerId, long term, boolean success, long logLastIndex, long logLastTerm,
51             short payloadVersion) {
52         this(followerId, term, success, logLastIndex, logLastTerm, payloadVersion, false, false,
53                 RaftVersions.CURRENT_VERSION);
54     }
55
56     public AppendEntriesReply(String followerId, long term, boolean success, long logLastIndex, long logLastTerm,
57             short payloadVersion, boolean forceInstallSnapshot, boolean needsLeaderAddress,
58             short recipientRaftVersion) {
59         this(followerId, term, success, logLastIndex, logLastTerm, payloadVersion, forceInstallSnapshot,
60                 needsLeaderAddress, RaftVersions.CURRENT_VERSION, recipientRaftVersion);
61
62     }
63
64     private AppendEntriesReply(String followerId, long term, boolean success, long logLastIndex, long logLastTerm,
65             short payloadVersion, boolean forceInstallSnapshot, boolean needsLeaderAddress, short raftVersion,
66             short recipientRaftVersion) {
67         super(term);
68         this.followerId = followerId;
69         this.success = success;
70         this.logLastIndex = logLastIndex;
71         this.logLastTerm = logLastTerm;
72         this.payloadVersion = payloadVersion;
73         this.forceInstallSnapshot = forceInstallSnapshot;
74         this.raftVersion = raftVersion;
75         this.needsLeaderAddress = needsLeaderAddress;
76         this.recipientRaftVersion = recipientRaftVersion;
77     }
78
79     public boolean isSuccess() {
80         return success;
81     }
82
83     public long getLogLastIndex() {
84         return logLastIndex;
85     }
86
87     public long getLogLastTerm() {
88         return logLastTerm;
89     }
90
91     public String getFollowerId() {
92         return followerId;
93     }
94
95     public short getPayloadVersion() {
96         return payloadVersion;
97     }
98
99     public short getRaftVersion() {
100         return raftVersion;
101     }
102
103     public boolean isForceInstallSnapshot() {
104         return forceInstallSnapshot;
105     }
106
107     public boolean isNeedsLeaderAddress() {
108         return needsLeaderAddress;
109     }
110
111     @Override
112     public String toString() {
113         return "AppendEntriesReply [term=" + getTerm() + ", success=" + success + ", followerId=" + followerId
114                 + ", logLastIndex=" + logLastIndex + ", logLastTerm=" + logLastTerm + ", forceInstallSnapshot="
115                 + forceInstallSnapshot + ", needsLeaderAddress=" + needsLeaderAddress
116                 + ", payloadVersion=" + payloadVersion + ", raftVersion=" + raftVersion
117                 + ", recipientRaftVersion=" + recipientRaftVersion + "]";
118     }
119
120     private Object writeReplace() {
121         return recipientRaftVersion >= RaftVersions.FLUORINE_VERSION ? new Proxy2(this) : new Proxy(this);
122     }
123
124     /**
125      * Fluorine version that adds the needsLeaderAddress flag.
126      */
127     private static class Proxy2 implements Externalizable {
128         private static final long serialVersionUID = 1L;
129
130         private AppendEntriesReply appendEntriesReply;
131
132         // checkstyle flags the public modifier as redundant which really doesn't make sense since it clearly isn't
133         // redundant. It is explicitly needed for Java serialization to be able to create instances via reflection.
134         @SuppressWarnings("checkstyle:RedundantModifier")
135         public Proxy2() {
136         }
137
138         Proxy2(AppendEntriesReply appendEntriesReply) {
139             this.appendEntriesReply = appendEntriesReply;
140         }
141
142         @Override
143         public void writeExternal(ObjectOutput out) throws IOException {
144             out.writeShort(appendEntriesReply.raftVersion);
145             out.writeLong(appendEntriesReply.getTerm());
146             out.writeObject(appendEntriesReply.followerId);
147             out.writeBoolean(appendEntriesReply.success);
148             out.writeLong(appendEntriesReply.logLastIndex);
149             out.writeLong(appendEntriesReply.logLastTerm);
150             out.writeShort(appendEntriesReply.payloadVersion);
151             out.writeBoolean(appendEntriesReply.forceInstallSnapshot);
152             out.writeBoolean(appendEntriesReply.needsLeaderAddress);
153         }
154
155         @Override
156         public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
157             short raftVersion = in.readShort();
158             long term = in.readLong();
159             String followerId = (String) in.readObject();
160             boolean success = in.readBoolean();
161             long logLastIndex = in.readLong();
162             long logLastTerm = in.readLong();
163             short payloadVersion = in.readShort();
164             boolean forceInstallSnapshot = in.readBoolean();
165             boolean needsLeaderAddress = in.readBoolean();
166
167             appendEntriesReply = new AppendEntriesReply(followerId, term, success, logLastIndex, logLastTerm,
168                     payloadVersion, forceInstallSnapshot, needsLeaderAddress, raftVersion,
169                     RaftVersions.CURRENT_VERSION);
170         }
171
172         private Object readResolve() {
173             return appendEntriesReply;
174         }
175     }
176
177     /**
178      * Pre-Fluorine version.
179      */
180     @Deprecated
181     private static class Proxy implements Externalizable {
182         private static final long serialVersionUID = 1L;
183
184         private AppendEntriesReply appendEntriesReply;
185
186         // checkstyle flags the public modifier as redundant which really doesn't make sense since it clearly isn't
187         // redundant. It is explicitly needed for Java serialization to be able to create instances via reflection.
188         @SuppressWarnings("checkstyle:RedundantModifier")
189         public Proxy() {
190         }
191
192         Proxy(AppendEntriesReply appendEntriesReply) {
193             this.appendEntriesReply = appendEntriesReply;
194         }
195
196         @Override
197         public void writeExternal(ObjectOutput out) throws IOException {
198             out.writeShort(appendEntriesReply.raftVersion);
199             out.writeLong(appendEntriesReply.getTerm());
200             out.writeObject(appendEntriesReply.followerId);
201             out.writeBoolean(appendEntriesReply.success);
202             out.writeLong(appendEntriesReply.logLastIndex);
203             out.writeLong(appendEntriesReply.logLastTerm);
204             out.writeShort(appendEntriesReply.payloadVersion);
205             out.writeBoolean(appendEntriesReply.forceInstallSnapshot);
206         }
207
208         @Override
209         public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
210             short raftVersion = in.readShort();
211             long term = in.readLong();
212             String followerId = (String) in.readObject();
213             boolean success = in.readBoolean();
214             long logLastIndex = in.readLong();
215             long logLastTerm = in.readLong();
216             short payloadVersion = in.readShort();
217             boolean forceInstallSnapshot = in.readBoolean();
218
219             appendEntriesReply = new AppendEntriesReply(followerId, term, success, logLastIndex, logLastTerm,
220                     payloadVersion, forceInstallSnapshot, false, raftVersion, RaftVersions.CURRENT_VERSION);
221         }
222
223         private Object readResolve() {
224             return appendEntriesReply;
225         }
226     }
227 }