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
8 package org.opendaylight.controller.cluster.raft.messages;
10 import com.google.common.annotations.VisibleForTesting;
11 import java.io.Externalizable;
12 import java.io.IOException;
13 import java.io.ObjectInput;
14 import java.io.ObjectOutput;
15 import org.opendaylight.controller.cluster.raft.RaftVersions;
18 * Reply for the AppendEntries message.
20 public final 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(final String followerId, final long term, final boolean success, final long logLastIndex,
51 final long logLastTerm, final short payloadVersion) {
52 this(followerId, term, success, logLastIndex, logLastTerm, payloadVersion, false, false,
53 RaftVersions.CURRENT_VERSION);
56 public AppendEntriesReply(final String followerId, final long term, final boolean success, final long logLastIndex,
57 final long logLastTerm, final short payloadVersion, final boolean forceInstallSnapshot,
58 final boolean needsLeaderAddress, final short recipientRaftVersion) {
59 this(followerId, term, success, logLastIndex, logLastTerm, payloadVersion, forceInstallSnapshot,
60 needsLeaderAddress, RaftVersions.CURRENT_VERSION, recipientRaftVersion);
63 AppendEntriesReply(final String followerId, final long term, final boolean success, final long logLastIndex,
64 final long logLastTerm, final short payloadVersion, final boolean forceInstallSnapshot,
65 final boolean needsLeaderAddress, final short raftVersion, final short recipientRaftVersion) {
67 this.followerId = followerId;
68 this.success = success;
69 this.logLastIndex = logLastIndex;
70 this.logLastTerm = logLastTerm;
71 this.payloadVersion = payloadVersion;
72 this.forceInstallSnapshot = forceInstallSnapshot;
73 this.raftVersion = raftVersion;
74 this.needsLeaderAddress = needsLeaderAddress;
75 this.recipientRaftVersion = recipientRaftVersion;
78 public boolean isSuccess() {
82 public long getLogLastIndex() {
86 public long getLogLastTerm() {
90 public String getFollowerId() {
94 public short getPayloadVersion() {
95 return payloadVersion;
98 public short getRaftVersion() {
102 public boolean isForceInstallSnapshot() {
103 return forceInstallSnapshot;
106 public boolean isNeedsLeaderAddress() {
107 return needsLeaderAddress;
111 public String toString() {
112 return "AppendEntriesReply [term=" + getTerm() + ", success=" + success + ", followerId=" + followerId
113 + ", logLastIndex=" + logLastIndex + ", logLastTerm=" + logLastTerm + ", forceInstallSnapshot="
114 + forceInstallSnapshot + ", needsLeaderAddress=" + needsLeaderAddress
115 + ", payloadVersion=" + payloadVersion + ", raftVersion=" + raftVersion
116 + ", recipientRaftVersion=" + recipientRaftVersion + "]";
120 Object writeReplace() {
121 if (recipientRaftVersion <= RaftVersions.BORON_VERSION) {
122 return new Proxy(this);
124 return recipientRaftVersion == RaftVersions.FLUORINE_VERSION ? new Proxy2(this) : new AR(this);
128 * Fluorine version that adds the needsLeaderAddress flag.
130 private static class Proxy2 implements Externalizable {
131 private static final long serialVersionUID = 1L;
133 private AppendEntriesReply appendEntriesReply;
135 // checkstyle flags the public modifier as redundant which really doesn't make sense since it clearly isn't
136 // redundant. It is explicitly needed for Java serialization to be able to create instances via reflection.
137 @SuppressWarnings("checkstyle:RedundantModifier")
141 Proxy2(final AppendEntriesReply appendEntriesReply) {
142 this.appendEntriesReply = appendEntriesReply;
146 public void writeExternal(final ObjectOutput out) throws IOException {
147 out.writeShort(appendEntriesReply.raftVersion);
148 out.writeLong(appendEntriesReply.getTerm());
149 out.writeObject(appendEntriesReply.followerId);
150 out.writeBoolean(appendEntriesReply.success);
151 out.writeLong(appendEntriesReply.logLastIndex);
152 out.writeLong(appendEntriesReply.logLastTerm);
153 out.writeShort(appendEntriesReply.payloadVersion);
154 out.writeBoolean(appendEntriesReply.forceInstallSnapshot);
155 out.writeBoolean(appendEntriesReply.needsLeaderAddress);
159 public void readExternal(final ObjectInput in) throws IOException, ClassNotFoundException {
160 short raftVersion = in.readShort();
161 long term = in.readLong();
162 String followerId = (String) in.readObject();
163 boolean success = in.readBoolean();
164 long logLastIndex = in.readLong();
165 long logLastTerm = in.readLong();
166 short payloadVersion = in.readShort();
167 boolean forceInstallSnapshot = in.readBoolean();
168 boolean needsLeaderAddress = in.readBoolean();
170 appendEntriesReply = new AppendEntriesReply(followerId, term, success, logLastIndex, logLastTerm,
171 payloadVersion, forceInstallSnapshot, needsLeaderAddress, raftVersion,
172 RaftVersions.CURRENT_VERSION);
175 private Object readResolve() {
176 return appendEntriesReply;
181 * Pre-Fluorine version.
184 private static class Proxy implements Externalizable {
185 private static final long serialVersionUID = 1L;
187 private AppendEntriesReply appendEntriesReply;
189 // checkstyle flags the public modifier as redundant which really doesn't make sense since it clearly isn't
190 // redundant. It is explicitly needed for Java serialization to be able to create instances via reflection.
191 @SuppressWarnings("checkstyle:RedundantModifier")
195 Proxy(final AppendEntriesReply appendEntriesReply) {
196 this.appendEntriesReply = appendEntriesReply;
200 public void writeExternal(final ObjectOutput out) throws IOException {
201 out.writeShort(appendEntriesReply.raftVersion);
202 out.writeLong(appendEntriesReply.getTerm());
203 out.writeObject(appendEntriesReply.followerId);
204 out.writeBoolean(appendEntriesReply.success);
205 out.writeLong(appendEntriesReply.logLastIndex);
206 out.writeLong(appendEntriesReply.logLastTerm);
207 out.writeShort(appendEntriesReply.payloadVersion);
208 out.writeBoolean(appendEntriesReply.forceInstallSnapshot);
212 public void readExternal(final ObjectInput in) throws IOException, ClassNotFoundException {
213 short raftVersion = in.readShort();
214 long term = in.readLong();
215 String followerId = (String) in.readObject();
216 boolean success = in.readBoolean();
217 long logLastIndex = in.readLong();
218 long logLastTerm = in.readLong();
219 short payloadVersion = in.readShort();
220 boolean forceInstallSnapshot = in.readBoolean();
222 appendEntriesReply = new AppendEntriesReply(followerId, term, success, logLastIndex, logLastTerm,
223 payloadVersion, forceInstallSnapshot, false, raftVersion, RaftVersions.CURRENT_VERSION);
226 private Object readResolve() {
227 return appendEntriesReply;