Maintain last known position in JournalIndex
[controller.git] / atomix-storage / src / main / java / io / atomix / storage / journal / index / SparseJournalIndex.java
index 2b317362c57f3ee6b7637e3fedecbff22e49276d..b1c5e2ba1b3f00c710e4f1d8806938fe59451892 100644 (file)
@@ -16,7 +16,9 @@
  */
 package io.atomix.storage.journal.index;
 
+import com.google.common.base.MoreObjects;
 import java.util.TreeMap;
+import org.eclipse.jdt.annotation.Nullable;
 
 /**
  * A {@link JournalIndex} maintaining target density.
@@ -24,8 +26,11 @@ import java.util.TreeMap;
 public final class SparseJournalIndex implements JournalIndex {
     private static final int MIN_DENSITY = 1000;
 
-    private final int density;
     private final TreeMap<Long, Integer> positions = new TreeMap<>();
+    private final int density;
+
+    // Last known position. May not be accurate immediately after a truncate() or construction
+    private @Nullable Position last;
 
     public SparseJournalIndex() {
         density = MIN_DENSITY;
@@ -36,10 +41,18 @@ public final class SparseJournalIndex implements JournalIndex {
     }
 
     @Override
-    public void index(final long index, final int position) {
+    public Position index(final long index, final int position) {
+        final var newLast = new Position(index, position);
+        last = newLast;
         if (index % density == 0) {
             positions.put(index, position);
         }
+        return newLast;
+    }
+
+    @Override
+    public Position last() {
+        return last;
     }
 
     @Override
@@ -49,7 +62,20 @@ public final class SparseJournalIndex implements JournalIndex {
 
     @Override
     public Position truncate(final long index) {
-        positions.tailMap(index, false).clear();
-        return Position.ofNullable(positions.lastEntry());
+        // Clear all indexes unto and including index, saving the first removed entry
+        final var tailMap = positions.tailMap(index, true);
+        final var firstRemoved = tailMap.firstEntry();
+        tailMap.clear();
+
+        // Update last position to the last entry, but make sure to return a pointer to index if that is what we have
+        // indexed.
+        final var newLast = Position.ofNullable(positions.lastEntry());
+        last = newLast;
+        return firstRemoved != null && firstRemoved.getKey() == index ? new Position(firstRemoved) : newLast;
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(this).add("positions", positions).toString();
     }
 }