2 * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
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
8 package org.opendaylight.controller.cluster.raft;
10 import com.google.protobuf.ByteString;
12 import java.util.ArrayList;
13 import java.util.List;
16 * Abstract class handling the mapping of
17 * logical LogEntry Index and the physical list index.
19 public abstract class AbstractReplicatedLogImpl implements ReplicatedLog {
21 protected List<ReplicatedLogEntry> journal;
22 protected ByteString snapshot;
23 protected long snapshotIndex = -1;
24 protected long snapshotTerm = -1;
26 // to be used for rollback during save snapshot failure
27 protected List<ReplicatedLogEntry> snapshottedJournal;
28 protected ByteString previousSnapshot;
29 protected long previousSnapshotIndex = -1;
30 protected long previousSnapshotTerm = -1;
32 public AbstractReplicatedLogImpl(ByteString state, long snapshotIndex,
33 long snapshotTerm, List<ReplicatedLogEntry> unAppliedEntries) {
34 this.snapshot = state;
35 this.snapshotIndex = snapshotIndex;
36 this.snapshotTerm = snapshotTerm;
37 this.journal = new ArrayList<>(unAppliedEntries);
41 public AbstractReplicatedLogImpl() {
43 this.journal = new ArrayList<>();
46 protected int adjustedIndex(long logEntryIndex) {
47 if(snapshotIndex < 0){
48 return (int) logEntryIndex;
50 return (int) (logEntryIndex - (snapshotIndex + 1));
54 public ReplicatedLogEntry get(long logEntryIndex) {
55 int adjustedIndex = adjustedIndex(logEntryIndex);
57 if (adjustedIndex < 0 || adjustedIndex >= journal.size()) {
58 // physical index should be less than list size and >= 0
62 return journal.get(adjustedIndex);
66 public ReplicatedLogEntry last() {
67 if (journal.isEmpty()) {
70 // get the last entry directly from the physical index
71 return journal.get(journal.size() - 1);
75 public long lastIndex() {
76 if (journal.isEmpty()) {
77 // it can happen that after snapshot, all the entries of the
78 // journal are trimmed till lastApplied, so lastIndex = snapshotIndex
81 return last().getIndex();
85 public long lastTerm() {
86 if (journal.isEmpty()) {
87 // it can happen that after snapshot, all the entries of the
88 // journal are trimmed till lastApplied, so lastTerm = snapshotTerm
91 return last().getTerm();
95 public void removeFrom(long logEntryIndex) {
96 int adjustedIndex = adjustedIndex(logEntryIndex);
97 if (adjustedIndex < 0 || adjustedIndex >= journal.size()) {
98 // physical index should be less than list size and >= 0
101 journal.subList(adjustedIndex , journal.size()).clear();
105 public void append(ReplicatedLogEntry replicatedLogEntry) {
106 journal.add(replicatedLogEntry);
110 public List<ReplicatedLogEntry> getFrom(long logEntryIndex) {
111 return getFrom(logEntryIndex, journal.size());
115 public List<ReplicatedLogEntry> getFrom(long logEntryIndex, int max) {
116 int adjustedIndex = adjustedIndex(logEntryIndex);
117 int size = journal.size();
118 List<ReplicatedLogEntry> entries = new ArrayList<>(100);
119 if (adjustedIndex >= 0 && adjustedIndex < size) {
120 // physical index should be less than list size and >= 0
121 int maxIndex = adjustedIndex + max;
125 entries.addAll(journal.subList(adjustedIndex, maxIndex));
133 return journal.size();
137 public boolean isPresent(long logEntryIndex) {
138 if (logEntryIndex > lastIndex()) {
139 // if the request logical index is less than the last present in the list
142 int adjustedIndex = adjustedIndex(logEntryIndex);
143 return (adjustedIndex >= 0);
147 public boolean isInSnapshot(long logEntryIndex) {
148 return logEntryIndex <= snapshotIndex && snapshotIndex != -1;
152 public ByteString getSnapshot() {
157 public long getSnapshotIndex() {
158 return snapshotIndex;
162 public long getSnapshotTerm() {
167 public abstract void appendAndPersist(ReplicatedLogEntry replicatedLogEntry);
170 public abstract void removeFromAndPersist(long index);
173 public void setSnapshotIndex(long snapshotIndex) {
174 this.snapshotIndex = snapshotIndex;
178 public void setSnapshotTerm(long snapshotTerm) {
179 this.snapshotTerm = snapshotTerm;
183 public void setSnapshot(ByteString snapshot) {
184 this.snapshot = snapshot;
188 public void clear(int startIndex, int endIndex) {
189 journal.subList(startIndex, endIndex).clear();
193 public void snapshotPreCommit(ByteString snapshot, long snapshotCapturedIndex, long snapshotCapturedTerm) {
194 snapshottedJournal = new ArrayList<>(journal.size());
196 snapshottedJournal.addAll(journal.subList(0, (int)(snapshotCapturedIndex - snapshotIndex)));
197 clear(0, (int) (snapshotCapturedIndex - snapshotIndex));
199 previousSnapshotIndex = snapshotIndex;
200 setSnapshotIndex(snapshotCapturedIndex);
202 previousSnapshotTerm = snapshotTerm;
203 setSnapshotTerm(snapshotCapturedTerm);
205 previousSnapshot = getSnapshot();
206 setSnapshot(snapshot);
210 public void snapshotCommit() {
211 snapshottedJournal.clear();
212 snapshottedJournal = null;
213 previousSnapshotIndex = -1;
214 previousSnapshotTerm = -1;
215 previousSnapshot = null;
219 public void snapshotRollback() {
220 snapshottedJournal.addAll(journal);
222 journal = snapshottedJournal;
223 snapshottedJournal = null;
225 snapshotIndex = previousSnapshotIndex;
226 previousSnapshotIndex = -1;
228 snapshotTerm = previousSnapshotTerm;
229 previousSnapshotTerm = -1;
231 snapshot = previousSnapshot;
232 previousSnapshot = null;