2 * Copyright (c) 2014 Cisco 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
9 package org.opendaylight.controller.cluster.raft.messages;
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;
19 * Reply for the AppendEntries message.
21 public class AppendEntriesReply extends AbstractRaftRPC {
22 private static final long serialVersionUID = -7487547356392536683L;
24 // true if follower contained entry matching
25 // prevLogIndex and prevLogTerm
26 private final boolean success;
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
31 private final long logLastIndex;
33 private final long logLastTerm;
35 // The followerId - this will be used to figure out which follower is
37 private final String followerId;
39 private final short payloadVersion;
41 private final short raftVersion;
43 private final boolean forceInstallSnapshot;
45 private final boolean needsLeaderAddress;
47 private final short recipientRaftVersion;
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);
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);
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) {
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;
79 public boolean isSuccess() {
83 public long getLogLastIndex() {
87 public long getLogLastTerm() {
91 public String getFollowerId() {
95 public short getPayloadVersion() {
96 return payloadVersion;
99 public short getRaftVersion() {
103 public boolean isForceInstallSnapshot() {
104 return forceInstallSnapshot;
107 public boolean isNeedsLeaderAddress() {
108 return needsLeaderAddress;
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 + "]";
120 private Object writeReplace() {
121 return recipientRaftVersion >= RaftVersions.FLUORINE_VERSION ? new Proxy2(this) : new Proxy(this);
125 * Fluorine version that adds the needsLeaderAddress flag.
127 private static class Proxy2 implements Externalizable {
128 private static final long serialVersionUID = 1L;
130 private AppendEntriesReply appendEntriesReply;
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")
138 Proxy2(AppendEntriesReply appendEntriesReply) {
139 this.appendEntriesReply = appendEntriesReply;
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);
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();
167 appendEntriesReply = new AppendEntriesReply(followerId, term, success, logLastIndex, logLastTerm,
168 payloadVersion, forceInstallSnapshot, needsLeaderAddress, raftVersion,
169 RaftVersions.CURRENT_VERSION);
172 private Object readResolve() {
173 return appendEntriesReply;
178 * Pre-Fluorine version.
181 private static class Proxy implements Externalizable {
182 private static final long serialVersionUID = 1L;
184 private AppendEntriesReply appendEntriesReply;
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")
192 Proxy(AppendEntriesReply appendEntriesReply) {
193 this.appendEntriesReply = appendEntriesReply;
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);
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();
219 appendEntriesReply = new AppendEntriesReply(followerId, term, success, logLastIndex, logLastTerm,
220 payloadVersion, forceInstallSnapshot, false, raftVersion, RaftVersions.CURRENT_VERSION);
223 private Object readResolve() {
224 return appendEntriesReply;