From: Robert Varga Date: Fri, 2 Dec 2022 16:00:02 +0000 (+0100) Subject: Trigger snapshots on legacy persisted entries X-Git-Tag: v7.0.0~9 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=commitdiff_plain;h=8f7f6ed83f1ab21aa9ba1fb2f4f9fbad3a9bfa56 Trigger snapshots on legacy persisted entries We have migrated proxies, hence we should be purging them from journal if we encounter them during recovery. Introduce a marker interface for that and subclasses which implement it. JIRA: CONTROLLER-2064 Change-Id: Ie16b1247306d64580df977bece70a94eb3187cbf Signed-off-by: Robert Varga --- diff --git a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/persisted/ApplyJournalEntries.java b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/persisted/ApplyJournalEntries.java index ad334f4c15..4439e2cfa1 100644 --- a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/persisted/ApplyJournalEntries.java +++ b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/persisted/ApplyJournalEntries.java @@ -22,13 +22,23 @@ import java.io.Serializable; * * @author Thomas Pantelis */ -public class ApplyJournalEntries implements Serializable, ControlMessage { +public sealed class ApplyJournalEntries implements Serializable, ControlMessage { + @Deprecated(since = "7.0.0", forRemoval = true) + private static final class Legacy extends ApplyJournalEntries implements LegacySerializable { + @java.io.Serial + private static final long serialVersionUID = 1L; + + Legacy(final long toIndex) { + super(toIndex); + } + } + @Deprecated(since = "7.0.0", forRemoval = true) private static final class Proxy implements Externalizable { @java.io.Serial private static final long serialVersionUID = 1L; - private ApplyJournalEntries applyEntries; + private ApplyJournalEntries applyEntries = null; // 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. @@ -37,10 +47,6 @@ public class ApplyJournalEntries implements Serializable, ControlMessage { // For Externalizable } - Proxy(final ApplyJournalEntries applyEntries) { - this.applyEntries = applyEntries; - } - @Override public void writeExternal(final ObjectOutput out) throws IOException { out.writeLong(applyEntries.toIndex); @@ -48,7 +54,7 @@ public class ApplyJournalEntries implements Serializable, ControlMessage { @Override public void readExternal(final ObjectInput in) throws IOException { - applyEntries = new ApplyJournalEntries(in.readLong()); + applyEntries = new Legacy(in.readLong()); } @java.io.Serial @@ -66,16 +72,17 @@ public class ApplyJournalEntries implements Serializable, ControlMessage { this.toIndex = toIndex; } - public long getToIndex() { + public final long getToIndex() { return toIndex; } - private Object writeReplace() { + @java.io.Serial + public final Object writeReplace() { return new AJE(this); } @Override - public String toString() { + public final String toString() { return "ApplyJournalEntries [toIndex=" + toIndex + "]"; } } diff --git a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/persisted/DeleteEntries.java b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/persisted/DeleteEntries.java index b4b4546504..189ca9c5c8 100644 --- a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/persisted/DeleteEntries.java +++ b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/persisted/DeleteEntries.java @@ -18,13 +18,23 @@ import java.io.Serializable; * * @author Thomas Pantelis */ -public class DeleteEntries implements Serializable { +public sealed class DeleteEntries implements Serializable { + @Deprecated(since = "7.0.0", forRemoval = true) + private static final class Legacy extends DeleteEntries implements LegacySerializable { + @java.io.Serial + private static final long serialVersionUID = 1L; + + Legacy(final long fromIndex) { + super(fromIndex); + } + } + @Deprecated(since = "7.0.0", forRemoval = true) private static final class Proxy implements Externalizable { @java.io.Serial private static final long serialVersionUID = 1L; - private DeleteEntries deleteEntries; + private DeleteEntries deleteEntries = null; // 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. @@ -33,10 +43,6 @@ public class DeleteEntries implements Serializable { // For Externalizable } - Proxy(final DeleteEntries deleteEntries) { - this.deleteEntries = deleteEntries; - } - @Override public void writeExternal(final ObjectOutput out) throws IOException { out.writeLong(deleteEntries.fromIndex); @@ -44,7 +50,7 @@ public class DeleteEntries implements Serializable { @Override public void readExternal(final ObjectInput in) throws IOException { - deleteEntries = new DeleteEntries(in.readLong()); + deleteEntries = new Legacy(in.readLong()); } @java.io.Serial @@ -62,16 +68,17 @@ public class DeleteEntries implements Serializable { this.fromIndex = fromIndex; } - public long getFromIndex() { + public final long getFromIndex() { return fromIndex; } - private Object writeReplace() { + @java.io.Serial + public final Object writeReplace() { return new DE(this); } @Override - public String toString() { + public final String toString() { return "DeleteEntries [fromIndex=" + fromIndex + "]"; } } diff --git a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/persisted/LegacySerializable.java b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/persisted/LegacySerializable.java new file mode 100644 index 0000000000..0e75d88fff --- /dev/null +++ b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/persisted/LegacySerializable.java @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2022 PANTHEON.tech, s.r.o. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.cluster.raft.persisted; + +/** + * Marker interface for serializable objects which have been migrated. It implements {@link MigratedSerializable} and + * always returns {@code true} from {@link #isMigrated()}. This interface is marked as deprecated , as any of its users + * should also be marked as deprecated. + */ +@Deprecated +public interface LegacySerializable extends MigratedSerializable { + @Override + @Deprecated(forRemoval = true) + default boolean isMigrated() { + return true; + } +} diff --git a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/persisted/NoopPayload.java b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/persisted/NoopPayload.java index 1fa865948a..f1a3a3b923 100644 --- a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/persisted/NoopPayload.java +++ b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/persisted/NoopPayload.java @@ -10,6 +10,7 @@ package org.opendaylight.controller.cluster.raft.persisted; import akka.dispatch.ControlMessage; import java.io.Serializable; import org.apache.commons.lang3.SerializationUtils; +import org.eclipse.jdt.annotation.NonNull; import org.opendaylight.controller.cluster.raft.messages.Payload; /** @@ -18,14 +19,14 @@ import org.opendaylight.controller.cluster.raft.messages.Payload; * * @author Thomas Pantelis */ -public final class NoopPayload extends Payload implements ControlMessage { - public static final NoopPayload INSTANCE = new NoopPayload(); - +// FIXME: do not implement MigratedSerializable once Proxy is gone +public final class NoopPayload extends Payload implements ControlMessage, MigratedSerializable { // There is no need for Externalizable @Deprecated(since = "7.0.0", forRemoval = true) private static final class Proxy implements Serializable { @java.io.Serial private static final long serialVersionUID = 1L; + private static final @NonNull NoopPayload INSTANCE = new NoopPayload(true); @java.io.Serial private Object readResolve() { @@ -35,12 +36,16 @@ public final class NoopPayload extends Payload implements ControlMessage { @java.io.Serial private static final long serialVersionUID = 1L; - private static final NP PROXY = new NP(); + private static final @NonNull NP PROXY = new NP(); // Estimate to how big the proxy is. Note this includes object stream overhead, so it is a bit conservative private static final int PROXY_SIZE = SerializationUtils.serialize(PROXY).length; - private NoopPayload() { - // Hidden on purpose + public static final @NonNull NoopPayload INSTANCE = new NoopPayload(false); + + private final boolean migrated; + + private NoopPayload(final boolean migrated) { + this.migrated = migrated; } @Override @@ -54,7 +59,13 @@ public final class NoopPayload extends Payload implements ControlMessage { } @Override - protected Object writeReplace() { + public boolean isMigrated() { + return migrated; + } + + // FIXME: protected once not MigratedSerializable + @Override + public Object writeReplace() { return PROXY; } } diff --git a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/persisted/SimpleReplicatedLogEntry.java b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/persisted/SimpleReplicatedLogEntry.java index 56c3f769ff..d075a41701 100644 --- a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/persisted/SimpleReplicatedLogEntry.java +++ b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/persisted/SimpleReplicatedLogEntry.java @@ -23,7 +23,17 @@ import org.opendaylight.controller.cluster.raft.messages.Payload; * * @author Thomas Pantelis */ -public final class SimpleReplicatedLogEntry implements ReplicatedLogEntry, Serializable { +public sealed class SimpleReplicatedLogEntry implements ReplicatedLogEntry, Serializable { + @Deprecated(since = "7.0.0", forRemoval = true) + private static final class Legacy extends SimpleReplicatedLogEntry implements LegacySerializable { + @java.io.Serial + private static final long serialVersionUID = 1L; + + Legacy(final long index, final long term, final Payload payload) { + super(index, term, payload); + } + } + @Deprecated(since = "7.0.0", forRemoval = true) private static final class Proxy implements Externalizable { @java.io.Serial @@ -62,7 +72,7 @@ public final class SimpleReplicatedLogEntry implements ReplicatedLogEntry, Seria @java.io.Serial private Object readResolve() { - return new SimpleReplicatedLogEntry(index, term, data); + return new Legacy(index, term, data); } } @@ -90,46 +100,47 @@ public final class SimpleReplicatedLogEntry implements ReplicatedLogEntry, Seria } @Override - public Payload getData() { + public final Payload getData() { return payload; } @Override - public long getTerm() { + public final long getTerm() { return term; } @Override - public long getIndex() { + public final long getIndex() { return index; } @Override - public int size() { + public final int size() { return payload.size(); } @Override - public int serializedSize() { + public final int serializedSize() { return PROXY_SIZE + payload.serializedSize(); } @Override - public boolean isPersistencePending() { + public final boolean isPersistencePending() { return persistencePending; } @Override - public void setPersistencePending(final boolean pending) { + public final void setPersistencePending(final boolean pending) { persistencePending = pending; } - private Object writeReplace() { + @java.io.Serial + public final Object writeReplace() { return new LE(this); } @Override - public int hashCode() { + public final int hashCode() { final int prime = 31; int result = 1; result = prime * result + payload.hashCode(); @@ -139,20 +150,13 @@ public final class SimpleReplicatedLogEntry implements ReplicatedLogEntry, Seria } @Override - public boolean equals(final Object obj) { - if (this == obj) { - return true; - } - if (obj == null || getClass() != obj.getClass()) { - return false; - } - - var other = (SimpleReplicatedLogEntry) obj; - return index == other.index && term == other.term && payload.equals(other.payload); + public final boolean equals(final Object obj) { + return this == obj || obj instanceof SimpleReplicatedLogEntry other && index == other.index + && term == other.term && payload.equals(other.payload); } @Override - public String toString() { + public final String toString() { return "SimpleReplicatedLogEntry [index=" + index + ", term=" + term + ", payload=" + payload + "]"; } } diff --git a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/persisted/Snapshot.java b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/persisted/Snapshot.java index 9812ac69d5..0acede1086 100644 --- a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/persisted/Snapshot.java +++ b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/persisted/Snapshot.java @@ -22,9 +22,8 @@ import org.opendaylight.controller.cluster.raft.messages.Payload; * * @author Thomas Pantelis */ -// Not final for mocking +// Not final and non-sealed for mocking public class Snapshot implements Serializable { - /** * Implementations of this interface are used as the state payload for a snapshot. * @@ -42,12 +41,25 @@ public class Snapshot implements Serializable { } } + @Deprecated(since = "7.0.0", forRemoval = true) + private static final class Legacy extends Snapshot implements LegacySerializable { + @java.io.Serial + private static final long serialVersionUID = 1L; + + Legacy(final State state, final List unAppliedEntries, final long lastIndex, + final long lastTerm, final long lastAppliedIndex, final long lastAppliedTerm, final long electionTerm, + final String electionVotedFor, final ServerConfigurationPayload serverConfig) { + super(state, unAppliedEntries, lastIndex, lastTerm, lastAppliedIndex, lastAppliedTerm, electionTerm, + electionVotedFor, serverConfig); + } + } + @Deprecated(since = "7.0.0", forRemoval = true) private static final class Proxy implements Externalizable { @java.io.Serial private static final long serialVersionUID = 1L; - private Snapshot snapshot; + private Snapshot snapshot = null; // 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. @@ -56,10 +68,6 @@ public class Snapshot implements Serializable { // For Externalizable } - Proxy(final Snapshot snapshot) { - this.snapshot = snapshot; - } - @Override public void writeExternal(final ObjectOutput out) throws IOException { out.writeLong(snapshot.lastIndex); @@ -91,7 +99,7 @@ public class Snapshot implements Serializable { ServerConfigurationPayload serverConfig = (ServerConfigurationPayload) in.readObject(); int size = in.readInt(); - List unAppliedEntries = new ArrayList<>(size); + var unAppliedEntries = new ArrayList(size); for (int i = 0; i < size; i++) { unAppliedEntries.add(new SimpleReplicatedLogEntry(in.readLong(), in.readLong(), (Payload) in.readObject())); @@ -99,7 +107,7 @@ public class Snapshot implements Serializable { State state = (State) in.readObject(); - snapshot = Snapshot.create(state, unAppliedEntries, lastIndex, lastTerm, lastAppliedIndex, lastAppliedTerm, + snapshot = new Legacy(state, unAppliedEntries, lastIndex, lastTerm, lastAppliedIndex, lastAppliedTerm, electionTerm, electionVotedFor, serverConfig); } @@ -180,12 +188,12 @@ public class Snapshot implements Serializable { } @java.io.Serial - private Object writeReplace() { + public final Object writeReplace() { return new SS(this); } @Override - public String toString() { + public final String toString() { return "Snapshot [lastIndex=" + lastIndex + ", lastTerm=" + lastTerm + ", lastAppliedIndex=" + lastAppliedIndex + ", lastAppliedTerm=" + lastAppliedTerm + ", unAppliedEntries size=" + unAppliedEntries.size() + ", state=" + state + ", electionTerm=" + electionTerm + ", electionVotedFor=" diff --git a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/persisted/UpdateElectionTerm.java b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/persisted/UpdateElectionTerm.java index 419aec0e32..99b3b61bad 100644 --- a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/persisted/UpdateElectionTerm.java +++ b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/persisted/UpdateElectionTerm.java @@ -16,13 +16,23 @@ import java.io.Serializable; /** * Message class to persist election term information. */ -public class UpdateElectionTerm implements Serializable { +public sealed class UpdateElectionTerm implements Serializable { + @Deprecated(since = "7.0.0", forRemoval = true) + private static final class Legacy extends UpdateElectionTerm implements LegacySerializable { + @java.io.Serial + private static final long serialVersionUID = 1L; + + Legacy(final long currentTerm, final String votedFor) { + super(currentTerm, votedFor); + } + } + @Deprecated(since = "7.0.0", forRemoval = true) private static final class Proxy implements Externalizable { @java.io.Serial private static final long serialVersionUID = 1L; - private UpdateElectionTerm updateElectionTerm; + private UpdateElectionTerm updateElectionTerm = null; // 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. @@ -31,10 +41,6 @@ public class UpdateElectionTerm implements Serializable { // For Externalizable } - Proxy(final UpdateElectionTerm updateElectionTerm) { - this.updateElectionTerm = updateElectionTerm; - } - @Override public void writeExternal(final ObjectOutput out) throws IOException { out.writeLong(updateElectionTerm.currentTerm); @@ -43,7 +49,7 @@ public class UpdateElectionTerm implements Serializable { @Override public void readExternal(final ObjectInput in) throws IOException, ClassNotFoundException { - updateElectionTerm = new UpdateElectionTerm(in.readLong(), (String) in.readObject()); + updateElectionTerm = new Legacy(in.readLong(), (String) in.readObject()); } @java.io.Serial @@ -63,21 +69,21 @@ public class UpdateElectionTerm implements Serializable { this.votedFor = votedFor; } - public long getCurrentTerm() { + public final long getCurrentTerm() { return currentTerm; } - public String getVotedFor() { + public final String getVotedFor() { return votedFor; } @java.io.Serial - private Object writeReplace() { + public final Object writeReplace() { return new UT(this); } @Override - public String toString() { + public final String toString() { return "UpdateElectionTerm [currentTerm=" + currentTerm + ", votedFor=" + votedFor + "]"; } }