From 2dedb8231e13abe55d6b75eb532d23dbe536e168 Mon Sep 17 00:00:00 2001 From: Robert Varga Date: Sat, 26 Nov 2022 18:35:35 +0100 Subject: [PATCH] Define efficient serialization proxies Superclasses have footprint in serialization protocol, as their descriptors get written out. Capture Externalizable logic into SerialForm, which implements Externalizable -- the protocol to be easily implemented without a superclass. This entails updating the API footprint of AbstractProxy to reuse its methods. Then introduce shorthand proxy classes which behave exactly like their AbstractProxy counterparts, but without the AbstractProxy baggage. This enables reading implied serialization format, if we encounter it, providing forward compatibility with the format. JIRA: CONTROLLER-2056 Change-Id: I4da54ca57849c2bfdaaf76c22e7903abcfa58be9 Signed-off-by: Robert Varga --- .../cluster/datastore/persisted/AT.java | 51 ++++++++ .../AbstractIdentifiablePayload.java | 76 ++++++++++-- .../cluster/datastore/persisted/CH.java | 51 ++++++++ .../cluster/datastore/persisted/CT.java | 62 ++++++++++ .../persisted/CommitTransactionPayload.java | 6 +- .../cluster/datastore/persisted/DH.java | 51 ++++++++ .../cluster/datastore/persisted/DS.java | 44 +++++++ .../cluster/datastore/persisted/DSS.java | 47 ++++++++ .../cluster/datastore/persisted/DT.java | 51 ++++++++ .../persisted/DatastoreSnapshot.java | 111 ++++++++++++------ .../cluster/datastore/persisted/FM.java | 55 +++++++++ .../cluster/datastore/persisted/MS.java | 83 +++++++++++++ .../cluster/datastore/persisted/PH.java | 51 ++++++++ .../cluster/datastore/persisted/PT.java | 51 ++++++++ .../cluster/datastore/persisted/SM.java | 47 ++++++++ .../cluster/datastore/persisted/SS.java | 44 +++++++ .../cluster/datastore/persisted/ST.java | 56 +++++++++ .../persisted/ShardManagerSnapshot.java | 70 ++++++++--- .../persisted/ShardSnapshotState.java | 35 ++++-- .../persisted/SkipTransactionsPayload.java | 2 +- 20 files changed, 973 insertions(+), 71 deletions(-) create mode 100644 opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/persisted/AT.java create mode 100644 opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/persisted/CH.java create mode 100644 opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/persisted/CT.java create mode 100644 opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/persisted/DH.java create mode 100644 opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/persisted/DS.java create mode 100644 opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/persisted/DSS.java create mode 100644 opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/persisted/DT.java create mode 100644 opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/persisted/FM.java create mode 100644 opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/persisted/MS.java create mode 100644 opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/persisted/PH.java create mode 100644 opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/persisted/PT.java create mode 100644 opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/persisted/SM.java create mode 100644 opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/persisted/SS.java create mode 100644 opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/persisted/ST.java diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/persisted/AT.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/persisted/AT.java new file mode 100644 index 0000000000..ddb9dc93e0 --- /dev/null +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/persisted/AT.java @@ -0,0 +1,51 @@ +/* + * 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.datastore.persisted; + +import static com.google.common.base.Verify.verifyNotNull; +import static java.util.Objects.requireNonNull; + +import com.google.common.io.ByteStreams; +import java.io.IOException; +import org.opendaylight.controller.cluster.access.concepts.TransactionIdentifier; +import org.opendaylight.controller.cluster.datastore.persisted.AbstractIdentifiablePayload.SerialForm; + +/** + * Serialization proxy for {@link AbortTransactionPayload}. + */ +final class AT implements SerialForm { + private static final long serialVersionUID = 1L; + + private TransactionIdentifier identifier; + private byte[] bytes; + + @SuppressWarnings("checkstyle:RedundantModifier") + public AT() { + // For Externalizable + } + + AT(final byte[] bytes) { + this.bytes = requireNonNull(bytes); + } + + @Override + public byte[] bytes() { + return bytes; + } + + @Override + public void readExternal(final byte[] newBytes) throws IOException { + bytes = requireNonNull(newBytes); + identifier = verifyNotNull(TransactionIdentifier.readFrom(ByteStreams.newDataInput(newBytes))); + } + + @Override + public Object readResolve() { + return new AbortTransactionPayload(identifier, bytes); + } +} diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/persisted/AbstractIdentifiablePayload.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/persisted/AbstractIdentifiablePayload.java index f07d4dbe90..9bc5a319da 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/persisted/AbstractIdentifiablePayload.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/persisted/AbstractIdentifiablePayload.java @@ -32,7 +32,62 @@ import org.opendaylight.yangtools.concepts.Identifier; */ public abstract class AbstractIdentifiablePayload extends IdentifiablePayload implements Serializable { - protected abstract static class AbstractProxy implements Externalizable { + /** + * An {@link Externalizable} with default implementations we expect our implementations to comply with. On-wire + * serialization format is defined by {@link #bytes()}. + */ + protected interface SerialForm extends Externalizable { + /** + * Return the serial form of this object contents, corresponding to + * {@link AbstractIdentifiablePayload#serialized}. + * + * @return Serialized form + */ + byte[] bytes(); + + /** + * Resolve this proxy to an actual {@link AbstractIdentifiablePayload}. + * + * @return A payload. + */ + Object readResolve(); + + /** + * Restore state from specified serialized form. + * + * @param newBytes Serialized form, as returned by {@link #bytes()} + * @throws IOException when a deserialization problem occurs + */ + void readExternal(byte[] newBytes) throws IOException; + + /** + * {@inheritDoc} + * + *

+ * The default implementation is canonical and should never be overridden. + */ + @Override + default void readExternal(final ObjectInput in) throws IOException { + final var bytes = new byte[in.readInt()]; + in.readFully(bytes); + readExternal(bytes); + } + + /** + * {@inheritDoc} + * + *

+ * The default implementation is canonical and should never be overridden. + */ + @Override + default void writeExternal(final ObjectOutput out) throws IOException { + final var bytes = bytes(); + out.writeInt(bytes.length); + out.write(bytes); + } + } + + protected abstract static class AbstractProxy implements SerialForm { private static final long serialVersionUID = 1L; private byte[] serialized; @@ -47,20 +102,18 @@ public abstract class AbstractIdentifiablePayload extends } @Override - public final void writeExternal(final ObjectOutput out) throws IOException { - out.writeInt(serialized.length); - out.write(serialized); + public final byte[] bytes() { + return serialized; } @Override - public final void readExternal(final ObjectInput in) throws IOException { - final int length = in.readInt(); - serialized = new byte[length]; - in.readFully(serialized); + public final void readExternal(final byte[] bytes) throws IOException { + serialized = requireNonNull(bytes); identifier = verifyNotNull(readIdentifier(ByteStreams.newDataInput(serialized))); } - protected final Object readResolve() { + @Override + public final Object readResolve() { return verifyNotNull(createObject(identifier, serialized)); } @@ -90,6 +143,10 @@ public abstract class AbstractIdentifiablePayload extends return serialized.length; } + protected final byte @NonNull [] serialized() { + return serialized; + } + @Override public final int serializedSize() { // TODO: this is not entirely accurate, as the serialization stream has additional overheads: @@ -109,7 +166,6 @@ public abstract class AbstractIdentifiablePayload extends return verifyNotNull(externalizableProxy(serialized)); } - @SuppressWarnings("checkstyle:hiddenField") protected abstract @NonNull AbstractProxy externalizableProxy(byte @NonNull[] serialized); protected abstract int externalizableProxySize(); diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/persisted/CH.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/persisted/CH.java new file mode 100644 index 0000000000..b4e827b403 --- /dev/null +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/persisted/CH.java @@ -0,0 +1,51 @@ +/* + * 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.datastore.persisted; + +import static com.google.common.base.Verify.verifyNotNull; +import static java.util.Objects.requireNonNull; + +import com.google.common.io.ByteStreams; +import java.io.IOException; +import org.opendaylight.controller.cluster.access.concepts.LocalHistoryIdentifier; +import org.opendaylight.controller.cluster.datastore.persisted.AbstractIdentifiablePayload.SerialForm; + +/** + * Serialization proxy for {@link CreateLocalHistoryPayload}. + */ +final class CH implements SerialForm { + private static final long serialVersionUID = 1L; + + private LocalHistoryIdentifier identifier; + private byte[] bytes; + + @SuppressWarnings("checkstyle:RedundantModifier") + public CH() { + // For Externalizable + } + + CH(final byte[] bytes) { + this.bytes = requireNonNull(bytes); + } + + @Override + public byte[] bytes() { + return bytes; + } + + @Override + public void readExternal(final byte[] newBytes) throws IOException { + bytes = requireNonNull(newBytes); + identifier = verifyNotNull(LocalHistoryIdentifier.readFrom(ByteStreams.newDataInput(newBytes))); + } + + @Override + public Object readResolve() { + return new CreateLocalHistoryPayload(identifier, bytes); + } +} diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/persisted/CT.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/persisted/CT.java new file mode 100644 index 0000000000..98c2562f0b --- /dev/null +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/persisted/CT.java @@ -0,0 +1,62 @@ +/* + * 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.datastore.persisted; + +import static com.google.common.base.Verify.verifyNotNull; +import static java.util.Objects.requireNonNull; + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.io.StreamCorruptedException; +import org.opendaylight.controller.cluster.datastore.persisted.CommitTransactionPayload.Chunked; +import org.opendaylight.controller.cluster.datastore.persisted.CommitTransactionPayload.Simple; +import org.opendaylight.controller.cluster.io.ChunkedByteArray; + +/** + * Serialization proxy for {@link CommitTransactionPayload}. + */ +final class CT implements Externalizable { + private static final long serialVersionUID = 1L; + + private CommitTransactionPayload payload; + + @SuppressWarnings("checkstyle:RedundantModifier") + public CT() { + // For Externalizable + } + + CT(final CommitTransactionPayload payload) { + this.payload = requireNonNull(payload); + } + + @Override + public void writeExternal(final ObjectOutput out) throws IOException { + out.writeInt(payload.size()); + payload.writeBytes(out); + } + + @Override + public void readExternal(final ObjectInput in) throws IOException { + final int length = in.readInt(); + if (length < 0) { + throw new StreamCorruptedException("Invalid payload length " + length); + } else if (length < CommitTransactionPayload.MAX_ARRAY_SIZE) { + final byte[] serialized = new byte[length]; + in.readFully(serialized); + payload = new Simple(serialized); + } else { + payload = new Chunked(ChunkedByteArray.readFrom(in, length, CommitTransactionPayload.MAX_ARRAY_SIZE)); + } + } + + private Object readResolve() { + return verifyNotNull(payload); + } +} diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/persisted/CommitTransactionPayload.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/persisted/CommitTransactionPayload.java index 128d46dc91..cb261a2b19 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/persisted/CommitTransactionPayload.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/persisted/CommitTransactionPayload.java @@ -53,7 +53,7 @@ public abstract sealed class CommitTransactionPayload extends IdentifiablePayloa private static final Logger LOG = LoggerFactory.getLogger(CommitTransactionPayload.class); private static final long serialVersionUID = 1L; - private static final int MAX_ARRAY_SIZE = ceilingPowerOfTwo(Integer.getInteger( + static final int MAX_ARRAY_SIZE = ceilingPowerOfTwo(Integer.getInteger( "org.opendaylight.controller.cluster.datastore.persisted.max-array-size", 256 * 1024)); private volatile Entry candidate = null; @@ -153,7 +153,7 @@ public abstract sealed class CommitTransactionPayload extends IdentifiablePayloa return new Proxy(this); } - private static final class Simple extends CommitTransactionPayload { + static final class Simple extends CommitTransactionPayload { private static final long serialVersionUID = 1L; private final byte[] serialized; @@ -178,7 +178,7 @@ public abstract sealed class CommitTransactionPayload extends IdentifiablePayloa } } - private static final class Chunked extends CommitTransactionPayload { + static final class Chunked extends CommitTransactionPayload { private static final long serialVersionUID = 1L; @SuppressFBWarnings(value = "SE_BAD_FIELD", justification = "Handled via serialization proxy") diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/persisted/DH.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/persisted/DH.java new file mode 100644 index 0000000000..a9c6c63491 --- /dev/null +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/persisted/DH.java @@ -0,0 +1,51 @@ +/* + * 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.datastore.persisted; + +import static com.google.common.base.Verify.verifyNotNull; +import static java.util.Objects.requireNonNull; + +import com.google.common.io.ByteStreams; +import java.io.IOException; +import org.opendaylight.controller.cluster.access.concepts.LocalHistoryIdentifier; +import org.opendaylight.controller.cluster.datastore.persisted.AbstractIdentifiablePayload.SerialForm; + +/** + * Serialization proxy for {@link CloseLocalHistoryPayload}. + */ +final class DH implements SerialForm { + private static final long serialVersionUID = 1L; + + private LocalHistoryIdentifier identifier; + private byte[] bytes; + + @SuppressWarnings("checkstyle:RedundantModifier") + public DH() { + // For Externalizable + } + + DH(final byte[] bytes) { + this.bytes = requireNonNull(bytes); + } + + @Override + public byte[] bytes() { + return bytes; + } + + @Override + public void readExternal(final byte[] newBytes) throws IOException { + bytes = requireNonNull(newBytes); + identifier = verifyNotNull(LocalHistoryIdentifier.readFrom(ByteStreams.newDataInput(newBytes))); + } + + @Override + public Object readResolve() { + return new CloseLocalHistoryPayload(identifier, bytes); + } +} diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/persisted/DS.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/persisted/DS.java new file mode 100644 index 0000000000..5dc365483b --- /dev/null +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/persisted/DS.java @@ -0,0 +1,44 @@ +/* + * 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.datastore.persisted; + +import static com.google.common.base.Verify.verifyNotNull; +import static java.util.Objects.requireNonNull; + +/** + * Serialization proxy for {@link DatastoreSnapshot}. + */ +final class DS implements DatastoreSnapshot.SerialForm { + private static final long serialVersionUID = 1L; + + private DatastoreSnapshot datastoreSnapshot; + + @SuppressWarnings("checkstyle:RedundantModifier") + public DS() { + // For Externalizable + } + + DS(final DatastoreSnapshot datastoreSnapshot) { + this.datastoreSnapshot = requireNonNull(datastoreSnapshot); + } + + @Override + public DatastoreSnapshot datastoreSnapshot() { + return datastoreSnapshot; + } + + @Override + public void resolveTo(final DatastoreSnapshot newDatastoreSnapshot) { + datastoreSnapshot = requireNonNull(newDatastoreSnapshot); + } + + @Override + public Object readResolve() { + return verifyNotNull(datastoreSnapshot); + } +} diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/persisted/DSS.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/persisted/DSS.java new file mode 100644 index 0000000000..074706b1ff --- /dev/null +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/persisted/DSS.java @@ -0,0 +1,47 @@ +/* + * 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.datastore.persisted; + +import static com.google.common.base.Verify.verifyNotNull; +import static java.util.Objects.requireNonNull; + +import org.opendaylight.controller.cluster.datastore.persisted.DatastoreSnapshot.ShardSnapshot; +import org.opendaylight.controller.cluster.raft.persisted.Snapshot; + +/** + * Serialization proxy for {@link ShardDataTreeSnapshot}. + */ +final class DSS implements ShardSnapshot.SerialForm { + private static final long serialVersionUID = 1L; + + private ShardSnapshot shardSnapshot; + + @SuppressWarnings("checkstyle:RedundantModifier") + public DSS() { + // For Externalizable + } + + DSS(final ShardSnapshot shardSnapshot) { + this.shardSnapshot = requireNonNull(shardSnapshot); + } + + @Override + public ShardSnapshot shardSnapshot() { + return shardSnapshot; + } + + @Override + public void resolveTo(final String name, final Snapshot snapshot) { + shardSnapshot = new ShardSnapshot(name, snapshot); + } + + @Override + public Object readResolve() { + return verifyNotNull(shardSnapshot); + } +} diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/persisted/DT.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/persisted/DT.java new file mode 100644 index 0000000000..8a619f64fa --- /dev/null +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/persisted/DT.java @@ -0,0 +1,51 @@ +/* + * 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.datastore.persisted; + +import static com.google.common.base.Verify.verifyNotNull; +import static java.util.Objects.requireNonNull; + +import com.google.common.io.ByteStreams; +import java.io.IOException; +import org.opendaylight.controller.cluster.access.concepts.ClientIdentifier; +import org.opendaylight.controller.cluster.datastore.persisted.AbstractIdentifiablePayload.SerialForm; + +/** + * Serialization proxy for {@link DisableTrackingPayload}. + */ +final class DT implements SerialForm { + private static final long serialVersionUID = 1L; + + private ClientIdentifier identifier; + private byte[] bytes; + + @SuppressWarnings("checkstyle:RedundantModifier") + public DT() { + // For Externalizable + } + + DT(final byte[] bytes) { + this.bytes = requireNonNull(bytes); + } + + @Override + public byte[] bytes() { + return bytes; + } + + @Override + public void readExternal(final byte[] newBytes) throws IOException { + bytes = requireNonNull(newBytes); + identifier = verifyNotNull(ClientIdentifier.readFrom(ByteStreams.newDataInput(newBytes))); + } + + @Override + public Object readResolve() { + return new DisableTrackingPayload(identifier, bytes); + } +} diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/persisted/DatastoreSnapshot.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/persisted/DatastoreSnapshot.java index 9b58eb1723..31e4356bbc 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/persisted/DatastoreSnapshot.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/persisted/DatastoreSnapshot.java @@ -7,6 +7,7 @@ */ package org.opendaylight.controller.cluster.datastore.persisted; +import static com.google.common.base.Verify.verifyNotNull; import static java.util.Objects.requireNonNull; import com.google.common.collect.ImmutableList; @@ -27,24 +28,31 @@ import org.opendaylight.controller.cluster.raft.persisted.Snapshot; * @author Thomas Pantelis */ public final class DatastoreSnapshot implements Serializable { - private static final class Proxy implements Externalizable { - private static final long serialVersionUID = 1L; + interface SerialForm extends Externalizable { - private DatastoreSnapshot datastoreSnapshot; + DatastoreSnapshot datastoreSnapshot(); - // 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() { - // For Externalizable - } + Object readResolve(); - Proxy(final DatastoreSnapshot datastoreSnapshot) { - this.datastoreSnapshot = datastoreSnapshot; + void resolveTo(@NonNull DatastoreSnapshot newDatastoreSnapshot); + + @Override + default void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + final var type = (String)in.readObject(); + final var snapshot = (ShardManagerSnapshot) in.readObject(); + + final int size = in.readInt(); + var localShardSnapshots = new ArrayList(size); + for (int i = 0; i < size; i++) { + localShardSnapshots.add((ShardSnapshot) in.readObject()); + } + + resolveTo(new DatastoreSnapshot(type, snapshot, localShardSnapshots)); } @Override - public void writeExternal(ObjectOutput out) throws IOException { + default void writeExternal(ObjectOutput out) throws IOException { + final var datastoreSnapshot = datastoreSnapshot(); out.writeObject(datastoreSnapshot.type); out.writeObject(datastoreSnapshot.shardManagerSnapshot); @@ -53,31 +61,45 @@ public final class DatastoreSnapshot implements Serializable { out.writeObject(shardSnapshot); } } + } - @Override - public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { - String localType = (String)in.readObject(); - ShardManagerSnapshot localShardManagerSnapshot = (ShardManagerSnapshot) in.readObject(); + private static final class Proxy implements SerialForm { + private static final long serialVersionUID = 1L; - int size = in.readInt(); - List localShardSnapshots = new ArrayList<>(size); - for (int i = 0; i < size; i++) { - localShardSnapshots.add((ShardSnapshot) in.readObject()); - } + private DatastoreSnapshot datastoreSnapshot; + + // 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() { + // For Externalizable + } - datastoreSnapshot = new DatastoreSnapshot(localType, localShardManagerSnapshot, localShardSnapshots); + Proxy(final DatastoreSnapshot datastoreSnapshot) { + this.datastoreSnapshot = requireNonNull(datastoreSnapshot); } - private Object readResolve() { + @Override + public DatastoreSnapshot datastoreSnapshot() { return datastoreSnapshot; } + + @Override + public void resolveTo(DatastoreSnapshot newDatastoreSnapshot) { + datastoreSnapshot = requireNonNull(newDatastoreSnapshot); + } + + @Override + public Object readResolve() { + return verifyNotNull(datastoreSnapshot); + } } private static final long serialVersionUID = 1L; - private final String type; + private final @NonNull String type; private final ShardManagerSnapshot shardManagerSnapshot; - private final List shardSnapshots; + private final @NonNull ImmutableList shardSnapshots; public DatastoreSnapshot(@NonNull String type, @Nullable ShardManagerSnapshot shardManagerSnapshot, @NonNull List shardSnapshots) { @@ -103,9 +125,28 @@ public final class DatastoreSnapshot implements Serializable { } public static final class ShardSnapshot implements Serializable { - private static final long serialVersionUID = 1L; + interface SerialForm extends Externalizable { + + ShardSnapshot shardSnapshot(); + + Object readResolve(); - private static final class Proxy implements Externalizable { + void resolveTo(String name, Snapshot snapshot); + + @Override + default void writeExternal(ObjectOutput out) throws IOException { + final var shardSnapshot = shardSnapshot(); + out.writeObject(shardSnapshot.name); + out.writeObject(shardSnapshot.snapshot); + } + + @Override + default void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + resolveTo((String) in.readObject(), (Snapshot) in.readObject()); + } + } + + private static final class Proxy implements SerialForm { private static final long serialVersionUID = 1L; private ShardSnapshot shardSnapshot; @@ -122,21 +163,23 @@ public final class DatastoreSnapshot implements Serializable { } @Override - public void writeExternal(ObjectOutput out) throws IOException { - out.writeObject(shardSnapshot.name); - out.writeObject(shardSnapshot.snapshot); + public ShardSnapshot shardSnapshot() { + return shardSnapshot; } @Override - public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { - shardSnapshot = new ShardSnapshot((String)in.readObject(), (Snapshot) in.readObject()); + public void resolveTo(final String name, final Snapshot snapshot) { + shardSnapshot = new ShardSnapshot(name, snapshot); } - private Object readResolve() { - return shardSnapshot; + @Override + public Object readResolve() { + return verifyNotNull(shardSnapshot); } } + private static final long serialVersionUID = 1L; + private final @NonNull String name; private final @NonNull Snapshot snapshot; diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/persisted/FM.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/persisted/FM.java new file mode 100644 index 0000000000..5a432cc8ad --- /dev/null +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/persisted/FM.java @@ -0,0 +1,55 @@ +/* + * 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.datastore.persisted; + +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.List; + +/** + * Externalizable proxy for {@link FrontendShardDataTreeSnapshotMetadata}. + */ +final class FM implements Externalizable { + private static final long serialVersionUID = 1L; + + private List clients; + + @SuppressWarnings("checkstyle:RedundantModifier") + public FM() { + // For Externalizable + } + + FM(final FrontendShardDataTreeSnapshotMetadata metadata) { + clients = metadata.getClients(); + } + + @Override + public void writeExternal(final ObjectOutput out) throws IOException { + out.writeInt(clients.size()); + for (var c : clients) { + c.writeTo(out); + } + } + + @Override + public void readExternal(final ObjectInput in) throws IOException { + final int size = in.readInt(); + final var builder = ImmutableList.builderWithExpectedSize(size); + for (int i = 0; i < size ; ++i) { + builder.add(FrontendClientMetadata.readFrom(in)); + } + clients = builder.build(); + } + + private Object readResolve() { + return new FrontendShardDataTreeSnapshotMetadata(clients); + } +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/persisted/MS.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/persisted/MS.java new file mode 100644 index 0000000000..7246e503db --- /dev/null +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/persisted/MS.java @@ -0,0 +1,83 @@ +/* + * 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.datastore.persisted; + +import static com.google.common.base.Preconditions.checkArgument; + +import com.google.common.collect.ImmutableMap; +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.Map; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; +import org.opendaylight.yangtools.yang.data.codec.binfmt.NormalizedNodeDataInput; +import org.opendaylight.yangtools.yang.data.codec.binfmt.NormalizedNodeStreamVersion; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Externalizable proxy for {@link MetadataShardDataTreeSnapshot}. + */ +final class MS implements Externalizable { + private static final Logger LOG = LoggerFactory.getLogger(MS.class); + private static final long serialVersionUID = 1L; + + private Map>, ShardDataTreeSnapshotMetadata> metadata; + private NormalizedNodeStreamVersion version; + private NormalizedNode rootNode; + + @SuppressWarnings("checkstyle:RedundantModifier") + public MS() { + // For Externalizable + } + + MS(final MetadataShardDataTreeSnapshot snapshot) { + rootNode = snapshot.getRootNode().orElseThrow(); + metadata = snapshot.getMetadata(); + version = snapshot.version().getStreamVersion(); + } + + @Override + public void writeExternal(final ObjectOutput out) throws IOException { + out.writeInt(metadata.size()); + for (var m : metadata.values()) { + out.writeObject(m); + } + try (var stream = version.newDataOutput(out)) { + stream.writeNormalizedNode(rootNode); + } + } + + @Override + public void readExternal(final ObjectInput in) throws IOException, ClassNotFoundException { + final int metaSize = in.readInt(); + checkArgument(metaSize >= 0, "Invalid negative metadata map length %s", metaSize); + + // Default pre-allocate is 4, which should be fine + final var metaBuilder = ImmutableMap + .>, ShardDataTreeSnapshotMetadata>builder(); + for (int i = 0; i < metaSize; ++i) { + final var m = (ShardDataTreeSnapshotMetadata) in.readObject(); + if (m != null) { + metaBuilder.put(m.getType(), m); + } else { + LOG.warn("Skipping null metadata"); + } + } + metadata = metaBuilder.build(); + + final var stream = NormalizedNodeDataInput.newDataInput(in); + version = stream.getVersion(); + rootNode = stream.readNormalizedNode(); + } + + private Object readResolve() { + return new MetadataShardDataTreeSnapshot(rootNode, metadata); + } +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/persisted/PH.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/persisted/PH.java new file mode 100644 index 0000000000..028d1508da --- /dev/null +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/persisted/PH.java @@ -0,0 +1,51 @@ +/* + * 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.datastore.persisted; + +import static com.google.common.base.Verify.verifyNotNull; +import static java.util.Objects.requireNonNull; + +import com.google.common.io.ByteStreams; +import java.io.IOException; +import org.opendaylight.controller.cluster.access.concepts.LocalHistoryIdentifier; +import org.opendaylight.controller.cluster.datastore.persisted.AbstractIdentifiablePayload.SerialForm; + +/** + * Serialization proxy for {@link PurgeLocalHistoryPayload}. + */ +final class PH implements SerialForm { + private static final long serialVersionUID = 1L; + + private LocalHistoryIdentifier identifier; + private byte[] bytes; + + @SuppressWarnings("checkstyle:RedundantModifier") + public PH() { + // For Externalizable + } + + PH(final byte[] bytes) { + this.bytes = requireNonNull(bytes); + } + + @Override + public byte[] bytes() { + return bytes; + } + + @Override + public void readExternal(final byte[] newBytes) throws IOException { + bytes = requireNonNull(newBytes); + identifier = verifyNotNull(LocalHistoryIdentifier.readFrom(ByteStreams.newDataInput(newBytes))); + } + + @Override + public Object readResolve() { + return new PurgeLocalHistoryPayload(identifier, bytes); + } +} diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/persisted/PT.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/persisted/PT.java new file mode 100644 index 0000000000..23bd12b1fa --- /dev/null +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/persisted/PT.java @@ -0,0 +1,51 @@ +/* + * 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.datastore.persisted; + +import static com.google.common.base.Verify.verifyNotNull; +import static java.util.Objects.requireNonNull; + +import com.google.common.io.ByteStreams; +import java.io.IOException; +import org.opendaylight.controller.cluster.access.concepts.TransactionIdentifier; +import org.opendaylight.controller.cluster.datastore.persisted.AbstractIdentifiablePayload.SerialForm; + +/** + * Serialization proxy for {@link PurgeTransactionPayload}. + */ +final class PT implements SerialForm { + private static final long serialVersionUID = 1L; + + private TransactionIdentifier identifier; + private byte[] bytes; + + @SuppressWarnings("checkstyle:RedundantModifier") + public PT() { + // For Externalizable + } + + PT(final byte[] bytes) { + this.bytes = requireNonNull(bytes); + } + + @Override + public byte[] bytes() { + return bytes; + } + + @Override + public void readExternal(final byte[] newBytes) throws IOException { + bytes = requireNonNull(newBytes); + identifier = verifyNotNull(TransactionIdentifier.readFrom(ByteStreams.newDataInput(newBytes))); + } + + @Override + public Object readResolve() { + return new PurgeTransactionPayload(identifier, bytes); + } +} diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/persisted/SM.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/persisted/SM.java new file mode 100644 index 0000000000..1e2cdc8da1 --- /dev/null +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/persisted/SM.java @@ -0,0 +1,47 @@ +/* + * 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.datastore.persisted; + +import static com.google.common.base.Verify.verifyNotNull; +import static java.util.Objects.requireNonNull; + +import java.util.List; + +/** + * Serialization proxy for {@link ShardManagerSnapshot}. + */ +final class SM implements ShardManagerSnapshot.SerializedForm { + private static final long serialVersionUID = 1L; + + private ShardManagerSnapshot snapshot; + + @SuppressWarnings("checkstyle:RedundantModifier") + public SM() { + // For Externalizable + } + + SM(final ShardManagerSnapshot snapshot) { + this.snapshot = requireNonNull(snapshot); + } + + @Override + public List shardNames() { + return snapshot.getShardList(); + } + + @Override + public void resolveTo(final ShardManagerSnapshot newSnapshot) { + snapshot = requireNonNull(newSnapshot); + } + + @Override + public Object readResolve() { + return verifyNotNull(snapshot); + } + +} diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/persisted/SS.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/persisted/SS.java new file mode 100644 index 0000000000..13a8ac64fb --- /dev/null +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/persisted/SS.java @@ -0,0 +1,44 @@ +/* + * 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.datastore.persisted; + +import static com.google.common.base.Verify.verifyNotNull; +import static java.util.Objects.requireNonNull; + +/** + * Serialization proxy for {@link ShardSnapshotState}. + */ +final class SS implements ShardSnapshotState.SerialForm { + private static final long serialVersionUID = 1L; + + private ShardSnapshotState snapshotState; + + @SuppressWarnings("checkstyle:RedundantModifier") + public SS() { + // For Externalizable + } + + SS(final ShardSnapshotState snapshotState) { + this.snapshotState = requireNonNull(snapshotState); + } + + @Override + public ShardSnapshotState snapshotState() { + return snapshotState; + } + + @Override + public void resolveTo(final ShardSnapshotState newSnapshotState) { + snapshotState = requireNonNull(newSnapshotState); + } + + @Override + public Object readResolve() { + return verifyNotNull(snapshotState); + } +} diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/persisted/ST.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/persisted/ST.java new file mode 100644 index 0000000000..756a20bcd2 --- /dev/null +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/persisted/ST.java @@ -0,0 +1,56 @@ +/* + * 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.datastore.persisted; + +import static com.google.common.base.Verify.verifyNotNull; +import static java.util.Objects.requireNonNull; + +import com.google.common.io.ByteStreams; +import java.io.IOException; +import org.opendaylight.controller.cluster.access.concepts.LocalHistoryIdentifier; +import org.opendaylight.controller.cluster.datastore.persisted.AbstractIdentifiablePayload.SerialForm; +import org.opendaylight.controller.cluster.datastore.utils.ImmutableUnsignedLongSet; + +/** + * Serialization proxy for {@link SkipTransactionsPayload}. + */ +final class ST implements SerialForm { + private static final long serialVersionUID = 1L; + + private ImmutableUnsignedLongSet transactionIds; + private LocalHistoryIdentifier identifier; + private byte[] bytes; + + @SuppressWarnings("checkstyle:RedundantModifier") + public ST() { + // For Externalizable + } + + ST(final byte[] bytes) { + this.bytes = requireNonNull(bytes); + } + + @Override + public byte[] bytes() { + return bytes; + } + + @Override + public void readExternal(final byte[] newBytes) throws IOException { + bytes = requireNonNull(newBytes); + + final var in = ByteStreams.newDataInput(newBytes); + identifier = LocalHistoryIdentifier.readFrom(in); + transactionIds = verifyNotNull(ImmutableUnsignedLongSet.readFrom(in)); + } + + @Override + public Object readResolve() { + return new SkipTransactionsPayload(identifier, bytes, transactionIds); + } +} diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/persisted/ShardManagerSnapshot.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/persisted/ShardManagerSnapshot.java index 03ffa9af79..2e0320bbcd 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/persisted/ShardManagerSnapshot.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/persisted/ShardManagerSnapshot.java @@ -7,6 +7,9 @@ */ package org.opendaylight.controller.cluster.datastore.persisted; +import static com.google.common.base.Verify.verifyNotNull; +import static java.util.Objects.requireNonNull; + import com.google.common.collect.ImmutableList; import java.io.Externalizable; import java.io.IOException; @@ -23,7 +26,50 @@ import org.eclipse.jdt.annotation.NonNull; * @author Thomas Pantelis */ public final class ShardManagerSnapshot implements Serializable { - private static final class Proxy implements Externalizable { + interface SerializedForm extends Externalizable { + /** + * Return the serial form of this object contents, corresponding to {@link ShardManagerSnapshot#shardList}. + * + * @return List of shards names. + */ + List shardNames(); + + /** + * Resolve this proxy to an actual {@link ShardManagerSnapshot}. Implementations can rely on the object to be + * set via {@link #resolveTo(ShardManagerSnapshot)}. + * + * @return A snapshot + */ + Object readResolve(); + + /** + * Set this proxy to return {@code snapshot} on next {@link #readResolve()}. + * + * @param newSnapshot Snapshot to set + */ + void resolveTo(@NonNull ShardManagerSnapshot newSnapshot); + + @Override + default void readExternal(final ObjectInput in) throws IOException, ClassNotFoundException { + final int size = in.readInt(); + final var shardList = new ArrayList(size); + for (int i = 0; i < size; i++) { + shardList.add((String) in.readObject()); + } + resolveTo(new ShardManagerSnapshot(shardList)); + } + + @Override + default void writeExternal(final ObjectOutput out) throws IOException { + final var shardList = shardNames(); + out.writeInt(shardList.size()); + for (var shardName : shardList) { + out.writeObject(shardName); + } + } + } + + private static final class Proxy implements SerializedForm { private static final long serialVersionUID = 1L; private ShardManagerSnapshot snapshot; @@ -40,26 +86,18 @@ public final class ShardManagerSnapshot implements Serializable { } @Override - public void writeExternal(final ObjectOutput out) throws IOException { - out.writeInt(snapshot.shardList.size()); - for (String shard: snapshot.shardList) { - out.writeObject(shard); - } + public List shardNames() { + return snapshot.getShardList(); } @Override - public void readExternal(final ObjectInput in) throws IOException, ClassNotFoundException { - int size = in.readInt(); - List localShardList = new ArrayList<>(size); - for (int i = 0; i < size; i++) { - localShardList.add((String) in.readObject()); - } - - snapshot = new ShardManagerSnapshot(localShardList); + public void resolveTo(final ShardManagerSnapshot newSnapshot) { + snapshot = requireNonNull(newSnapshot); } - private Object readResolve() { - return snapshot; + @Override + public Object readResolve() { + return verifyNotNull(snapshot); } } diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/persisted/ShardSnapshotState.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/persisted/ShardSnapshotState.java index 061749db81..3f0b748676 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/persisted/ShardSnapshotState.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/persisted/ShardSnapshotState.java @@ -7,6 +7,7 @@ */ package org.opendaylight.controller.cluster.datastore.persisted; +import static com.google.common.base.Verify.verifyNotNull; import static java.util.Objects.requireNonNull; import com.google.common.annotations.VisibleForTesting; @@ -24,7 +25,26 @@ import org.opendaylight.controller.cluster.raft.persisted.Snapshot; * @author Thomas Pantelis */ public final class ShardSnapshotState implements Snapshot.State { - private static final class Proxy implements Externalizable { + interface SerialForm extends Externalizable { + + ShardSnapshotState snapshotState(); + + void resolveTo(@NonNull ShardSnapshotState newSnapshotState); + + Object readResolve(); + + @Override + default void readExternal(final ObjectInput in) throws IOException { + resolveTo(ShardDataTreeSnapshot.deserialize(in)); + } + + @Override + default void writeExternal(final ObjectOutput out) throws IOException { + snapshotState().getSnapshot().serialize(out); + } + } + + private static final class Proxy implements SerialForm { private static final long serialVersionUID = 1L; private ShardSnapshotState snapshotState; @@ -41,17 +61,18 @@ public final class ShardSnapshotState implements Snapshot.State { } @Override - public void writeExternal(final ObjectOutput out) throws IOException { - snapshotState.snapshot.serialize(out); + public ShardSnapshotState snapshotState() { + return snapshotState; } @Override - public void readExternal(final ObjectInput in) throws IOException { - snapshotState = ShardDataTreeSnapshot.deserialize(in); + public void resolveTo(final ShardSnapshotState newSnapshotState) { + snapshotState = requireNonNull(newSnapshotState); } - private Object readResolve() { - return snapshotState; + @Override + public Object readResolve() { + return verifyNotNull(snapshotState); } } diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/persisted/SkipTransactionsPayload.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/persisted/SkipTransactionsPayload.java index 5b8ba73942..a3f7af99f0 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/persisted/SkipTransactionsPayload.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/persisted/SkipTransactionsPayload.java @@ -63,7 +63,7 @@ public final class SkipTransactionsPayload extends AbstractIdentifiablePayload