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.List;
14 * Abstract class handling the mapping of
15 * logical LogEntry Index and the physical list index.
17 public abstract class AbstractReplicatedLogImpl implements ReplicatedLog {
19 // We define this as ArrayList so we can use ensureCapacity.
20 protected ArrayList<ReplicatedLogEntry> journal;
22 protected long snapshotIndex = -1;
23 protected long snapshotTerm = -1;
25 // to be used for rollback during save snapshot failure
26 protected ArrayList<ReplicatedLogEntry> snapshottedJournal;
27 protected long previousSnapshotIndex = -1;
28 protected long previousSnapshotTerm = -1;
30 public AbstractReplicatedLogImpl(long snapshotIndex,
31 long snapshotTerm, List<ReplicatedLogEntry> unAppliedEntries) {
32 this.snapshotIndex = snapshotIndex;
33 this.snapshotTerm = snapshotTerm;
34 this.journal = new ArrayList<>(unAppliedEntries);
37 public AbstractReplicatedLogImpl() {
38 this.journal = new ArrayList<>();
41 protected int adjustedIndex(long logEntryIndex) {
42 if(snapshotIndex < 0){
43 return (int) logEntryIndex;
45 return (int) (logEntryIndex - (snapshotIndex + 1));
49 public ReplicatedLogEntry get(long logEntryIndex) {
50 int adjustedIndex = adjustedIndex(logEntryIndex);
52 if (adjustedIndex < 0 || adjustedIndex >= journal.size()) {
53 // physical index should be less than list size and >= 0
57 return journal.get(adjustedIndex);
61 public ReplicatedLogEntry last() {
62 if (journal.isEmpty()) {
65 // get the last entry directly from the physical index
66 return journal.get(journal.size() - 1);
70 public long lastIndex() {
71 if (journal.isEmpty()) {
72 // it can happen that after snapshot, all the entries of the
73 // journal are trimmed till lastApplied, so lastIndex = snapshotIndex
76 return last().getIndex();
80 public long lastTerm() {
81 if (journal.isEmpty()) {
82 // it can happen that after snapshot, all the entries of the
83 // journal are trimmed till lastApplied, so lastTerm = snapshotTerm
86 return last().getTerm();
90 public void removeFrom(long logEntryIndex) {
91 int adjustedIndex = adjustedIndex(logEntryIndex);
92 if (adjustedIndex < 0 || adjustedIndex >= journal.size()) {
93 // physical index should be less than list size and >= 0
96 journal.subList(adjustedIndex , journal.size()).clear();
100 public void append(ReplicatedLogEntry replicatedLogEntry) {
101 journal.add(replicatedLogEntry);
105 public void increaseJournalLogCapacity(int amount) {
106 journal.ensureCapacity(journal.size() + amount);
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 long getSnapshotIndex() {
153 return snapshotIndex;
157 public long getSnapshotTerm() {
162 public abstract void appendAndPersist(ReplicatedLogEntry replicatedLogEntry);
165 public abstract void removeFromAndPersist(long index);
168 public void setSnapshotIndex(long snapshotIndex) {
169 this.snapshotIndex = snapshotIndex;
173 public void setSnapshotTerm(long snapshotTerm) {
174 this.snapshotTerm = snapshotTerm;
178 public void clear(int startIndex, int endIndex) {
179 journal.subList(startIndex, endIndex).clear();
183 public void snapshotPreCommit(long snapshotCapturedIndex, long snapshotCapturedTerm) {
184 snapshottedJournal = new ArrayList<>(journal.size());
186 snapshottedJournal.addAll(journal.subList(0, (int)(snapshotCapturedIndex - snapshotIndex)));
187 clear(0, (int) (snapshotCapturedIndex - snapshotIndex));
189 previousSnapshotIndex = snapshotIndex;
190 setSnapshotIndex(snapshotCapturedIndex);
192 previousSnapshotTerm = snapshotTerm;
193 setSnapshotTerm(snapshotCapturedTerm);
197 public void snapshotCommit() {
198 snapshottedJournal = null;
199 previousSnapshotIndex = -1;
200 previousSnapshotTerm = -1;
204 public void snapshotRollback() {
205 snapshottedJournal.addAll(journal);
206 journal = snapshottedJournal;
207 snapshottedJournal = null;
209 snapshotIndex = previousSnapshotIndex;
210 previousSnapshotIndex = -1;
212 snapshotTerm = previousSnapshotTerm;
213 previousSnapshotTerm = -1;