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 {
21 private static final long serialVersionUID = -7487547356392536683L;
23 // true if follower contained entry matching
24 // prevLogIndex and prevLogTerm
25 private final boolean success;
27 // The index of the last entry in the followers log
28 // This will be used to set the matchIndex for the follower on the
30 private final long logLastIndex;
32 private final long logLastTerm;
34 // The followerId - this will be used to figure out which follower is
36 private final String followerId;
38 private final short payloadVersion;
40 private final short raftVersion;
42 private final boolean forceInstallSnapshot;
44 private final boolean needsLeaderAddress;
46 private final short recipientRaftVersion;
49 public AppendEntriesReply(final String followerId, final long term, final boolean success, final long logLastIndex,
50 final long logLastTerm, final short payloadVersion) {
51 this(followerId, term, success, logLastIndex, logLastTerm, payloadVersion, false, false,
52 RaftVersions.CURRENT_VERSION);
55 public AppendEntriesReply(final String followerId, final long term, final boolean success, final long logLastIndex,
56 final long logLastTerm, final short payloadVersion, final boolean forceInstallSnapshot,
57 final boolean needsLeaderAddress, final short recipientRaftVersion) {
58 this(followerId, term, success, logLastIndex, logLastTerm, payloadVersion, forceInstallSnapshot,
59 needsLeaderAddress, RaftVersions.CURRENT_VERSION, recipientRaftVersion);
62 AppendEntriesReply(final String followerId, final long term, final boolean success, final long logLastIndex,
63 final long logLastTerm, final short payloadVersion, final boolean forceInstallSnapshot,
64 final boolean needsLeaderAddress, final short raftVersion, final short recipientRaftVersion) {
66 this.followerId = followerId;
67 this.success = success;
68 this.logLastIndex = logLastIndex;
69 this.logLastTerm = logLastTerm;
70 this.payloadVersion = payloadVersion;
71 this.forceInstallSnapshot = forceInstallSnapshot;
72 this.raftVersion = raftVersion;
73 this.needsLeaderAddress = needsLeaderAddress;
74 this.recipientRaftVersion = recipientRaftVersion;
77 public boolean isSuccess() {
81 public long getLogLastIndex() {
85 public long getLogLastTerm() {
89 public String getFollowerId() {
93 public short getPayloadVersion() {
94 return payloadVersion;
97 public short getRaftVersion() {
101 public boolean isForceInstallSnapshot() {
102 return forceInstallSnapshot;
105 public boolean isNeedsLeaderAddress() {
106 return needsLeaderAddress;
110 public String toString() {
111 return "AppendEntriesReply [term=" + getTerm() + ", success=" + success + ", followerId=" + followerId
112 + ", logLastIndex=" + logLastIndex + ", logLastTerm=" + logLastTerm + ", forceInstallSnapshot="
113 + forceInstallSnapshot + ", needsLeaderAddress=" + needsLeaderAddress
114 + ", payloadVersion=" + payloadVersion + ", raftVersion=" + raftVersion
115 + ", recipientRaftVersion=" + recipientRaftVersion + "]";
119 Object writeReplace() {
120 if (recipientRaftVersion <= RaftVersions.BORON_VERSION) {
121 return new Proxy(this);
123 return recipientRaftVersion == RaftVersions.FLUORINE_VERSION ? new Proxy2(this) : new AR(this);
127 * Fluorine version that adds the needsLeaderAddress flag.
129 private static class Proxy2 implements Externalizable {
130 private static final long serialVersionUID = 1L;
132 private AppendEntriesReply appendEntriesReply;
134 // checkstyle flags the public modifier as redundant which really doesn't make sense since it clearly isn't
135 // redundant. It is explicitly needed for Java serialization to be able to create instances via reflection.
136 @SuppressWarnings("checkstyle:RedundantModifier")
140 Proxy2(final AppendEntriesReply appendEntriesReply) {
141 this.appendEntriesReply = appendEntriesReply;
145 public void writeExternal(final ObjectOutput out) throws IOException {
146 out.writeShort(appendEntriesReply.raftVersion);
147 out.writeLong(appendEntriesReply.getTerm());
148 out.writeObject(appendEntriesReply.followerId);
149 out.writeBoolean(appendEntriesReply.success);
150 out.writeLong(appendEntriesReply.logLastIndex);
151 out.writeLong(appendEntriesReply.logLastTerm);
152 out.writeShort(appendEntriesReply.payloadVersion);
153 out.writeBoolean(appendEntriesReply.forceInstallSnapshot);
154 out.writeBoolean(appendEntriesReply.needsLeaderAddress);
158 public void readExternal(final ObjectInput in) throws IOException, ClassNotFoundException {
159 short raftVersion = in.readShort();
160 long term = in.readLong();
161 String followerId = (String) in.readObject();
162 boolean success = in.readBoolean();
163 long logLastIndex = in.readLong();
164 long logLastTerm = in.readLong();
165 short payloadVersion = in.readShort();
166 boolean forceInstallSnapshot = in.readBoolean();
167 boolean needsLeaderAddress = in.readBoolean();
169 appendEntriesReply = new AppendEntriesReply(followerId, term, success, logLastIndex, logLastTerm,
170 payloadVersion, forceInstallSnapshot, needsLeaderAddress, raftVersion,
171 RaftVersions.CURRENT_VERSION);
174 private Object readResolve() {
175 return appendEntriesReply;
180 * Pre-Fluorine version.
183 private static class Proxy implements Externalizable {
184 private static final long serialVersionUID = 1L;
186 private AppendEntriesReply appendEntriesReply;
188 // checkstyle flags the public modifier as redundant which really doesn't make sense since it clearly isn't
189 // redundant. It is explicitly needed for Java serialization to be able to create instances via reflection.
190 @SuppressWarnings("checkstyle:RedundantModifier")
194 Proxy(final AppendEntriesReply appendEntriesReply) {
195 this.appendEntriesReply = appendEntriesReply;
199 public void writeExternal(final ObjectOutput out) throws IOException {
200 out.writeShort(appendEntriesReply.raftVersion);
201 out.writeLong(appendEntriesReply.getTerm());
202 out.writeObject(appendEntriesReply.followerId);
203 out.writeBoolean(appendEntriesReply.success);
204 out.writeLong(appendEntriesReply.logLastIndex);
205 out.writeLong(appendEntriesReply.logLastTerm);
206 out.writeShort(appendEntriesReply.payloadVersion);
207 out.writeBoolean(appendEntriesReply.forceInstallSnapshot);
211 public void readExternal(final ObjectInput in) throws IOException, ClassNotFoundException {
212 short raftVersion = in.readShort();
213 long term = in.readLong();
214 String followerId = (String) in.readObject();
215 boolean success = in.readBoolean();
216 long logLastIndex = in.readLong();
217 long logLastTerm = in.readLong();
218 short payloadVersion = in.readShort();
219 boolean forceInstallSnapshot = in.readBoolean();
221 appendEntriesReply = new AppendEntriesReply(followerId, term, success, logLastIndex, logLastTerm,
222 payloadVersion, forceInstallSnapshot, false, raftVersion, RaftVersions.CURRENT_VERSION);
225 private Object readResolve() {
226 return appendEntriesReply;