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 2009/08/19 10:28:45 UTC

svn commit: r805696 - in /db/derby/code/trunk/java: engine/org/apache/derby/impl/store/access/btree/BTreeController.java testing/org/apache/derbyTesting/functionTests/tests/lang/NullableUniqueConstraintTest.java

Author: kahatlen
Date: Wed Aug 19 08:28:45 2009
New Revision: 805696

URL: http://svn.apache.org/viewvc?rev=805696&view=rev
Log:
DERBY-4081: BTreeController.comparePreviousRecord() may fail to release latch on left-most leaf

When a new value is inserted into a nullable unique index, the rows
immediately to the left and the right of the insertion point are
checked for duplicates. comparePreviousRecord() checks the rows to the
left of the insertion point. If the row immediately to the left is
marked as deleted, it will have to go further to the left until it
finds a row that is not deleted.

Now this check may cross page boundaries, and if it does so, and all
the rows to the left of the insertion point are deleted,
comparePreviousRecord() will return NO_MATCH before the latch
left-most leaf in the index has been released.

This means that the left-most leaf is still latched when
comparePreviousRecord() returns, which it is not supposed to be unless
the new value was actually inserted into the left-most leaf. The
unexpected extra latch may cause deadlocks or livelocks.

This patch adds a test that runs into a livelock because of the bug,
and it fixes the bug by releasing the latch on the left-most leaf
before returning NO_MATCH from comparePreviousRecord().

Modified:
    db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/btree/BTreeController.java
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/NullableUniqueConstraintTest.java

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/btree/BTreeController.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/btree/BTreeController.java?rev=805696&r1=805695&r2=805696&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/btree/BTreeController.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/btree/BTreeController.java Wed Aug 19 08:28:45 2009
@@ -386,14 +386,15 @@
                     //slot is pointing before the first slot
                     //get left sibiling
                     leaf = (LeafControlRow) leaf.getLeftSibling(this);
+                    if (newLeaf) {
+                        oldLeaf.release();
+                    }
+                    newLeaf = true;
                     //no left sibiling
                     if (leaf == null)
                         return NO_MATCH;
                     //set the slot to last slot number
                     slot = leaf.page.recordCount() - 1;
-                    if (newLeaf)
-                        oldLeaf.release();
-                    newLeaf = true;
                     // DERBY-4027: We have moved to the previous page and need
                     // to recheck that the slot number is valid (it won't be
                     // if the page we moved to is empty). Restart from the top

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/NullableUniqueConstraintTest.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/NullableUniqueConstraintTest.java?rev=805696&r1=805695&r2=805696&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/NullableUniqueConstraintTest.java (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/NullableUniqueConstraintTest.java Wed Aug 19 08:28:45 2009
@@ -531,6 +531,33 @@
                 "update constraintest set val1 = '2' where val1 = '3'");
     }
 
+    /**
+     * Test that we can insert and delete the same value multiple times in a
+     * nullable unique index. This used to cause a livelock before DERBY-4081
+     * because the duplicate check on insert sometimes didn't release all
+     * latches.
+     */
+    public void testInsertDeleteContinuouslySameValue() throws SQLException {
+        // Must disable auto-commit for reliable reproduction, otherwise the
+        // post-commit worker thread will remove deleted index rows.
+        setAutoCommit(false);
+
+        Statement s = createStatement();
+        s.execute("create table d4081(x int unique)");
+
+        // The loop below did not get past the 372nd iteration before
+        // DERBY-4081 was fixed. Try 500 iterations now.
+        PreparedStatement ins = prepareStatement("insert into d4081 values 0");
+        PreparedStatement del = prepareStatement("delete from d4081");
+        for (int i = 0; i < 500; i++) {
+            ins.execute();
+            del.execute();
+        }
+
+        // Verify that the table is empty after the last delete operation.
+        assertTableRowCount("D4081", 0);
+    }
+
     public static void main(String [] args) {
         TestResult tr = new TestResult();
         Test t = suite();