db-derby-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From mi...@apache.org
Subject svn commit: r603774 - in /db/derby/code/branches/10.3/java/engine/org/apache/derby/impl/store/access/btree: BTreeLockingPolicy.java index/B2IRowLocking3.java
Date Wed, 12 Dec 2007 23:15:00 GMT
Author: mikem
Date: Wed Dec 12 15:14:59 2007
New Revision: 603774

URL: http://svn.apache.org/viewvc?rev=603774&view=rev
Log:
DERBY-3244

backport svn 603375 from trunk to 10.3.

In the case of a wait for a latch while traveling left at leaf level, and
a subsequent wait for either a lock or another latch while looking for row
to lock then one path through the code would get a null pointer.  The code
was trying to release a latch that had already been released and was tracked
by "current_leaf == null".

I could not get this to fail in my environment, but did force it by code
inspection and changing the path through the code by hand to mimic latch
waits.  My assumption is that intermittently on some platforms this single
threaded test is competing for these latches with background deleted row
cleaner thread, probably on a fast multiple processor machine.


Modified:
    db/derby/code/branches/10.3/java/engine/org/apache/derby/impl/store/access/btree/BTreeLockingPolicy.java
    db/derby/code/branches/10.3/java/engine/org/apache/derby/impl/store/access/btree/index/B2IRowLocking3.java

Modified: db/derby/code/branches/10.3/java/engine/org/apache/derby/impl/store/access/btree/BTreeLockingPolicy.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.3/java/engine/org/apache/derby/impl/store/access/btree/BTreeLockingPolicy.java?rev=603774&r1=603773&r2=603774&view=diff
==============================================================================
--- db/derby/code/branches/10.3/java/engine/org/apache/derby/impl/store/access/btree/BTreeLockingPolicy.java
(original)
+++ db/derby/code/branches/10.3/java/engine/org/apache/derby/impl/store/access/btree/BTreeLockingPolicy.java
Wed Dec 12 15:14:59 2007
@@ -293,8 +293,10 @@
      * then it will release all latches that it has acquired up to that point
      * including the latched current_leaf passed into the routine, and request 
      * the lock WAIT.  Once the lock has been granted the routine will return
-     * and it is up to the caller to research the tree to find where the 
-     * row may have ended up.
+     * and it is up to the caller to research the tree to find where the
+     * current position may have ended up.  For instance in the case of insert
+     * once the current latch is released, the correct page to do the insert
+     * may no longer be where the original scan found it.
      * <p>
      * If routine returns true, lock was granted NOWAIT, current leaf
      * remains latched, and was never unlatched.  If routine returns false,

Modified: db/derby/code/branches/10.3/java/engine/org/apache/derby/impl/store/access/btree/index/B2IRowLocking3.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.3/java/engine/org/apache/derby/impl/store/access/btree/index/B2IRowLocking3.java?rev=603774&r1=603773&r2=603774&view=diff
==============================================================================
--- db/derby/code/branches/10.3/java/engine/org/apache/derby/impl/store/access/btree/index/B2IRowLocking3.java
(original)
+++ db/derby/code/branches/10.3/java/engine/org/apache/derby/impl/store/access/btree/index/B2IRowLocking3.java
Wed Dec 12 15:14:59 2007
@@ -341,6 +341,41 @@
         return(ret_status);
     }
 
+    /**
+     * move left in btree and lock previous key.
+     * <p>
+     * Enter routine with "current_leaf" latched.  This routine implements
+     * the left travel ladder locking protocol to search the leaf pages from
+     * right to left for the previous key to 1st key on current_leaf.
+     *
+     * There are 2 cases:
+     * 1) the previous page has keys, in which case the last key on that
+     *    page is locked, other wise search continues on the next page to
+     *    the left.
+     * 2) there are no keys on the current page and there is no page to the
+     *    left.  In this case the special "leftmost key" lock is gotten by
+     *    calling lockPreviousToFirstKey().
+     *
+     * Left laddar locking is used if all latches can be obtained immediately
+     * with NOWAIT.  This means that current latch is held while asking for
+     * left latch NOWAIT, and if left latch is granted then subsequently 
+     * current latch can be released.  If this protocol is followed and 
+     * all latches are granted then caller is guaranteed that the correct
+     * previous key has been locked and current_page latch remains.  The
+     * NOWAIT protocol is used to avoid latch/latch deadlocks.  The overall
+     * protocol is that one never holds a latch while waiting on another unless
+     * the direction of travel is down and to the right.
+     * <p>
+     * If along the search a latch has to be waited on then latches are
+     * released and a wait is performed, and "false" status is returned to
+     * caller.  In this case the routine can no longer be sure of it's current
+     * position and may have to retry the whole operation.
+     *
+     * @return true if previous key found without ever waiting on a latch, 
+     *         false if latch released in order to wait for other latch.
+     *
+     * @exception  StandardException  Standard exception policy.
+     **/
     private boolean searchLeftAndLockPreviousKey(
     B2I                     b2i,
     LeafControlRow          current_leaf,
@@ -364,18 +399,18 @@
 
             prev_leaf = 
                 (LeafControlRow) current_leaf.getLeftSibling(open_btree);
-
         }
         catch (WaitError e)
         {
+            // initial latch request on leaf left of current could not be
+            // granted NOWAIT.
+
             long previous_pageno = current_leaf.getleftSiblingPageNumber();
 
-            // error going from mainpage to first left page.  Release 
-            // current page latch and continue the search.
             current_leaf.release();
             current_leaf = null;
 
-            // wait on the left page, which we could not get before. 
+            // wait on the left leaf, which we could not be granted NOWAIT.
             prev_leaf = (LeafControlRow) 
                 ControlRow.get(open_btree, previous_pageno);
 
@@ -391,6 +426,7 @@
 
                 if (prev_leaf.getPage().recordCount() > 1)
                 {
+
                     // lock the last row on the page, which is the previous 
                     // record to the first row on the next page.
                     
@@ -409,6 +445,9 @@
 
                     if (!ret_status)
                     {
+                        // needed to wait on a row lock, so both prev_leaf and
+                        // current_leaf latches have been released by 
+                        // lockRowOnPage()
                         prev_leaf        = null;
                         current_leaf     = null;
                         latches_released = true;
@@ -427,6 +466,10 @@
 
                     if (!ret_status)
                     {
+                        // needed to wait on a row lock, so both prev_leaf and
+                        // current_leaf latches have been released by 
+                        // lockPreviousToFirstKey()
+
                         prev_leaf        = null;
                         current_leaf     = null;
                         latches_released = true;
@@ -440,14 +483,14 @@
                 // Release latches on pages between "current_leaf" and 
                 // where the search leads, so that at most 3 latched pages
                 // (current_leaf, prev_leaf, prev_prev_leaf) are held during 
-                // the search.  Do left ladder locking as you walk left, 
-                // but be ready to release l
+                // the search.  Do left ladder locking as you walk left.
 
                 prev_prev_leaf = 
                     (LeafControlRow) prev_leaf.getLeftSibling(open_btree);
                 prev_leaf.release();
                 prev_leaf = prev_prev_leaf;
                 prev_prev_leaf = null;
+
             }
             catch (WaitError e)
             {
@@ -455,8 +498,17 @@
 
                 // error going left.  Release current page latch and 
                 // original page latch continue the search.
-                current_leaf.release();
-                current_leaf = null;
+                if (current_leaf != null)
+                {
+                    // current_leaf may have already been released as part of
+                    // previous calls, need to check null status.
+                    current_leaf.release();
+                    current_leaf = null;
+                }
+
+                // can only get here by above getLeftSibling() call so prev_leaf
+                // should always be valid and latched at this point.  No null
+                // check necessary.
                 prev_leaf.release();
                 prev_leaf = null;
 
@@ -467,11 +519,11 @@
                 latches_released = true;
             }
         }
+
         if (prev_leaf != null)
             prev_leaf.release();
 
         return(!latches_released);
-
     }
 
     /**************************************************************************
@@ -897,7 +949,7 @@
     /**
      * Lock the row previous to the input row.
      * <p>
-     * See BTree.lockPreviousRow() for more info.
+     * See BTreeLockingPolicy.lockNonScanPreviousRow
      *
 	 * @exception  StandardException  Standard exception policy.
      **/



Mime
View raw message