Trigger snapshots on legacy persisted entries
[controller.git] / opendaylight / md-sal / sal-akka-raft / src / main / java / org / opendaylight / controller / cluster / raft / persisted / Snapshot.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.persisted;
9
10 import java.io.Externalizable;
11 import java.io.IOException;
12 import java.io.ObjectInput;
13 import java.io.ObjectOutput;
14 import java.io.Serializable;
15 import java.util.ArrayList;
16 import java.util.List;
17 import org.opendaylight.controller.cluster.raft.ReplicatedLogEntry;
18 import org.opendaylight.controller.cluster.raft.messages.Payload;
19
20 /**
21  * Represents a snapshot of the raft data.
22  *
23  * @author Thomas Pantelis
24  */
25 // Not final and non-sealed for mocking
26 public class Snapshot implements Serializable {
27     /**
28      * Implementations of this interface are used as the state payload for a snapshot.
29      *
30      * @author Thomas Pantelis
31      */
32     public interface State extends Serializable {
33         /**
34          * Indicate whether the snapshot requires migration, i.e. a new snapshot should be created after recovery.
35          * Default implementation returns false, i.e. do not re-snapshot.
36          *
37          * @return True if complete recovery based upon this snapshot should trigger a new snapshot.
38          */
39         default boolean needsMigration() {
40             return false;
41         }
42     }
43
44     @Deprecated(since = "7.0.0", forRemoval = true)
45     private static final class Legacy extends Snapshot implements LegacySerializable {
46         @java.io.Serial
47         private static final long serialVersionUID = 1L;
48
49         Legacy(final State state, final List<ReplicatedLogEntry> unAppliedEntries, final long lastIndex,
50                 final long lastTerm, final long lastAppliedIndex, final long lastAppliedTerm, final long electionTerm,
51                 final String electionVotedFor, final ServerConfigurationPayload serverConfig) {
52             super(state, unAppliedEntries, lastIndex, lastTerm, lastAppliedIndex, lastAppliedTerm, electionTerm,
53                 electionVotedFor, serverConfig);
54         }
55     }
56
57     @Deprecated(since = "7.0.0", forRemoval = true)
58     private static final class Proxy implements Externalizable {
59         @java.io.Serial
60         private static final long serialVersionUID = 1L;
61
62         private Snapshot snapshot = null;
63
64         // checkstyle flags the public modifier as redundant which really doesn't make sense since it clearly isn't
65         // redundant. It is explicitly needed for Java serialization to be able to create instances via reflection.
66         @SuppressWarnings("checkstyle:RedundantModifier")
67         public Proxy() {
68             // For Externalizable
69         }
70
71         @Override
72         public void writeExternal(final ObjectOutput out) throws IOException {
73             out.writeLong(snapshot.lastIndex);
74             out.writeLong(snapshot.lastTerm);
75             out.writeLong(snapshot.lastAppliedIndex);
76             out.writeLong(snapshot.lastAppliedTerm);
77             out.writeLong(snapshot.electionTerm);
78             out.writeObject(snapshot.electionVotedFor);
79             out.writeObject(snapshot.serverConfig);
80
81             out.writeInt(snapshot.unAppliedEntries.size());
82             for (ReplicatedLogEntry e: snapshot.unAppliedEntries) {
83                 out.writeLong(e.getIndex());
84                 out.writeLong(e.getTerm());
85                 out.writeObject(e.getData());
86             }
87
88             out.writeObject(snapshot.state);
89         }
90
91         @Override
92         public void readExternal(final ObjectInput in) throws IOException, ClassNotFoundException {
93             long lastIndex = in.readLong();
94             long lastTerm = in.readLong();
95             long lastAppliedIndex = in.readLong();
96             long lastAppliedTerm = in.readLong();
97             long electionTerm = in.readLong();
98             String electionVotedFor = (String) in.readObject();
99             ServerConfigurationPayload serverConfig = (ServerConfigurationPayload) in.readObject();
100
101             int size = in.readInt();
102             var unAppliedEntries = new ArrayList<ReplicatedLogEntry>(size);
103             for (int i = 0; i < size; i++) {
104                 unAppliedEntries.add(new SimpleReplicatedLogEntry(in.readLong(), in.readLong(),
105                         (Payload) in.readObject()));
106             }
107
108             State state = (State) in.readObject();
109
110             snapshot = new Legacy(state, unAppliedEntries, lastIndex, lastTerm, lastAppliedIndex, lastAppliedTerm,
111                     electionTerm, electionVotedFor, serverConfig);
112         }
113
114         @java.io.Serial
115         private Object readResolve() {
116             return snapshot;
117         }
118     }
119
120     @java.io.Serial
121     private static final long serialVersionUID = 1L;
122
123     private final State state;
124     private final List<ReplicatedLogEntry> unAppliedEntries;
125     private final long lastIndex;
126     private final long lastTerm;
127     private final long lastAppliedIndex;
128     private final long lastAppliedTerm;
129     private final long electionTerm;
130     private final String electionVotedFor;
131     private final ServerConfigurationPayload serverConfig;
132
133     Snapshot(final State state, final List<ReplicatedLogEntry> unAppliedEntries, final long lastIndex,
134             final long lastTerm, final long lastAppliedIndex, final long lastAppliedTerm, final long electionTerm,
135             final String electionVotedFor, final ServerConfigurationPayload serverConfig) {
136         this.state = state;
137         this.unAppliedEntries = unAppliedEntries;
138         this.lastIndex = lastIndex;
139         this.lastTerm = lastTerm;
140         this.lastAppliedIndex = lastAppliedIndex;
141         this.lastAppliedTerm = lastAppliedTerm;
142         this.electionTerm = electionTerm;
143         this.electionVotedFor = electionVotedFor;
144         this.serverConfig = serverConfig;
145     }
146
147     public static Snapshot create(final State state, final List<ReplicatedLogEntry> entries, final long lastIndex,
148             final long lastTerm, final long lastAppliedIndex, final long lastAppliedTerm, final long electionTerm,
149             final String electionVotedFor, final ServerConfigurationPayload serverConfig) {
150         return new Snapshot(state, entries, lastIndex, lastTerm, lastAppliedIndex, lastAppliedTerm,
151                 electionTerm, electionVotedFor, serverConfig);
152     }
153
154     public State getState() {
155         return state;
156     }
157
158     public List<ReplicatedLogEntry> getUnAppliedEntries() {
159         return unAppliedEntries;
160     }
161
162     public long getLastTerm() {
163         return lastTerm;
164     }
165
166     public long getLastAppliedIndex() {
167         return lastAppliedIndex;
168     }
169
170     public long getLastAppliedTerm() {
171         return lastAppliedTerm;
172     }
173
174     public long getLastIndex() {
175         return lastIndex;
176     }
177
178     public long getElectionTerm() {
179         return electionTerm;
180     }
181
182     public String getElectionVotedFor() {
183         return electionVotedFor;
184     }
185
186     public ServerConfigurationPayload getServerConfiguration() {
187         return serverConfig;
188     }
189
190     @java.io.Serial
191     public final Object writeReplace() {
192         return new SS(this);
193     }
194
195     @Override
196     public final String toString() {
197         return "Snapshot [lastIndex=" + lastIndex + ", lastTerm=" + lastTerm + ", lastAppliedIndex=" + lastAppliedIndex
198                 + ", lastAppliedTerm=" + lastAppliedTerm + ", unAppliedEntries size=" + unAppliedEntries.size()
199                 + ", state=" + state + ", electionTerm=" + electionTerm + ", electionVotedFor="
200                 + electionVotedFor + ", ServerConfigPayload="  + serverConfig + "]";
201     }
202 }