This is an automated email from the ASF dual-hosted git repository.

blerer pushed a commit to branch cep-21-tcm-review
in repository https://gitbox.apache.org/repos/asf/cassandra.git

commit 509d33155f9e222a086b3d61c969208dad6fe722
Author: Benjamin Lerer <b.le...@gmail.com>
AuthorDate: Tue Oct 17 13:10:15 2023 +0200

    Simplify the RecentlySealedPeriod logic
---
 .../cassandra/tcm/RecentlySealedPeriods.java       | 92 +++++++++-------------
 src/java/org/apache/cassandra/tcm/Sealed.java      |  2 +-
 .../cassandra/tcm/RecentlySealedPeriodsTest.java   | 18 +++--
 3 files changed, 48 insertions(+), 64 deletions(-)

diff --git a/src/java/org/apache/cassandra/tcm/RecentlySealedPeriods.java 
b/src/java/org/apache/cassandra/tcm/RecentlySealedPeriods.java
index cc16ae656e..cca1d7a213 100644
--- a/src/java/org/apache/cassandra/tcm/RecentlySealedPeriods.java
+++ b/src/java/org/apache/cassandra/tcm/RecentlySealedPeriods.java
@@ -18,11 +18,12 @@
 
 package org.apache.cassandra.tcm;
 
-import java.util.Arrays;
-import java.util.Collections;
 import java.util.List;
+import java.util.Map;
+import java.util.NavigableMap;
 
 import com.google.common.annotations.VisibleForTesting;
+import com.google.common.collect.ImmutableSortedMap;
 
 import org.apache.cassandra.config.CassandraRelevantProperties;
 
@@ -34,50 +35,40 @@ import 
org.apache.cassandra.config.CassandraRelevantProperties;
  * the target is outside the range of this index, we eventually fall back to a 
read
  * from the system.metadata_sealed_periods table.
  */
-public class RecentlySealedPeriods
+public final class RecentlySealedPeriods
 {
-    public static final RecentlySealedPeriods EMPTY = new 
RecentlySealedPeriods(new Sealed[0]);
+    public static final RecentlySealedPeriods EMPTY = new 
RecentlySealedPeriods(ImmutableSortedMap.of());
 
     /**
      * The maximum number of sealed periods stored in memory.
      */
-    private int maxSize = 
CassandraRelevantProperties.TCM_RECENTLY_SEALED_PERIOD_INDEX_SIZE.getInt();
-    private Sealed[] recent;
+    private final int maxSize = 
CassandraRelevantProperties.TCM_RECENTLY_SEALED_PERIOD_INDEX_SIZE.getInt();
+    private final NavigableMap<Epoch, Sealed> recent;
 
-    private RecentlySealedPeriods(Sealed first)
-    {
-        this.recent = new Sealed[]{first};
-    }
-
-    private RecentlySealedPeriods(Sealed[] recent)
+    private RecentlySealedPeriods(ImmutableSortedMap<Epoch, Sealed> recent)
     {
         this.recent = recent;
     }
 
     public static RecentlySealedPeriods init(List<Sealed> recent)
     {
-        Collections.sort(recent);
-        return new RecentlySealedPeriods(recent.toArray(new 
Sealed[recent.size()]));
+        ImmutableSortedMap.Builder<Epoch, Sealed> builder = 
ImmutableSortedMap.naturalOrder();
+        for (Sealed sealed: recent)
+        {
+            builder.put(sealed.epoch, sealed);
+        }
+        return new RecentlySealedPeriods(builder.build());
     }
 
-
     public RecentlySealedPeriods with(Epoch epoch, long period)
     {
-        if (recent == null)
-        {
-            return new RecentlySealedPeriods(new Sealed(period, epoch));
-        }
-        else
-        {
-            int toCopy = Math.min(recent.length, maxSize - 1);
-            int newSize = Math.min(recent.length + 1, maxSize);
-            Sealed[] newList = new Sealed[newSize];
-            System.arraycopy(recent, recent.length - toCopy, newList, 0, 
toCopy);
-            newList[newSize - 1] = new Sealed(period, epoch);
-            // shouldn't be necessary, but is cheap
-            Arrays.sort(newList, Sealed::compareTo);
-            return new RecentlySealedPeriods(newList);
-        }
+        NavigableMap<Epoch, Sealed> toKeep = recent.size() < maxSize ? recent
+                                                                     : 
recent.tailMap(recent.firstKey(), false);
+
+        return new RecentlySealedPeriods(ImmutableSortedMap.<Epoch, 
Sealed>naturalOrder()
+                                                           .putAll(toKeep)
+                                                           .put(epoch, new 
Sealed(period, epoch))
+                                                           .build());
     }
 
     /**
@@ -86,28 +77,27 @@ public class RecentlySealedPeriods
      * as long as its epoch is greater than the target.
      * If the target epoch is greater than the max epoch in the latest sealed
      * period, then assume there is no suitable snapshot.
-     * @param epoch
+     * @param epoch the target epoch
      * @return
      */
     public Sealed lookupEpochForSnapshot(Epoch epoch)
     {
+        if (recent.isEmpty())
+            return Sealed.EMPTY;
+
         // if the target is > the highest indexed value there's no need to
         // scan the index. Instead, just signal to the caller that no suitable
         // sealed period was found.
-        if (recent.length > 0)
-        {
-            Sealed latest = recent[recent.length - 1];
-            return latest.epoch.isAfter(epoch) ? latest : Sealed.EMPTY;
-        }
-        return Sealed.EMPTY;
+        Map.Entry<Epoch, Sealed> latest = recent.lastEntry();
+        return latest.getKey().isAfter(epoch) ? latest.getValue() : 
Sealed.EMPTY;
     }
 
     // TODO add a lookupEpochForSnapshotBetween(start, end) so we can walk
     //      through the index if the latest snapshot happens to be missing
 
     /**
-     * Find the *closest* sealed period to a target epoch. Used to identify
-     * the period to start at if building a list of all log entries with an
+     * Find the sealed period stricly greater than the target epoch.
+     * <p>This method is used to identify the period to start from if building 
a list of all log entries with an
      * epoch greater than the one supplied. If the target epoch happens to be
      * the max in a sealed period, we would start with the period following
      * that. If the target epoch is equal to or after the max in the latest
@@ -117,28 +107,18 @@ public class RecentlySealedPeriods
      */
     public Sealed lookupPeriodForReplication(Epoch epoch)
     {
-        // if the target is > the highest indexed value there's no need to
-        // scan the index. Instead, just signal to the caller that no suitable
-        // sealed period was found.
-        if (recent.length > 0 && epoch.isEqualOrAfter(recent[recent.length - 
1].epoch))
-            return Sealed.EMPTY;
-
-        for (int i = recent.length - 1; i >= 0; i--)
-        {
-            Sealed e = recent[i];
-            if (e.epoch.isEqualOrBefore(epoch))
-                return recent[Math.min(i + 1, recent.length - 1)];
-        }
-
-        // the target epoch couldn't be found in the index, signal to the
+        // if the target is not within the index we need to signal to the
         // caller that a slower/more expensive/more comprehensive lookup
         // is required
-        return Sealed.EMPTY;
+        if (recent.isEmpty() || epoch.isBefore(recent.firstKey()) || 
epoch.isEqualOrAfter(recent.lastKey()))
+            return Sealed.EMPTY;
+
+        return recent.higherEntry(epoch).getValue();
     }
 
     @VisibleForTesting
-    public Sealed[] array()
+    public Sealed[] toArray()
     {
-        return recent;
+        return recent.values().toArray(new Sealed[recent.size()]);
     }
 }
diff --git a/src/java/org/apache/cassandra/tcm/Sealed.java 
b/src/java/org/apache/cassandra/tcm/Sealed.java
index 574131b626..2a38d92fc0 100644
--- a/src/java/org/apache/cassandra/tcm/Sealed.java
+++ b/src/java/org/apache/cassandra/tcm/Sealed.java
@@ -150,6 +150,6 @@ public class Sealed implements Comparable<Sealed>
     @Override
     public int compareTo(Sealed o)
     {
-        return Long.compare(this.epoch.getEpoch(), o.epoch.getEpoch());
+        return this.epoch.compareTo(o.epoch);
     }
 }
diff --git a/test/unit/org/apache/cassandra/tcm/RecentlySealedPeriodsTest.java 
b/test/unit/org/apache/cassandra/tcm/RecentlySealedPeriodsTest.java
index b0d236a67b..6bc3d6ab4f 100644
--- a/test/unit/org/apache/cassandra/tcm/RecentlySealedPeriodsTest.java
+++ b/test/unit/org/apache/cassandra/tcm/RecentlySealedPeriodsTest.java
@@ -19,6 +19,7 @@
 package org.apache.cassandra.tcm;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 import java.util.Random;
@@ -49,11 +50,14 @@ public class RecentlySealedPeriodsTest
         for (int i=1; i<=10;i++)
             idx = idx.with(Epoch.create((i*3)+1), i);
 
-        assertEquals(10, idx.array().length);
+        System.out.println(Arrays.toString(idx.toArray()));
+
+
+        assertEquals(10, idx.toArray().length);
         // lowest indexed period is 1
-        assertEquals(1, idx.array()[0].period);
+        assertEquals(1, idx.toArray()[0].period);
         // greatest indexed period is 10
-        assertEquals(10, idx.array()[idx.array().length - 1].period);
+        assertEquals(10, idx.toArray()[idx.toArray().length - 1].period);
 
         assertEquals(7, 
idx.lookupPeriodForReplication(Epoch.create(20)).period);
         // looking an epoch which is the max in a sealed period, should return 
the next period (for replication purposes)
@@ -68,11 +72,11 @@ public class RecentlySealedPeriodsTest
         // add an additional entry
         idx = idx.with(Epoch.create(100), 11);
         // reassert the boundaries
-        assertEquals(10, idx.array().length);
+        assertEquals(10, idx.toArray().length);
         // lowest indexed period is now 2
-        assertEquals(2, idx.array()[0].period);
+        assertEquals(2, idx.toArray()[0].period);
         // greatest indexed period is now 11
-        assertEquals(11, idx.array()[idx.array().length - 1].period);
+        assertEquals(11, idx.toArray()[idx.toArray().length - 1].period);
 
         // lookup an epoch within the (new) maximum sealed period
         assertEquals(11, 
idx.lookupPeriodForReplication(Epoch.create(76)).period);
@@ -101,7 +105,7 @@ public class RecentlySealedPeriodsTest
         for (Long epoch : keys)
             idx = idx.with(Epoch.create(epoch), epoch/10);
 
-        Sealed[] index = idx.array();
+        Sealed[] index = idx.toArray();
         for(int i=0; i<index.length; i++)
         {
             Sealed entry = index[i];


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@cassandra.apache.org
For additional commands, e-mail: commits-h...@cassandra.apache.org

Reply via email to