From e84de8ea992525eb6ac672ddc764e3a4825e36d9 Mon Sep 17 00:00:00 2001
From: Nicolas Capponi <nicolas.capponi@forgerock.com>
Date: Mon, 25 Apr 2016 09:38:43 +0000
Subject: [PATCH] OPENDJ-2794 Move check of key ordering from Log to LogFile class when adding a changelog record

---
 opendj-server-legacy/src/main/java/org/opends/server/replication/server/changelog/file/LogFile.java |   63 ++++++++++++++++++++++---------
 1 files changed, 44 insertions(+), 19 deletions(-)

diff --git a/opendj-server-legacy/src/main/java/org/opends/server/replication/server/changelog/file/LogFile.java b/opendj-server-legacy/src/main/java/org/opends/server/replication/server/changelog/file/LogFile.java
index f088a15..09b95ad 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/replication/server/changelog/file/LogFile.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/replication/server/changelog/file/LogFile.java
@@ -11,7 +11,7 @@
  * Header, with the fields enclosed by brackets [] replaced by your own identifying
  * information: "Portions Copyright [year] [name of copyright owner]".
  *
- * Copyright 2014-2015 ForgeRock AS.
+ * Copyright 2014-2016 ForgeRock AS.
  */
 package org.opends.server.replication.server.changelog.file;
 
@@ -77,6 +77,11 @@
   /** Lock used to ensure that log file is in a consistent state when reading it. */
   private final Lock sharedLock;
 
+  /**
+   * The newest (last) record appended to this log file. In order to keep the ordering of the keys
+   * in the log file, any attempt to append a record with a key lower or equal to this key is
+   * rejected (no error but an event is logged).
+   */
   private Record<K, V> newestRecord;
 
   /**
@@ -114,6 +119,7 @@
     final ReadWriteLock rwLock = new ReentrantReadWriteLock();
     exclusiveLock = rwLock.writeLock();
     sharedLock = rwLock.readLock();
+    initializeNewestRecord();
   }
 
   /**
@@ -227,9 +233,11 @@
   /**
    * Add the provided record at the end of this log.
    * <p>
-   * In order to ensure that record is written out of buffers and persisted
-   * to file system, it is necessary to explicitely call the
-   * {@code syncToFileSystem()} method.
+   * The record must have a key strictly higher than the key of the last record added.
+   * If it is not the case, the record is not appended.
+   * <p>
+   * In order to ensure that record is written out of buffers and persisted to file system, it is
+   * necessary to explicitly call the {@link #syncToFileSystem()} method.
    *
    * @param record
    *          The record to add.
@@ -242,6 +250,10 @@
     exclusiveLock.lock();
     try
     {
+      if (appendWouldBreakKeyOrdering(record))
+      {
+        return;
+      }
       writer.write(record);
       newestRecord = record;
     }
@@ -251,6 +263,18 @@
     }
   }
 
+  /** Indicates if the provided record has a key that would break the key ordering if appended in this file log. */
+  boolean appendWouldBreakKeyOrdering(final Record<K, V> record)
+  {
+    boolean wouldBreakOrder = newestRecord != null && record.getKey().compareTo(newestRecord.getKey()) <= 0;
+    if (wouldBreakOrder)
+    {
+      logger.debug(
+          INFO_CHANGELOG_FILTER_OUT_RECORD_BREAKING_ORDER.get(logfile.getPath(), record, newestRecord.getKey()));
+    }
+    return wouldBreakOrder;
+  }
+
   /**
    * Dump this log file as a text file, intended for debugging purpose only.
    *
@@ -363,28 +387,29 @@
    * @throws ChangelogException
    *           If an error occurs while retrieving the record.
    */
-  Record<K, V> getNewestRecord() throws ChangelogException
+  Record<K, V> getNewestRecord()
   {
-    if (newestRecord == null)
+    return newestRecord;
+  }
+
+  private void initializeNewestRecord() throws ChangelogException
+  {
+    try (BlockLogReader<K, V> reader = getReader())
     {
-      try (BlockLogReader<K, V> reader = getReader())
+      sharedLock.lock();
+      try
       {
-        sharedLock.lock();
-        try
-        {
-          newestRecord = reader.getNewestRecord();
-        }
-        finally
-        {
-          sharedLock.unlock();
-        }
+        newestRecord = reader.getNewestRecord();
       }
-      catch (IOException ioe)
+      finally
       {
-        throw new ChangelogException(ERR_CHANGELOG_CANNOT_READ_NEWEST_RECORD.get(logfile.getAbsolutePath()), ioe);
+        sharedLock.unlock();
       }
     }
-    return newestRecord;
+    catch (IOException ioe)
+    {
+      throw new ChangelogException(ERR_CHANGELOG_CANNOT_READ_NEWEST_RECORD.get(logfile.getAbsolutePath()), ioe);
+    }
   }
 
   /**

--
Gitblit v1.10.0