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