import static java.util.Objects.requireNonNull;
import com.google.common.annotations.VisibleForTesting;
+import com.google.common.collect.ImmutableList;
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
-import java.util.ArrayList;
import java.util.List;
-import java.util.Optional;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.opendaylight.controller.cluster.raft.RaftVersions;
import org.opendaylight.controller.cluster.raft.ReplicatedLogEntry;
import org.opendaylight.controller.cluster.raft.persisted.SimpleReplicatedLogEntry;
-import org.opendaylight.controller.cluster.raft.protobuff.client.messages.Payload;
/**
* Invoked by leader to replicate log entries (§5.3); also used as heartbeat (§5.2).
*/
public final class AppendEntries extends AbstractRaftRPC {
+ @java.io.Serial
private static final long serialVersionUID = 1L;
// So that follower can redirect clients
private final String leaderAddress;
- private AppendEntries(final long term, @NonNull final String leaderId, final long prevLogIndex,
+ AppendEntries(final long term, @NonNull final String leaderId, final long prevLogIndex,
final long prevLogTerm, @NonNull final List<ReplicatedLogEntry> entries, final long leaderCommit,
final long replicatedToAllIndex, final short payloadVersion, final short recipientRaftVersion,
final short leaderRaftVersion, @Nullable final String leaderAddress) {
return payloadVersion;
}
- public Optional<String> getLeaderAddress() {
- return Optional.ofNullable(leaderAddress);
+ public @Nullable String leaderAddress() {
+ return leaderAddress;
}
public short getLeaderRaftVersion() {
@Override
Object writeReplace() {
- return recipientRaftVersion >= RaftVersions.FLUORINE_VERSION ? new ProxyV2(this) : new Proxy(this);
+ return recipientRaftVersion <= RaftVersions.FLUORINE_VERSION ? new ProxyV2(this) : new AE(this);
}
/**
* Fluorine version that adds the leader address.
*/
private static class ProxyV2 implements Externalizable {
+ @java.io.Serial
private static final long serialVersionUID = 1L;
private AppendEntries appendEntries;
out.writeInt(appendEntries.entries.size());
for (ReplicatedLogEntry e: appendEntries.entries) {
- out.writeLong(e.getIndex());
- out.writeLong(e.getTerm());
+ out.writeLong(e.index());
+ out.writeLong(e.term());
out.writeObject(e.getData());
}
short payloadVersion = in.readShort();
int size = in.readInt();
- List<ReplicatedLogEntry> entries = new ArrayList<>(size);
+ var entries = ImmutableList.<ReplicatedLogEntry>builderWithExpectedSize(size);
for (int i = 0; i < size; i++) {
entries.add(new SimpleReplicatedLogEntry(in.readLong(), in.readLong(), (Payload) in.readObject()));
}
String leaderAddress = (String)in.readObject();
- appendEntries = new AppendEntries(term, leaderId, prevLogIndex, prevLogTerm, entries, leaderCommit,
+ appendEntries = new AppendEntries(term, leaderId, prevLogIndex, prevLogTerm, entries.build(), leaderCommit,
replicatedToAllIndex, payloadVersion, RaftVersions.CURRENT_VERSION, leaderRaftVersion,
leaderAddress);
}
- private Object readResolve() {
- return appendEntries;
- }
- }
-
- /**
- * Pre-Fluorine version.
- */
- @Deprecated
- private static class Proxy implements Externalizable {
- private static final long serialVersionUID = 1L;
-
- private AppendEntries appendEntries;
-
- // checkstyle flags the public modifier as redundant which really doesn't make sense since it clearly isn't
- // redundant. It is explicitly needed for Java serialization to be able to create instances via reflection.
- @SuppressWarnings("checkstyle:RedundantModifier")
- public Proxy() {
- }
-
- Proxy(final AppendEntries appendEntries) {
- this.appendEntries = appendEntries;
- }
-
- @Override
- public void writeExternal(final ObjectOutput out) throws IOException {
- out.writeLong(appendEntries.getTerm());
- out.writeObject(appendEntries.leaderId);
- out.writeLong(appendEntries.prevLogTerm);
- out.writeLong(appendEntries.prevLogIndex);
- out.writeLong(appendEntries.leaderCommit);
- out.writeLong(appendEntries.replicatedToAllIndex);
- out.writeShort(appendEntries.payloadVersion);
-
- out.writeInt(appendEntries.entries.size());
- for (ReplicatedLogEntry e: appendEntries.entries) {
- out.writeLong(e.getIndex());
- out.writeLong(e.getTerm());
- out.writeObject(e.getData());
- }
- }
-
- @Override
- public void readExternal(final ObjectInput in) throws IOException, ClassNotFoundException {
- long term = in.readLong();
- String leaderId = (String) in.readObject();
- long prevLogTerm = in.readLong();
- long prevLogIndex = in.readLong();
- long leaderCommit = in.readLong();
- long replicatedToAllIndex = in.readLong();
- short payloadVersion = in.readShort();
-
- int size = in.readInt();
- List<ReplicatedLogEntry> entries = new ArrayList<>(size);
- for (int i = 0; i < size; i++) {
- entries.add(new SimpleReplicatedLogEntry(in.readLong(), in.readLong(), (Payload) in.readObject()));
- }
-
- appendEntries = new AppendEntries(term, leaderId, prevLogIndex, prevLogTerm, entries, leaderCommit,
- replicatedToAllIndex, payloadVersion, RaftVersions.CURRENT_VERSION, RaftVersions.BORON_VERSION, null);
- }
-
+ @java.io.Serial
private Object readResolve() {
return appendEntries;
}