You are viewing a plain text version of this content. The canonical link for it is here.
Posted to derby-commits@db.apache.org by ka...@apache.org on 2011/10/11 14:48:03 UTC

svn commit: r1181756 - /db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/store/IndexSplitDeadlockTest.java

Author: kahatlen
Date: Tue Oct 11 12:48:03 2011
New Revision: 1181756

URL: http://svn.apache.org/viewvc?rev=1181756&view=rev
Log:
DERBY-5440: test failure in testBTreeForwardScan_fetchRows_resumeAfterWait_nonUnique_split(org.apache.derbyTesting.functionTests.tests.store.IndexSplitDeadlockTest)junit.framework.AssertionFailedError: expected:<1> but was:<0>

Modified:
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/store/IndexSplitDeadlockTest.java

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/store/IndexSplitDeadlockTest.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/store/IndexSplitDeadlockTest.java?rev=1181756&r1=1181755&r2=1181756&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/store/IndexSplitDeadlockTest.java (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/store/IndexSplitDeadlockTest.java Tue Oct 11 12:48:03 2011
@@ -360,11 +360,12 @@ public class IndexSplitDeadlockTest exte
         commit();
 
         // Object used for synchronization between the main thread and the
-        // helper thread. The main thread should increment the value to tell
-        // the helper thread that it's ready to start the index scan. The
-        // helper thread should increment it to tell the main thread that it
-        // has locked row 40 and is ready to insert more values.
-        final int[] syncObject = new int[1];
+        // helper thread. The main thread uses it to tell the helper thread
+        // that it has started the index scan. The helper thread uses it
+        // to tell the main thread that it has locked row 40 and is ready to
+        // insert more values. Both threads should wait until the other thread
+        // has reached the barrier before continuing.
+        final Barrier barrier = new Barrier(2);
 
         // Lock a row on the first page in a different thread to stop the
         // index scan. Then split the first leaf by inserting many values
@@ -376,20 +377,12 @@ public class IndexSplitDeadlockTest exte
                 s.executeUpdate("update t set x = x where x = 40");
                 s.close();
 
-                synchronized (syncObject) {
-                    // Tell the main thread that we've locked the row and that
-                    // it can go ahead with the index scan.
-                    syncObject[0]++;
-                    syncObject.notifyAll();
-
-                    // Wait here until the main thread is actually ready to
-                    // start the scan.
-                    while (syncObject[0] < 2) {
-                        syncObject.wait();
-                    }
-                }
+                // Tell the main thread that we've locked the row and that
+                // it can go ahead with the index scan. Wait here until the
+                // main thread has started the scan.
+                barrier.await();
 
-                // The main thread is ready to start the index scan. Give it a
+                // The main thread has started the index scan. Give it a
                 // second to get to the row we have locked.
                 Thread.sleep(1000L);
 
@@ -406,26 +399,21 @@ public class IndexSplitDeadlockTest exte
         });
 
         // Prepare the index scan.
-        PreparedStatement scan = prepareStatement(
+        ResultSet rs = s.executeQuery(
                 "select * from t --DERBY-PROPERTIES constraint=C");
 
-        synchronized (syncObject) {
-            // Tell the helper thread we're ready to start the scan.
-            syncObject[0]++;
-            syncObject.notifyAll();
-
-            // Wait until the helper thread has obtained the lock.
-            while (syncObject[0] < 2) {
-                syncObject.wait();
-            }
-        }
-
         // Perform an index scan. Will be blocked for a while when fetching
         // the row where x=40, but should be able to resume the scan.
-        ResultSet rs = scan.executeQuery();
         for (int i = 0; i < 300; i++) {
             assertTrue(rs.next());
             assertEquals(i, rs.getInt(1));
+
+            // Once we have fetched the first row, tell the helper thread we
+            // have started the index scan, and wait until it has locked the
+            // row that should block the scan (x=40).
+            if (i == 0) {
+                barrier.await();
+            }
         }
         assertFalse(rs.next());
         rs.close();
@@ -492,6 +480,11 @@ public class IndexSplitDeadlockTest exte
         }
         commit();
 
+        // Object used for synchronization between main thread and helper
+        // thread. They should both wait for the other thread to reach the
+        // barrier point before continuing.
+        final Barrier barrier = new Barrier(2);
+
         // Hold a lock in a different thread to stop the index scan, then
         // split the first leaf (on which the scan is positioned) before the
         // lock is released.
@@ -500,30 +493,42 @@ public class IndexSplitDeadlockTest exte
                 conn.setAutoCommit(false);
                 Statement s = conn.createStatement();
                 s.executeUpdate("update t set x = x where x = 40");
-                // Give the index scan time to start and position on
-                // the row we have locked. (Give it two seconds, since the
-                // main thread sleeps for one second first before it starts
-                // the index scan.)
-                Thread.sleep(2000);
-                // Split the first leaf by inserting more zeros
-                for (int i = -1; i > -300; i--) {
-                    s.executeUpdate("insert into t values 0");
+
+                // Tell the main thread we have locked the row, and wait for
+                // it to start the index scan.
+                barrier.await();
+
+                // Give the index scan time to get to the row we have locked.
+                Thread.sleep(1000);
+
+                // The index scan should be blocked now. Split the first leaf
+                // by inserting more values just before the lowest key, so
+                // that we can verify that the index scan is able to reposition
+                // correctly after a page split.
+                for (int i = 0; i < 300; i++) {
+                    s.executeUpdate("insert into t values -1");
                 }
                 s.close();
                 conn.commit();
             }
         });
 
-        // Give the other thread time to obtain the lock
-        Thread.sleep(1000);
-
         // Perform an index scan. Will be blocked for a while when fetching
-        // the row where x=100, but should be able to resume the scan.
+        // the row where x=40, but should be able to resume the scan after
+        // the helper thread commits and releases its locks.
         ResultSet rs = s.executeQuery(
                 "select * from t --DERBY-PROPERTIES index=IDX");
+
         for (int i = 0; i < 300; i++) {
             assertTrue(rs.next());
             assertEquals(i, rs.getInt(1));
+
+            // Once we have fetched the first row, tell the helper thread we
+            // have started the index scan, and wait until it has locked the
+            // row that should block the scan (x=40).
+            if (i == 0) {
+                barrier.await();
+            }
         }
         assertFalse(rs.next());
         rs.close();
@@ -829,4 +834,38 @@ public class IndexSplitDeadlockTest exte
             }
         }
     }
+
+    /**
+     * A poor man's substitute for java.util.concurrent.CyclicBarrier.
+     */
+    private static class Barrier {
+        /** The number of parties that still haven't reached the barrier. */
+        private int n;
+
+        /**
+         * Create a barrier that blocks until the specified number of threads
+         * have reached the barrier point.
+         *
+         * @param parties the number of parties to wait for at the barrier
+         */
+        Barrier(int parties) {
+            n = parties;
+        }
+
+        /**
+         * Wait until all parties have reached the barrier.
+         *
+         * @throws InterruptedException if the thread is interrupted
+         */
+        synchronized void await() throws InterruptedException {
+            assertTrue("Too many parties at barrier", n > 0);
+
+            n--;
+            notifyAll();
+
+            while (n > 0) {
+                wait();
+            }
+        }
+    }
 }