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 java.util.ArrayList;
11 import java.util.Collections;
12 import java.util.List;
15 * Abstract class handling the mapping of
16 * logical LogEntry Index and the physical list index.
18 public abstract class AbstractReplicatedLogImpl implements ReplicatedLog {
20 // We define this as ArrayList so we can use ensureCapacity.
21 protected ArrayList<ReplicatedLogEntry> journal;
23 private long snapshotIndex = -1;
24 private long snapshotTerm = -1;
26 // to be used for rollback during save snapshot failure
27 private ArrayList<ReplicatedLogEntry> snapshottedJournal;
28 private long previousSnapshotIndex = -1;
29 private long previousSnapshotTerm = -1;
30 protected int dataSize = 0;
32 public AbstractReplicatedLogImpl(long snapshotIndex,
33 long snapshotTerm, List<ReplicatedLogEntry> unAppliedEntries) {
34 this.snapshotIndex = snapshotIndex;
35 this.snapshotTerm = snapshotTerm;
36 this.journal = new ArrayList<>(unAppliedEntries);
39 public AbstractReplicatedLogImpl() {
40 this(-1L, -1L, Collections.<ReplicatedLogEntry>emptyList());
43 protected int adjustedIndex(long logEntryIndex) {
44 if (snapshotIndex < 0) {
45 return (int) logEntryIndex;
47 return (int) (logEntryIndex - (snapshotIndex + 1));
51 public ReplicatedLogEntry get(long logEntryIndex) {
52 int adjustedIndex = adjustedIndex(logEntryIndex);
54 if (adjustedIndex < 0 || adjustedIndex >= journal.size()) {
55 // physical index should be less than list size and >= 0
59 return journal.get(adjustedIndex);
63 public ReplicatedLogEntry last() {
64 if (journal.isEmpty()) {
67 // get the last entry directly from the physical index
68 return journal.get(journal.size() - 1);
72 public long lastIndex() {
73 if (journal.isEmpty()) {
74 // it can happen that after snapshot, all the entries of the
75 // journal are trimmed till lastApplied, so lastIndex = snapshotIndex
78 return last().getIndex();
82 public long lastTerm() {
83 if (journal.isEmpty()) {
84 // it can happen that after snapshot, all the entries of the
85 // journal are trimmed till lastApplied, so lastTerm = snapshotTerm
88 return last().getTerm();
92 public void removeFrom(long logEntryIndex) {
93 int adjustedIndex = adjustedIndex(logEntryIndex);
94 if (adjustedIndex < 0 || adjustedIndex >= journal.size()) {
95 // physical index should be less than list size and >= 0
98 journal.subList(adjustedIndex , journal.size()).clear();
102 public void append(ReplicatedLogEntry replicatedLogEntry) {
103 journal.add(replicatedLogEntry);
107 public void increaseJournalLogCapacity(int amount) {
108 journal.ensureCapacity(journal.size() + amount);
112 public List<ReplicatedLogEntry> getFrom(long logEntryIndex) {
113 return getFrom(logEntryIndex, journal.size());
117 public List<ReplicatedLogEntry> getFrom(long logEntryIndex, int max) {
118 int adjustedIndex = adjustedIndex(logEntryIndex);
119 int size = journal.size();
120 if (adjustedIndex >= 0 && adjustedIndex < size) {
121 // physical index should be less than list size and >= 0
122 int maxIndex = adjustedIndex + max;
126 return new ArrayList<>(journal.subList(adjustedIndex, maxIndex));
128 return Collections.emptyList();
134 return journal.size();
138 public int dataSize() {
143 public boolean isPresent(long logEntryIndex) {
144 if (logEntryIndex > lastIndex()) {
145 // if the request logical index is less than the last present in the list
148 int adjustedIndex = adjustedIndex(logEntryIndex);
149 return (adjustedIndex >= 0);
153 public boolean isInSnapshot(long logEntryIndex) {
154 return logEntryIndex <= snapshotIndex && snapshotIndex != -1;
158 public long getSnapshotIndex() {
159 return snapshotIndex;
163 public long getSnapshotTerm() {
168 public abstract void appendAndPersist(ReplicatedLogEntry replicatedLogEntry);
171 public abstract void removeFromAndPersist(long index);
174 public void setSnapshotIndex(long snapshotIndex) {
175 this.snapshotIndex = snapshotIndex;
179 public void setSnapshotTerm(long snapshotTerm) {
180 this.snapshotTerm = snapshotTerm;
184 public void clear(int startIndex, int endIndex) {
185 journal.subList(startIndex, endIndex).clear();
189 public void snapshotPreCommit(long snapshotCapturedIndex, long snapshotCapturedTerm) {
190 snapshottedJournal = new ArrayList<>(journal.size());
192 snapshottedJournal.addAll(journal.subList(0, (int)(snapshotCapturedIndex - snapshotIndex)));
193 clear(0, (int) (snapshotCapturedIndex - snapshotIndex));
195 previousSnapshotIndex = snapshotIndex;
196 setSnapshotIndex(snapshotCapturedIndex);
198 previousSnapshotTerm = snapshotTerm;
199 setSnapshotTerm(snapshotCapturedTerm);
203 public void snapshotCommit() {
204 snapshottedJournal = null;
205 previousSnapshotIndex = -1;
206 previousSnapshotTerm = -1;
208 // need to recalc the datasize based on the entries left after precommit.
209 for(ReplicatedLogEntry logEntry : journal) {
210 dataSize += logEntry.size();
216 public void snapshotRollback() {
217 snapshottedJournal.addAll(journal);
218 journal = snapshottedJournal;
219 snapshottedJournal = null;
221 snapshotIndex = previousSnapshotIndex;
222 previousSnapshotIndex = -1;
224 snapshotTerm = previousSnapshotTerm;
225 previousSnapshotTerm = -1;