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 private 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 return recipientRaftVersion >= RaftVersions.FLUORINE_VERSION ? new Proxy2(this) : new Proxy(this);
124 * Fluorine version that adds the needsLeaderAddress flag.
126 private static class Proxy2 implements Externalizable {
127 private static final long serialVersionUID = 1L;
129 private AppendEntriesReply appendEntriesReply;
131 // checkstyle flags the public modifier as redundant which really doesn't make sense since it clearly isn't
132 // redundant. It is explicitly needed for Java serialization to be able to create instances via reflection.
133 @SuppressWarnings("checkstyle:RedundantModifier")
137 Proxy2(final AppendEntriesReply appendEntriesReply) {
138 this.appendEntriesReply = appendEntriesReply;
142 public void writeExternal(final ObjectOutput out) throws IOException {
143 out.writeShort(appendEntriesReply.raftVersion);
144 out.writeLong(appendEntriesReply.getTerm());
145 out.writeObject(appendEntriesReply.followerId);
146 out.writeBoolean(appendEntriesReply.success);
147 out.writeLong(appendEntriesReply.logLastIndex);
148 out.writeLong(appendEntriesReply.logLastTerm);
149 out.writeShort(appendEntriesReply.payloadVersion);
150 out.writeBoolean(appendEntriesReply.forceInstallSnapshot);
151 out.writeBoolean(appendEntriesReply.needsLeaderAddress);
155 public void readExternal(final ObjectInput in) throws IOException, ClassNotFoundException {
156 short raftVersion = in.readShort();
157 long term = in.readLong();
158 String followerId = (String) in.readObject();
159 boolean success = in.readBoolean();
160 long logLastIndex = in.readLong();
161 long logLastTerm = in.readLong();
162 short payloadVersion = in.readShort();
163 boolean forceInstallSnapshot = in.readBoolean();
164 boolean needsLeaderAddress = in.readBoolean();
166 appendEntriesReply = new AppendEntriesReply(followerId, term, success, logLastIndex, logLastTerm,
167 payloadVersion, forceInstallSnapshot, needsLeaderAddress, raftVersion,
168 RaftVersions.CURRENT_VERSION);
171 private Object readResolve() {
172 return appendEntriesReply;
177 * Pre-Fluorine version.
180 private static class Proxy implements Externalizable {
181 private static final long serialVersionUID = 1L;
183 private AppendEntriesReply appendEntriesReply;
185 // checkstyle flags the public modifier as redundant which really doesn't make sense since it clearly isn't
186 // redundant. It is explicitly needed for Java serialization to be able to create instances via reflection.
187 @SuppressWarnings("checkstyle:RedundantModifier")
191 Proxy(final AppendEntriesReply appendEntriesReply) {
192 this.appendEntriesReply = appendEntriesReply;
196 public void writeExternal(final ObjectOutput out) throws IOException {
197 out.writeShort(appendEntriesReply.raftVersion);
198 out.writeLong(appendEntriesReply.getTerm());
199 out.writeObject(appendEntriesReply.followerId);
200 out.writeBoolean(appendEntriesReply.success);
201 out.writeLong(appendEntriesReply.logLastIndex);
202 out.writeLong(appendEntriesReply.logLastTerm);
203 out.writeShort(appendEntriesReply.payloadVersion);
204 out.writeBoolean(appendEntriesReply.forceInstallSnapshot);
208 public void readExternal(final ObjectInput in) throws IOException, ClassNotFoundException {
209 short raftVersion = in.readShort();
210 long term = in.readLong();
211 String followerId = (String) in.readObject();
212 boolean success = in.readBoolean();
213 long logLastIndex = in.readLong();
214 long logLastTerm = in.readLong();
215 short payloadVersion = in.readShort();
216 boolean forceInstallSnapshot = in.readBoolean();
218 appendEntriesReply = new AppendEntriesReply(followerId, term, success, logLastIndex, logLastTerm,
219 payloadVersion, forceInstallSnapshot, false, raftVersion, RaftVersions.CURRENT_VERSION);
222 private Object readResolve() {
223 return appendEntriesReply;