From 9ca54cae8c40fcd3fd4b85414c4be5aa3c3c77d6 Mon Sep 17 00:00:00 2001
From: Jean-Noel Rouvignac <jean-noel.rouvignac@forgerock.com>
Date: Tue, 20 May 2014 14:06:04 +0000
Subject: [PATCH] Fixing JEChangeNumberIndexDBTest random tests. JE was throwing exception when the thread accessing it had been interrupted which happens frequently on single core machines. The solution is to replace the use of Thread.sleep(long) + Thread.interrupt() with Object.wait(long) + Object.notify() on thread shutdown.

---
 opendj3-server-dev/src/server/org/opends/server/replication/server/changelog/je/JEChangelogDB.java |   53 +++++++++++++++++++++++++++++++++++++++--------------
 1 files changed, 39 insertions(+), 14 deletions(-)

diff --git a/opendj3-server-dev/src/server/org/opends/server/replication/server/changelog/je/JEChangelogDB.java b/opendj3-server-dev/src/server/org/opends/server/replication/server/changelog/je/JEChangelogDB.java
index 6a5a11b..a5540a2 100644
--- a/opendj3-server-dev/src/server/org/opends/server/replication/server/changelog/je/JEChangelogDB.java
+++ b/opendj3-server-dev/src/server/org/opends/server/replication/server/changelog/je/JEChangelogDB.java
@@ -377,13 +377,11 @@
     if (indexer != null)
     {
       indexer.initiateShutdown();
-      indexer.interrupt();
     }
     final ChangelogDBPurger purger = cnPurger.getAndSet(null);
     if (purger != null)
     {
       purger.initiateShutdown();
-      purger.interrupt();
     }
 
     try
@@ -827,17 +825,14 @@
             oldestNotPurgedCSN = localCNIndexDB.purgeUpTo(purgeCSN);
             if (oldestNotPurgedCSN == null)
             { // shutdown may have been initiated...
-              if (!isShutdownInitiated())
-              {
-                // ... or the change number index DB is empty,
-                // wait for new changes to come in.
+              // ... or the change number index DB is empty,
+              // wait for new changes to come in.
 
-                // Note we cannot sleep for as long as the purge delay
-                // (3 days default), because we might receive late updates
-                // that will have to be purged before the purge delay elapses.
-                // This can particularly happen in case of network partitions.
-                sleep(DEFAULT_SLEEP);
-              }
+              // Note we cannot sleep for as long as the purge delay
+              // (3 days default), because we might receive late updates
+              // that will have to be purged before the purge delay elapses.
+              // This can particularly happen in case of network partitions.
+              jeFriendlySleep(DEFAULT_SLEEP);
               continue;
             }
           }
@@ -853,7 +848,7 @@
 
           latestPurgeDate = purgeTimestamp;
 
-          sleep(computeSleepTimeUntilNextPurge(oldestNotPurgedCSN));
+          jeFriendlySleep(computeSleepTimeUntilNextPurge(oldestNotPurgedCSN));
         }
         catch (InterruptedException e)
         {
@@ -870,6 +865,33 @@
       }
     }
 
+    /**
+     * This method implements a sleep() that is friendly to Berkeley JE.
+     * <p>
+     * Originally, {@link Thread#sleep(long)} was used , but waking up a
+     * sleeping threads required calling {@link Thread#interrupt()}, and JE
+     * threw exceptions when invoked on interrupted threads.
+     * <p>
+     * The solution is to replace:
+     * <ol>
+     * <li> {@link Thread#sleep()} with {@link Object#wait(long)}</li>
+     * <li> {@link Thread#interrupt()} with {@link Object#notify()}</li>
+     * </ol>
+     */
+    private void jeFriendlySleep(long millis) throws InterruptedException
+    {
+      if (!isShutdownInitiated())
+      {
+        synchronized (this)
+        {
+          if (!isShutdownInitiated())
+          {
+            wait(millis);
+          }
+        }
+      }
+    }
+
     private long computeSleepTimeUntilNextPurge(CSN notPurgedCSN)
     {
       final long nextPurgeTime = notPurgedCSN.getTime();
@@ -888,7 +910,10 @@
     public void initiateShutdown()
     {
       super.initiateShutdown();
-      this.interrupt(); // wake up the purger thread for faster shutdown
+      synchronized (this)
+      {
+        notify(); // wake up the purger thread for faster shutdown
+      }
     }
   }
 }

--
Gitblit v1.10.0