From 933e60b44df8950bb3df2e8908d991bcb6edfc1a Mon Sep 17 00:00:00 2001
From: Nicolas Capponi <nicolas.capponi@forgerock.com>
Date: Wed, 25 Jun 2014 15:43:38 +0000
Subject: [PATCH] Checkpoint commit for OPENDJ-1471 File based changelog : improve cursor behavior

---
 opends/src/server/org/opends/server/replication/server/changelog/file/FileReplicaDBCursor.java |   68 +++++++++++++++++++++------------
 1 files changed, 43 insertions(+), 25 deletions(-)

diff --git a/opends/src/server/org/opends/server/replication/server/changelog/file/FileReplicaDBCursor.java b/opends/src/server/org/opends/server/replication/server/changelog/file/FileReplicaDBCursor.java
index e067b6a..2bd7392 100644
--- a/opends/src/server/org/opends/server/replication/server/changelog/file/FileReplicaDBCursor.java
+++ b/opends/src/server/org/opends/server/replication/server/changelog/file/FileReplicaDBCursor.java
@@ -32,18 +32,28 @@
 import org.opends.server.replication.server.changelog.file.Log.RepositionableCursor;
 
 /**
- * A cursor on ReplicaDB.
+ * A cursor on ReplicaDB, which can re-initialize itself after exhaustion.
  * <p>
- * This cursor behaves specially in two ways :
- * <ul>
- *  <li>The cursor initially points to a {@code null} value: the
- *      {@code getRecord()} method return {@code null} if called before any call to
- *      {@code next()} method.</li>
- *  <li>The cursor automatically re-initializes itself if it is exhausted: when
- *      exhausted, the cursor re-position itself to the last non null CSN previously
- *      read.
- *  <li>
- * </ul>
+ * The cursor provides a java.sql.ResultSet like API :
+ * <pre>
+ * {@code
+ *  FileReplicaDBCursor cursor = ...;
+ *  try {
+ *    while (cursor.next()) {
+ *      Record record = cursor.getRecord();
+ *      // ... can call cursor.getRecord() again: it will return the same result
+ *    }
+ *  }
+ *  finally {
+ *    close(cursor);
+ *  }
+ * }
+ * </pre>
+ * <p>
+ * The cursor automatically re-initializes itself if it is exhausted: if a
+ * record is newly available, a subsequent call to the {@code next()} method will
+ * return {@code true} and the record will be available by calling {@code getRecord()}
+ * method.
  */
 class FileReplicaDBCursor implements DBCursor<UpdateMsg>
 {
@@ -54,7 +64,7 @@
   /** The next record to return. */
   private Record<CSN, UpdateMsg> nextRecord;
 
-  /** The CSN to re-start with in case the cursor is exhausted. */
+  /**  The CSN to re-start with in case the cursor is exhausted. */
   private CSN lastNonNullCurrentCSN;
 
   /**
@@ -82,25 +92,33 @@
   @Override
   public boolean next() throws ChangelogException
   {
-    nextRecord = cursor.getRecord();
-    if (nextRecord != null)
+    if (cursor.next())
     {
+      nextRecord = cursor.getRecord();
+      if (nextRecord.getKey().compareTo(lastNonNullCurrentCSN) > 0)
+      {
+        lastNonNullCurrentCSN = nextRecord.getKey();
+        return true;
+      }
+    }
+    return nextWhenCursorIsExhaustedOrNotCorrectlyPositionned();
+  }
+
+  /** Re-initialize the cursor after the last non null CSN. */
+  private boolean nextWhenCursorIsExhaustedOrNotCorrectlyPositionned() throws ChangelogException
+  {
+    final boolean found = cursor.positionTo(lastNonNullCurrentCSN, true);
+    if (found && cursor.next())
+    {
+      nextRecord = cursor.getRecord();
       lastNonNullCurrentCSN = nextRecord.getKey();
+      return true;
     }
     else
     {
-      // Exhausted cursor must be able to reinitialize itself
-      cursor.positionTo(lastNonNullCurrentCSN, true);
-
-      nextRecord = cursor.getRecord();
-      if (nextRecord != null)
-      {
-        lastNonNullCurrentCSN = nextRecord.getKey();
-      }
+      nextRecord = null;
+      return false;
     }
-    // the underlying cursor is one record in advance
-    cursor.next();
-    return nextRecord != null;
   }
 
   /** {@inheritDoc} */

--
Gitblit v1.10.0