80bcb70d9af9426daf7b65f275e13752038f4a85
[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 package org.opendaylight.controller.cluster.raft.messages;
9
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;
16
17 /**
18  * Reply for the AppendEntries message.
19  */
20 public final class AppendEntriesReply extends AbstractRaftRPC {
21     private static final long serialVersionUID = -7487547356392536683L;
22
23     // true if follower contained entry matching
24     // prevLogIndex and prevLogTerm
25     private final boolean success;
26
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
29     // Leader
30     private final long logLastIndex;
31
32     private final long logLastTerm;
33
34     // The followerId - this will be used to figure out which follower is
35     // responding
36     private final String followerId;
37
38     private final short payloadVersion;
39
40     private final short raftVersion;
41
42     private final boolean forceInstallSnapshot;
43
44     private final boolean needsLeaderAddress;
45
46     private final short recipientRaftVersion;
47
48     @VisibleForTesting
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);
53     }
54
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);
60     }
61
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) {
65         super(term);
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;
75     }
76
77     public boolean isSuccess() {
78         return success;
79     }
80
81     public long getLogLastIndex() {
82         return logLastIndex;
83     }
84
85     public long getLogLastTerm() {
86         return logLastTerm;
87     }
88
89     public String getFollowerId() {
90         return followerId;
91     }
92
93     public short getPayloadVersion() {
94         return payloadVersion;
95     }
96
97     public short getRaftVersion() {
98         return raftVersion;
99     }
100
101     public boolean isForceInstallSnapshot() {
102         return forceInstallSnapshot;
103     }
104
105     public boolean isNeedsLeaderAddress() {
106         return needsLeaderAddress;
107     }
108
109     @Override
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 + "]";
116     }
117
118     @Override
119     Object writeReplace() {
120         if (recipientRaftVersion <= RaftVersions.BORON_VERSION) {
121             return new Proxy(this);
122         }
123         return recipientRaftVersion == RaftVersions.FLUORINE_VERSION ? new Proxy2(this) : new AR(this);
124     }
125
126     /**
127      * Fluorine version that adds the needsLeaderAddress flag.
128      */
129     private static class Proxy2 implements Externalizable {
130         private static final long serialVersionUID = 1L;
131
132         private AppendEntriesReply appendEntriesReply;
133
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")
137         public Proxy2() {
138         }
139
140         Proxy2(final AppendEntriesReply appendEntriesReply) {
141             this.appendEntriesReply = appendEntriesReply;
142         }
143
144         @Override
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);
155         }
156
157         @Override
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();
168
169             appendEntriesReply = new AppendEntriesReply(followerId, term, success, logLastIndex, logLastTerm,
170                     payloadVersion, forceInstallSnapshot, needsLeaderAddress, raftVersion,
171                     RaftVersions.CURRENT_VERSION);
172         }
173
174         private Object readResolve() {
175             return appendEntriesReply;
176         }
177     }
178
179     /**
180      * Pre-Fluorine version.
181      */
182     @Deprecated
183     private static class Proxy implements Externalizable {
184         private static final long serialVersionUID = 1L;
185
186         private AppendEntriesReply appendEntriesReply;
187
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")
191         public Proxy() {
192         }
193
194         Proxy(final AppendEntriesReply appendEntriesReply) {
195             this.appendEntriesReply = appendEntriesReply;
196         }
197
198         @Override
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);
208         }
209
210         @Override
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();
220
221             appendEntriesReply = new AppendEntriesReply(followerId, term, success, logLastIndex, logLastTerm,
222                     payloadVersion, forceInstallSnapshot, false, raftVersion, RaftVersions.CURRENT_VERSION);
223         }
224
225         private Object readResolve() {
226             return appendEntriesReply;
227         }
228     }
229 }