db-derby-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From kahat...@apache.org
Subject svn commit: r754894 [1/6] - in /db/derby/code/trunk/java: engine/org/apache/derby/iapi/store/access/conglomerate/ engine/org/apache/derby/iapi/store/raw/ engine/org/apache/derby/impl/store/access/ engine/org/apache/derby/impl/store/access/btree/ engine...
Date Mon, 16 Mar 2009 13:55:50 GMT
Author: kahatlen
Date: Mon Mar 16 13:55:49 2009
New Revision: 754894

URL: http://svn.apache.org/viewvc?rev=754894&view=rev
Log:
DERBY-2991: Index split deadlock

This is the main fix (patch d2991-2b.diff) which removes the scan lock
mechanism that caused the deadlocks and instead saves the scan
position by key whenever a scan loses its latches.

Modified:
    db/derby/code/trunk/java/engine/org/apache/derby/iapi/store/access/conglomerate/ScanManager.java
    db/derby/code/trunk/java/engine/org/apache/derby/iapi/store/access/conglomerate/TransactionManager.java
    db/derby/code/trunk/java/engine/org/apache/derby/iapi/store/raw/Page.java
    db/derby/code/trunk/java/engine/org/apache/derby/iapi/store/raw/RecordHandle.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/RAMTransaction.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/btree/BTreeController.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/btree/BTreeForwardScan.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/btree/BTreeLockingPolicy.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/btree/BTreeMaxScan.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/btree/BTreePostCommit.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/btree/BTreeRowPosition.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/btree/BTreeScan.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/btree/LeafControlRow.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/btree/OpenBTree.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/btree/index/B2INoLocking.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/btree/index/B2IRowLocking1.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/btree/index/B2IRowLocking2.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/btree/index/B2IRowLocking3.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/btree/index/B2IRowLockingRR.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/heap/HeapRowLocation.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/heap/HeapScan.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/sort/Scan.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/store/raw/data/BasePage.java
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/RowLockIso.out
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/readlocks.out
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/rlliso2multi.out
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/rlliso3multi.out
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/updatelocksJDBC30.out
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/store/rlliso2multi.sql
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/store/rlliso3multi.sql
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/unitTests/store/T_RawStoreFactory.java
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/unitTests/store/T_b2i.java

Modified: db/derby/code/trunk/java/engine/org/apache/derby/iapi/store/access/conglomerate/ScanManager.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/store/access/conglomerate/ScanManager.java?rev=754894&r1=754893&r2=754894&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/iapi/store/access/conglomerate/ScanManager.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/store/access/conglomerate/ScanManager.java Mon Mar 16 13:55:49 2009
@@ -170,21 +170,4 @@
     int[]                   key_column_numbers,
     BackingStoreHashtable   hash_table)
         throws StandardException;
-
-
-    /**
-     * Do work necessary to maintain the current position in the scan.
-     * <p>
-     * The latched page in the conglomerate "congomid" is changing, do
-     * whatever is necessary to maintain the current position of the scan.
-     * For some conglomerates this may be a no-op.
-     * <p>
-     *
-     * @param conglom   Conglomerate object of the conglomerate being changed.
-     * @param page      Page in the conglomerate being changed.
-     *
-	 * @exception  StandardException  Standard exception policy.
-     **/
-    public void savePosition(Conglomerate conglom, Page page)
-        throws StandardException;
 }

Modified: db/derby/code/trunk/java/engine/org/apache/derby/iapi/store/access/conglomerate/TransactionManager.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/store/access/conglomerate/TransactionManager.java?rev=754894&r1=754893&r2=754894&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/iapi/store/access/conglomerate/TransactionManager.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/store/access/conglomerate/TransactionManager.java Mon Mar 16 13:55:49 2009
@@ -22,12 +22,9 @@
 package org.apache.derby.iapi.store.access.conglomerate;
 
 import org.apache.derby.iapi.services.daemon.Serviceable;
-import org.apache.derby.iapi.store.access.AccessFactory;
 import org.apache.derby.iapi.store.access.ConglomerateController;
 import org.apache.derby.iapi.store.access.SortController;
 import org.apache.derby.iapi.store.access.TransactionController;
-import org.apache.derby.iapi.store.raw.LockingPolicy;
-import org.apache.derby.iapi.store.raw.Page;
 import org.apache.derby.iapi.store.raw.Transaction;
 import org.apache.derby.iapi.error.StandardException;
 
@@ -172,23 +169,4 @@
      **/
     public Transaction getRawStoreXact()
         throws StandardException;
-
-
-    /**
-     * Do work necessary to maintain the current position in all the scans.
-     * <p>
-     * The latched page in the conglomerate "congomid" is changing, do
-     * whatever is necessary to maintain the current position of all the
-     * scans open in this transaction.
-     * <p>
-     * For some conglomerates this may be a no-op.
-     * <p>
-     *
-     * @param conglom   Conglomerate object of the conglomerate being changed.
-     * @param page      Page in the conglomerate being changed.
-     *
-	 * @exception  StandardException  Standard exception policy.
-     **/
-    public void saveScanPositions(Conglomerate conglom, Page page)
-        throws StandardException;
 }

Modified: db/derby/code/trunk/java/engine/org/apache/derby/iapi/store/raw/Page.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/store/raw/Page.java?rev=754894&r1=754893&r2=754894&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/iapi/store/raw/Page.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/store/raw/Page.java Mon Mar 16 13:55:49 2009
@@ -139,14 +139,6 @@
 	public RecordHandle getInvalidRecordHandle();
 
     /**
-     * Get a record id protection handle.
-     *
-     * @return a record id protection handle
-     * @see RecordHandle#RECORD_ID_PROTECTION_HANDLE
-     */
-    public RecordHandle getProtectionRecordHandle();
-
-    /**
      * Return a record handle for the given constant record id.
      * <p>
      * Return a record handle that doesn't represent a record but rather has 
@@ -1081,6 +1073,30 @@
 		MT - latched
 	*/
 
+    /**
+     * Set a hint in the page object to indicate that scans positioned on it
+     * need to reposition. Only called on B-tree pages.
+     */
+    void setRepositionNeeded();
+
+    /**
+     * Check if this page has been changed in such a way that scans that are
+     * positioned on it will have to reposition. Only called on B-tree pages.
+     *
+     * @param version the version number of the page when the scan positioned
+     * on it (after which version the page should not have changed in a way
+     * that requires repositioning)
+     * @return {@code true} if a scan that was positioned on the page at page
+     * version {@code version} needs to reposition; {@code false} otherwise
+     */
+    boolean isRepositionNeeded(long version);
+
+    /**
+     * Get the current version number of the page.
+     *
+     * @return page version number
+     */
+    long getPageVersion();
 
 	/*
 	 * time stamp - for those implmentation that supports it

Modified: db/derby/code/trunk/java/engine/org/apache/derby/iapi/store/raw/RecordHandle.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/store/raw/RecordHandle.java?rev=754894&r1=754893&r2=754894&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/iapi/store/raw/RecordHandle.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/store/raw/RecordHandle.java Mon Mar 16 13:55:49 2009
@@ -47,11 +47,10 @@
 	public static final int INVALID_RECORD_HANDLE = 0;
  
 	/**
-		A lock with this recordHandle protects all the recordIds in the page.
-		No recordId can disappear while this lock is held. 
-		New recordIds may appear while this lock is held.
-	*/
-	public static final int RECORD_ID_PROTECTION_HANDLE = 1;
+     * Reserved for future use - name it and define it when you have a need
+     * to use one.
+     */
+	public static final int RESERVED1_RECORD_HANDLE = 1;
 
 	/**
 		A lock with this recordHandle protects this deallocated page from

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/RAMTransaction.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/RAMTransaction.java?rev=754894&r1=754893&r2=754894&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/RAMTransaction.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/RAMTransaction.java Mon Mar 16 13:55:49 2009
@@ -35,7 +35,6 @@
 
 import org.apache.derby.iapi.services.daemon.Serviceable;
 import org.apache.derby.iapi.services.locks.CompatibilitySpace;
-import org.apache.derby.iapi.services.monitor.Monitor;
 import org.apache.derby.iapi.services.sanity.SanityManager;
 import org.apache.derby.iapi.error.StandardException;
 import org.apache.derby.iapi.store.access.conglomerate.Conglomerate;
@@ -71,7 +70,6 @@
 
 
 import org.apache.derby.iapi.store.raw.Loggable;
-import org.apache.derby.iapi.store.raw.Page;
 import org.apache.derby.iapi.store.raw.Transaction;
 
 import org.apache.derby.iapi.types.DataValueDescriptor;
@@ -86,7 +84,6 @@
 import java.io.Serializable;
 
 // debugging
-import org.apache.derby.iapi.services.stream.HeaderPrintWriter;
 
 public class RAMTransaction 
     implements XATransactionController, TransactionManager
@@ -2372,53 +2369,6 @@
         return(rawtran);
     }
 
-
-    /**
-     * Do work necessary to maintain the current position in all the scans.
-     * <p>
-     * The latched page in the conglomerate "congomid" is changing, do
-     * whatever is necessary to maintain the current position of all the
-     * scans open in this transaction.
-     * <p>
-     * For some conglomerates this may be a no-op.
-     * <p>
-     *
-     * @param conglom   Conglomerate being changed.
-     * @param page      Page in the conglomerate being changed.
-     *
-	 * @exception  StandardException  Standard exception policy.
-     **/
-    public void saveScanPositions(Conglomerate conglom, Page page)
-        throws StandardException
-    {
-        for (Iterator it = scanControllers.iterator(); it.hasNext(); )
-		{
-            Object o = it.next();
-
-            if (SanityManager.DEBUG)
-            {
-                // The following debugging code is here because the following 
-                // (ScanManager) cast is occasionally causing a 
-                // java.lang.ClassCastException.
-
-                if (!(o instanceof ScanManager))
-                {
-                    HeaderPrintWriter istream = Monitor.getStream();
-                    
-                    if (o == null)
-                        istream.println("next element was null\n");
-                    else
-                        istream.println("non ScanManager on list: " + o);
-
-                    istream.println(
-                        "Current list of open scans: " +  debugOpened());
-                }
-            }
-			ScanManager sm = (ScanManager) o;
-            sm.savePosition(conglom, page);
-		}
-    }
-
 	public FileResource getFileHandler() {
 		return rawtran.getFileHandler();
 	}

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=754894&r1=754893&r2=754894&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 Mon Mar 16 13:55:49 2009
@@ -141,13 +141,8 @@
             int num_possible_commit_delete = 
                 leaf.page.recordCount() - 1 - leaf.page.nonDeletedRecordCount();
 
-            if ((num_possible_commit_delete > 0) &&
-                (btree_locking_policy.lockScanForReclaimSpace(leaf)))
+            if (num_possible_commit_delete > 0)
             {
-                // Need to get an exclusive scan lock on the page before we can
-                // do any sort of purges, otherwise other concurrent scans would
-                // not work.  If we can't get the lock NOWAIT, just give up on
-                // purging rows and do the split without reclaiming rows.
 
                 Page page   = leaf.page;
 
@@ -192,9 +187,15 @@
         }
         finally
         {
-            if (controlRow != null)
+            if (controlRow != null) {
+                if (purged_at_least_one_row) {
+                    // Set a hint in the page that scans positioned on it
+                    // need to reposition because rows have disappeared from
+                    // the page.
+                    controlRow.page.setRepositionNeeded();
+                }
                 controlRow.release();
-
+            }
         }
 
         return(purged_at_least_one_row);
@@ -724,7 +725,7 @@
                 latch_released = 
                     test_errors(
                         this,
-                        "BTreeController_doIns", false,
+                        "BTreeController_doIns", null,
                         this.getLockingPolicy(), 
                         targetleaf, latch_released);
             }

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/btree/BTreeForwardScan.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/btree/BTreeForwardScan.java?rev=754894&r1=754893&r2=754894&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/btree/BTreeForwardScan.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/btree/BTreeForwardScan.java Mon Mar 16 13:55:49 2009
@@ -29,7 +29,6 @@
 
 import org.apache.derby.iapi.store.access.ScanController;
 
-import org.apache.derby.iapi.store.raw.Page;
 import org.apache.derby.iapi.store.raw.RecordHandle;
 
 import org.apache.derby.iapi.types.DataValueDescriptor;
@@ -199,12 +198,14 @@
         // will be null), or when stopKeyValue is reached/passed.  Along the
         // way apply qualifiers to skip rows which don't qualify.
 
+        leaf_loop:
 		while (pos.current_leaf != null)
 		{
             // System.out.println(
               //   "1 of fetchSet loop, ret_row_count = " + ret_row_count +
                 // "fetch_row = " + fetch_row);
 
+            slot_loop:
 			while ((pos.current_slot + 1) < pos.current_leaf.page.recordCount())
 			{
 
@@ -304,7 +305,6 @@
                 boolean latch_released =
                     !this.getLockingPolicy().lockScanRow(
                         this, this.getConglomerate(), pos, 
-                        false, 
                         init_lock_fetch_desc,
                         pos.current_lock_template,
                         pos.current_lock_row_loc,
@@ -316,7 +316,7 @@
                     latch_released = 
                         test_errors(
                             this,
-                            "BTreeScan_fetchNextGroup", false, 
+                            "BTreeScan_fetchNextGroup", pos,
                             this.getLockingPolicy(),
                             pos.current_leaf, latch_released);
                 }
@@ -328,15 +328,42 @@
                 // is null until after the lock is granted.
                 pos.current_rh = rh;
 
-                if (latch_released)
+                while (latch_released)
                 {
                     // lost latch on page in order to wait for row lock.
-                    // Because we have scan lock on page, we need only
-                    // call reposition() which will use the saved record
-                    // handle to reposition to the same spot on the page.
-                    // We don't have to search the
-                    // tree again, as we have the a scan lock on the page
-                    // which means the current_rh is valid to reposition on.
+                    // reposition() will take care of the complexity with
+                    // finding the correct spot to position on if the row
+                    // has been moved to another page.
+
+                    if (!reposition(pos, false))
+                    {
+                        // Could not position on the exact same row that was
+                        // saved, which means that it has been purged.
+                        // Reposition on the row immediately to the left of
+                        // the purged row instead.
+                        if (!reposition(pos, true))
+                        {
+                            if (SanityManager.DEBUG)
+                            {
+                                SanityManager.THROWASSERT(
+                                        "Cannot fail with 2nd param true");
+                            }
+                            // reposition will set pos.current_leaf to null if
+                            // it returns false, so if this ever does fail in
+                            // delivered code, expect a NullPointerException at
+                            // the top of this loop when we call recordCount().
+                        }
+
+                        // Now we're positioned to the left of our saved
+                        // position. Go to the top of the loop so that we move
+                        // the scan to the next row and release the lock on
+                        // the purged row.
+                        continue slot_loop;
+                    }
+
+                    // At this point, the scan is positioned and the latch
+                    // is held.
+                    latch_released = false;
 
                     if (this.getConglomerate().isUnique())
                     {
@@ -355,25 +382,6 @@
                         // lock, and the row location we fetched earlier in
                         // this loop is invalid.
 
-                        while (latch_released)
-                        {
-                            if (!reposition(pos, false))
-                            {
-                                if (SanityManager.DEBUG)
-                                {
-                                    // can't fail while with scan lock
-                                    SanityManager.THROWASSERT(
-                                        "can not fail holding scan lock.");
-                                }
-
-                                // reposition will set pos.current_leaf to 
-                                // null, if it returns false so if the this
-                                // ever does fail in delivered code, expect
-                                // a null pointer exception on the next line,
-                                // trying to call fetchFromSlot().
-
-                            }
-
                             pos.current_leaf.page.fetchFromSlot(
                                 (RecordHandle) null,
                                 pos.current_slot, fetch_row, 
@@ -385,32 +393,10 @@
                                     this, 
                                     this.getConglomerate(), 
                                     pos, 
-                                    false, 
                                     init_lock_fetch_desc,
                                     pos.current_lock_template,
                                     pos.current_lock_row_loc,
                                     false, init_forUpdate, lock_operation);
-                        }
-                    }
-                    else
-                    {
-                        if (!reposition(pos, false))
-                        {
-                            if (SanityManager.DEBUG)
-                            {
-                                // can't fail while with scan lock
-                                SanityManager.THROWASSERT(
-                                    "can not fail holding scan lock.");
-                            }
-
-                            // reposition will set pos.current_leaf to 
-                            // null, if it returns false so if the this
-                            // ever does fail in delivered code, expect
-                            // a null pointer exception on the next line,
-                            // trying to call isDeletedAtSlot().
-
-                        }
-
                     }
                 }
 
@@ -446,6 +432,16 @@
                     ret_row_count++;
                     stat_numrows_qualified++;
 
+                    final boolean doneWithGroup = max_rowcnt <= ret_row_count;
+
+                    if (doneWithGroup) {
+                        if (SanityManager.DEBUG) {
+                            SanityManager.ASSERT(pos == scan_position);
+                        }
+                        int[] vcols = init_fetchDesc.getValidColumnsArray();
+                        savePositionAndReleasePage(fetch_row, vcols);
+                    }
+
                     if (hash_table != null)
                     {
                         if (hash_table.putRow(false, fetch_row))
@@ -456,15 +452,8 @@
                         fetch_row = null;
                     }
 
-                    if (max_rowcnt <= ret_row_count) 
+                    if (doneWithGroup)
                     {
-                        // current_slot is invalid after releasing latch
-                        pos.current_slot = Page.INVALID_SLOT_NUMBER;
-
-                        // exit fetch row loop and return to the client.
-                        pos.current_leaf.release();
-                        pos.current_leaf = null;
-
                         return(ret_row_count);
                     }
                 }

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/btree/BTreeLockingPolicy.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/btree/BTreeLockingPolicy.java?rev=754894&r1=754893&r2=754894&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/btree/BTreeLockingPolicy.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/btree/BTreeLockingPolicy.java Mon Mar 16 13:55:49 2009
@@ -73,96 +73,12 @@
 {
     /**************************************************************************
      * Abstract Protected lockScan*() locking methods of BTree:
-     *     lockScan                 - lock the scan page
-     *     lockScanForReclaimSpace  - lock page for reclaiming deleted rows.
-     *     lockScanRow              - lock row and possibly the scan page
-     *     unlockScan               - unlock the scan page
+     *     lockScanRow              - lock row
      *     unlockScanRecordAfterRead- unlock the scan record
      **************************************************************************
      */
 
     /**
-     * Lock the current leaf page.
-     * <p>
-     * Logically lock the record id's on a leaf page.  This protocol is used
-     * by splits/row purgers and scans to coordinate between themselves.
-     * <p>
-     * Anyone who wants to either move rows off of a btree page or, purge
-     * them from existence must first call this routine with "forUpdate" 
-     * true.  This will result in a lock request which will block on other
-     * processes which cannot work if rows move off the page or disappear.
-     * It is expected that the this routine will only be called for update
-     * by very short term internal transactions which will commit immediately
-     * after doing their work and give up the exclusive lock quickly.
-     * <p>
-     * Currently scans can position themselves in one of 2 ways, either by
-     * saving the record handle of a record when they give up the latch on 
-     * the page, or by saving the entire row.  If they save the record handle
-     * then they must call this routine with "forUpdate" false, to get a 
-     * lock which will protect the record handle they are using from moving
-     * off the page or disapearing.  This is also why aborts of inserts must
-     * be done by marking the rows deleted, rather than purging them.
-     * It is expected that scanner's will release this lock once they move
-     * off the page they are looking at.  They do this by calling 
-     * unlockScan().
-     * <p>
-     * This lock enforces the same lock/latch protocol as btree row locks.
-     * On return the lock has been obtained.  Return status indicates if the
-     * lock was waited for, which will mean a latch(s) were dropped while 
-     * waiting.
-     * In general a false status means that the caller will either have 
-     * to research the tree unless some protocol has been implemented that
-     * insures that the row will not have moved while the latch was dropped.
-     * <p>
-     * This routine requests a special row on the RECORD_ID_PROTECTION_HANDLE 
-     * row id.  If the lock is granted the routine will return true.
-     * If the lock cannot be granted NOWAIT, then the routine will release
-     * the latch on "current_leaf" and "aux_control_row" (if 
-     * aux_control_row is non-null), and then it will request a WAIT lock on 
-     * the row.  
-     *
-     * @param current_leaf      The lock is associated with this page in the
-     *                          btree.  This control row is unlatched if the
-     *                          routine has to wait on the lock.
-     * @param aux_control_row   If non-null, this control row is unlatched 
-     *                          if the routine has to wait on the lock.
-     * @param forUpdate         Whether to wait for lock.
-     * @param lock_operation    For what operation are we requesting the lock, 
-     *                          this should be one of the following 4 options:
-     *                          LOCK_READ [read lock], 
-     *                          (LOCK_INS | LOCK_UPD) [ lock for insert], 
-     *                          (LOCK_INSERT_PREVKEY | LOCK_UPD) [lock for 
-     *                          previous key to insert],
-     *                          (LOCK_UPD) [lock for delete or replace]
-     *
-	 * @exception  StandardException  Standard exception policy.
-     **/
-    abstract public boolean lockScan(
-    LeafControlRow          current_leaf,
-    ControlRow              aux_control_row,
-    boolean                 forUpdate,
-    int                     lock_operation)
-		throws StandardException;
-
-
-    /**
-     * Lock a control row page for reclaiming deleted rows.
-     * <p>
-     * When reclaiming deleted rows during split need to get an exclusive
-     * scan lock on the page, which will mean there are no other scans 
-     * positioned on the page.  If there are other scans positioned, just
-     * give up on reclaiming space now.
-     *
-	 * @return true if lock was granted nowait, else false and not lock was
-     *         granted.
-     *
-	 * @exception  StandardException  Standard exception policy.
-     **/
-    abstract public boolean lockScanForReclaimSpace(
-    LeafControlRow          current_leaf)
-		throws StandardException;
-
-    /**
      * Lock a btree row to determine if it is a committed deleted row.
      * <p>
      * Request an exclusive lock on the row located at the given slot, NOWAIT.
@@ -188,16 +104,12 @@
      * Lock a row as part of doing the scan.
      * <p>
      * Lock the row at the given slot (or the previous row if slot is 0).
-     * Get the scan lock on the page if "request_scan_lock" is true.
      * <p>
      * If this routine returns true all locks were acquired while maintaining
      * the latch on leaf.  If this routine returns false, locks may or may
      * not have been acquired, and the routine should be called again after
      * the client has researched the tree to reget the latch on the 
      * appropriate page.
-     * (p>
-     * As a side effect stores the value of the record handle of the current
-     * scan lock.
      *
 	 * @return Whether locks were acquired without releasing latch on leaf.
      *
@@ -205,8 +117,6 @@
      *                          used if routine has to scan backward.
      * @param btree             the conglomerate info.
      * @param pos               Description of position of row to lock.
-     * @param request_scan_lock Whether to request the page scan lock, should
-     *                          only be requested once per page in the scan.
      * @param lock_template     A scratch area to use to read in rows.
      * @param previous_key_lock Is this a previous key lock call?
      * @param forUpdate         Is the scan for update or for read only.
@@ -224,7 +134,6 @@
     OpenBTree               open_btree,
     BTree                   btree,
     BTreeRowPosition        pos,
-    boolean                 request_scan_lock,
     FetchDescriptor         lock_fetch_desc,
     DataValueDescriptor[]   lock_template,
     RowLocation             lock_row_loc,
@@ -248,19 +157,6 @@
     boolean                 forUpdate)
 		throws StandardException;
 
-    /**
-     * Release the lock gotten by calling lockScan.  This call can only be
-     * made to release read scan locks, write scan locks must be held until
-     * end of transaction.
-     * <p>
-     *
-     * @param protectionHandle a <code>RecordHandle</code> that, when locked,
-     * protects all the record ids on a page
-     * @see RecordHandle#RECORD_ID_PROTECTION_HANDLE
-     *
-     **/
-    abstract public void unlockScan(RecordHandle protectionHandle);
-
 
     /**************************************************************************
      * Abstract Protected lockNonScan*() locking methods of BTree:

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/btree/BTreeMaxScan.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/btree/BTreeMaxScan.java?rev=754894&r1=754893&r2=754894&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/btree/BTreeMaxScan.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/btree/BTreeMaxScan.java Mon Mar 16 13:55:49 2009
@@ -77,7 +77,6 @@
 	 * @exception  StandardException  Standard exception policy.
      **/
     private boolean fetchMaxRowFromBeginning(
-    BTreeRowPosition        pos,
     DataValueDescriptor[]   fetch_row)
         throws StandardException
 	{
@@ -99,6 +98,8 @@
             (DataValueDescriptor[]) null,
             ScanController.NA);
 
+        BTreeRowPosition pos = scan_position;
+
         positionAtStartForForwardScan(pos);
 
         // At this point:
@@ -111,8 +112,10 @@
         // seen.
 
         boolean nulls_not_reached = true;
+        leaf_loop:
 		while ((pos.current_leaf != null) && nulls_not_reached)
 		{
+            slot_loop:
 			while ((pos.current_slot + 1) < pos.current_leaf.page.recordCount())
 			{
                 // unlock the previous row if doing read.
@@ -145,7 +148,6 @@
                 boolean latch_released =
                     !this.getLockingPolicy().lockScanRow(
                         this, this.getConglomerate(), pos,
-                        false, 
                         init_lock_fetch_desc,
                         pos.current_lock_template,
                         pos.current_lock_row_loc,
@@ -157,7 +159,7 @@
                     latch_released = 
                         test_errors(
                             this,
-                            "BTreeMaxScan_fetchNextGroup", false, 
+                            "BTreeMaxScan_fetchNextGroup", pos,
                             this.getLockingPolicy(),
                             pos.current_leaf, latch_released);
                 }
@@ -172,20 +174,35 @@
                 if (latch_released)
                 {
                     // lost latch on page in order to wait for row lock.
-                    // Because we have scan lock on page, we need only
-                    // call reposition() which will use the saved record
+                    // Call reposition() which will use the saved record
                     // handle to reposition to the same spot on the page.
-                    // We don't have to search the
-                    // tree again, as we have the a scan lock on the page
-                    // which means the current_rh is valid to reposition on.
+                    // If the row is no longer on the page, reposition()
+                    // will take care of searching the tree and position
+                    // on the correct page.
                     if (!reposition(pos, false))
                     {
-                        if (SanityManager.DEBUG)
+                        // Could not position on the exact same row that was
+                        // saved, which means that it has been purged.
+                        // Reposition on the row immediately to the left of
+                        // the purged row instead.
+                        if (!reposition(pos, true))
                         {
-                            // can't fail while with scan lock
-                            SanityManager.THROWASSERT(
-                                "can not fail holding scan lock.");
+                            if (SanityManager.DEBUG)
+                            {
+                                SanityManager.THROWASSERT(
+                                        "Cannot fail with 2nd param true");
+                            }
+                            // reposition will set pos.current_leaf to null if
+                            // it returns false, so if this ever does fail in
+                            // delivered code, expect a NullPointerException at
+                            // the top of this loop when we call recordCount().
                         }
+
+                        // Now we're positioned to the left of our saved
+                        // position. Go to the top of the loop so that we move
+                        // the scan to the next row and release the lock on
+                        // the purged row.
+                        continue slot_loop;
                     }
                 }
 
@@ -285,7 +302,6 @@
             SanityManager.ASSERT(this.scan_state          == SCAN_INIT);
             SanityManager.ASSERT(pos.current_rh          == null);
             SanityManager.ASSERT(pos.current_positionKey         == null);
-            SanityManager.ASSERT(pos.current_scan_protectionHandle == null);
         }
 
         // Loop until you can lock the row previous to the first row to be
@@ -325,14 +341,12 @@
             // can be made depending on isolation level.
             // 
             // Note that this is not a "previous key" lock as the row we are
-            // locking is the max row to return.  Get the scan lock at the
-            // same time.
+            // locking is the max row to return.
 
             pos.current_slot--;
             boolean latch_released = 
                 !this.getLockingPolicy().lockScanRow(
                     this, this.getConglomerate(), pos,
-                    true, 
                     init_lock_fetch_desc,
                     pos.current_lock_template,
                     pos.current_lock_row_loc,
@@ -345,7 +359,7 @@
                 latch_released = 
                     test_errors(
                         this,
-                        "BTreeMaxScan_positionAtStartPosition", true,
+                        "BTreeMaxScan_positionAtStartPosition", pos,
                         this.getLockingPolicy(), pos.current_leaf, latch_released);
             }
 
@@ -363,8 +377,6 @@
         }
 
         this.scan_state          = SCAN_INPROGRESS;
-        pos.current_scan_protectionHandle =
-            pos.current_leaf.page.getProtectionRecordHandle();
 
         if (SanityManager.DEBUG)
             SanityManager.ASSERT(pos.current_leaf != null);
@@ -460,7 +472,6 @@
                 boolean latch_released =
                     !this.getLockingPolicy().lockScanRow(
                         this, this.getConglomerate(), pos, 
-                        false, 
                         init_lock_fetch_desc,
                         pos.current_lock_template,
                         pos.current_lock_row_loc,
@@ -531,7 +542,7 @@
         if (!max_found)
         {
             // max row in table was not last row in table
-            max_found = fetchMaxRowFromBeginning(scan_position, fetch_row);
+            max_found = fetchMaxRowFromBeginning(fetch_row);
         }
 
         return(max_found);

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/btree/BTreePostCommit.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/btree/BTreePostCommit.java?rev=754894&r1=754893&r2=754894&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/btree/BTreePostCommit.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/btree/BTreePostCommit.java Mon Mar 16 13:55:49 2009
@@ -384,6 +384,10 @@
                             }
 
                             page.purgeAtSlot(slot_no, 1, true);
+                            // Tell scans positioned on this page to reposition
+                            // because the row they are positioned on may have
+                            // disappeared.
+                            page.setRepositionNeeded();
 
                             if (SanityManager.DEBUG)
                             {
@@ -474,17 +478,12 @@
             int num_possible_commit_delete = 
                 leaf.page.recordCount() - 1 - leaf.page.nonDeletedRecordCount();
 
-            if ((num_possible_commit_delete > 0) &&
-                (btree_locking_policy.lockScanForReclaimSpace(leaf)))
+            if (num_possible_commit_delete > 0)
             {
                 DataValueDescriptor[] scratch_template = 
                     open_btree.getRuntimeMem().get_template(
                         open_btree.getRawTran());
 
-                // Need to get an exclusive scan lock on the page before we can
-                // do any sort of purges, otherwise other concurrent scans would
-                // not work.  If we can't get the lock NOWAIT, just give up on
-                // purging rows. 
                 Page page   = leaf.page;
 
 
@@ -511,6 +510,10 @@
                         {
                             // the row is a committed deleted row, purge it.
                             page.purgeAtSlot(slot_no, 1, true);
+                            // Tell scans positioned on this page to reposition
+                            // because the row they are positioned on may have
+                            // disappeared.
+                            page.setRepositionNeeded();
                         }
                     }
                 }

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/btree/BTreeRowPosition.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/btree/BTreeRowPosition.java?rev=754894&r1=754893&r2=754894&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/btree/BTreeRowPosition.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/btree/BTreeRowPosition.java Mon Mar 16 13:55:49 2009
@@ -22,13 +22,15 @@
 package org.apache.derby.impl.store.access.btree;
 
 
+import org.apache.derby.iapi.error.StandardException;
+import org.apache.derby.iapi.services.io.FormatableBitSet;
 import org.apache.derby.iapi.services.sanity.SanityManager;
 
 import org.apache.derby.iapi.store.raw.Page;
-import org.apache.derby.iapi.store.raw.RecordHandle;
 
 import org.apache.derby.iapi.store.access.RowUtil;
 
+import org.apache.derby.iapi.store.raw.FetchDescriptor;
 import org.apache.derby.iapi.types.DataValueDescriptor;
 
 import org.apache.derby.iapi.types.RowLocation;
@@ -46,19 +48,39 @@
      **************************************************************************
      */
     public    DataValueDescriptor[] current_positionKey;
-    public    RecordHandle          current_scan_protectionHandle;
     public    LeafControlRow        current_leaf;
     protected LeafControlRow        next_leaf;
     public    DataValueDescriptor[] current_lock_template;
     public    RowLocation           current_lock_row_loc;
 
+    /** The scan that owns this position object. */
+    private final BTreeScan parent;
+
+    /**
+     * The version number of the leaf page when this position was saved by
+     * key. Only valid if {@link #current_positionKey} is non-null. This value
+     * is used to decide whether repositioning should be performed by using
+     * the key, or if {@link #current_rh} could be used directly.
+     */
+    long versionWhenSaved;
+
+    /** Cached template for saving this position by key. */
+    private DataValueDescriptor[] positionKey_template;
+
+    /**
+     * Cached fetch descriptor that can be used to fetch the key columns that
+     * are not already fetched by the scan. The fetch descriptor is used when
+     * this position is about to be saved by its full key.
+     */
+    private FetchDescriptor savedFetchDescriptor;
+
     /**************************************************************************
      * Constructors for This class:
      **************************************************************************
      */
-    public BTreeRowPosition()
+    public BTreeRowPosition(BTreeScan parent)
     {
-        super();
+        this.parent = parent;
     }
 
     /**************************************************************************
@@ -80,6 +102,12 @@
 
     public final void unlatch()
     {
+        // This method is never called for a BTreeRowPosition. If it is ever
+        // used, make sure that the key is saved first, unless the scan won't
+        // use that page again. DERBY-2991
+        if (SanityManager.DEBUG) {
+            SanityManager.THROWASSERT("Did you really call me?!?");
+        }
         if (current_leaf != null)
         {
             current_leaf.release();
@@ -88,6 +116,83 @@
         current_slot = Page.INVALID_SLOT_NUMBER;
     }
 
+    /**
+     * Save this position by key and release the latch on the current leaf.
+     * @throws StandardException if an error occurs while saving the position
+     * @see BTreeScan#savePositionAndReleasePage()
+     */
+    public void saveMeAndReleasePage() throws StandardException {
+        if (SanityManager.DEBUG) {
+            SanityManager.ASSERT(parent.scan_position == this);
+        }
+        parent.savePositionAndReleasePage();
+    }
+
+    /**
+     * Get a template into which the position key can be copied. The value
+     * is cached, so two calls to this method on the same object will return
+     * the same object.
+     *
+     * @return an array into which the position key can be copied
+     * @throws StandardException if an error occurs while allocating the
+     * template array
+     */
+    DataValueDescriptor[] getKeyTemplate() throws StandardException {
+        if (positionKey_template == null) {
+            positionKey_template = parent.getRuntimeMem().
+                    get_row_for_export(parent.getRawTran());
+        }
+        return positionKey_template;
+    }
+
+    /**
+     * Get a fetch descriptor that can be used to fetch the missing columns
+     * in a partial key. The fetch descriptor is only created on the first
+     * call to this method. The returned descriptor will be cached, so
+     * subsequent calls will return the same descriptor and the arguments
+     * to this method should be the same between invokations.
+     *
+     * @param vcols an array which tells which columns the partial key contains
+     * (valid columns have non-zero values in the array)
+     * @param fullLength the length of the full key to create a fetch
+     * descriptor for (may be greater than {@code vcols.length})
+     * @return a fetch descriptor
+     */
+    FetchDescriptor getFetchDescriptorForSaveKey(int[] vcols, int fullLength) {
+        if (savedFetchDescriptor == null) {
+            FormatableBitSet columns = new FormatableBitSet(fullLength);
+            for (int i = 0; i < vcols.length; i++) {
+                if (vcols[i] == 0) {
+                    // partial key does not have a valid value for this
+                    // column, add it to the set of columns to fetch
+                    columns.set(i);
+                }
+            }
+            // also fetch the columns behind the ones in the partial key
+            for (int i = vcols.length; i < fullLength; i++) {
+                columns.set(i);
+            }
+            savedFetchDescriptor =
+                    new FetchDescriptor(fullLength, columns, null);
+        }
+
+        // Verify that the cached fetch descriptor matches the arguments
+        // (will fail if this method is not called with the same parameters
+        // as when the descriptor was created and cached).
+        if (SanityManager.DEBUG) {
+            FormatableBitSet fetchCols = savedFetchDescriptor.getValidColumns();
+            SanityManager.ASSERT(fullLength == fetchCols.size());
+            for (int i = 0; i < vcols.length; i++) {
+                SanityManager.ASSERT((vcols[i] == 0) == fetchCols.get(i));
+            }
+            for (int i = vcols.length; i < fullLength; i++) {
+                SanityManager.ASSERT(fetchCols.get(i));
+            }
+        }
+
+        return savedFetchDescriptor;
+    }
+
     public final String toString()
     {
         String ret_string = null;
@@ -98,8 +203,6 @@
                 super.toString() + 
                 "current_positionKey = " + current_positionKey + 
                 ";key = " + RowUtil.toString(current_positionKey) + 
-                ";current_scan_protectionHandle" +
-                current_scan_protectionHandle +
                 ";next_leaf" + next_leaf + 
                 ";current_leaf" + current_leaf;
         }

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/btree/BTreeScan.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/btree/BTreeScan.java?rev=754894&r1=754893&r2=754894&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/btree/BTreeScan.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/btree/BTreeScan.java Mon Mar 16 13:55:49 2009
@@ -27,7 +27,6 @@
 
 import org.apache.derby.iapi.error.StandardException;
 
-import org.apache.derby.iapi.store.access.conglomerate.Conglomerate;
 import org.apache.derby.iapi.store.access.conglomerate.LogicalUndo;
 import org.apache.derby.iapi.store.access.conglomerate.ScanManager;
 import org.apache.derby.iapi.store.access.conglomerate.TransactionManager;
@@ -257,7 +256,7 @@
 
         // reset the "current" position to starting condition.
         // RESOLVE (mmm) - "compile" this.
-        scan_position = new BTreeRowPosition();
+        scan_position = new BTreeRowPosition(this);
 
         scan_position.init();
 
@@ -348,7 +347,6 @@
                 (scan_state == SCAN_INIT) || (scan_state == SCAN_HOLD_INIT));
             SanityManager.ASSERT(pos.current_rh          == null);
             SanityManager.ASSERT(pos.current_positionKey == null);
-            SanityManager.ASSERT(pos.current_scan_protectionHandle == null);
         }
 
         // Loop until you can lock the row previous to the first row to be
@@ -436,25 +434,12 @@
                 latch_released = 
                     !this.getLockingPolicy().lockScanRow(
                         this, this.getConglomerate(), pos,
-                        true, 
                         init_lock_fetch_desc,
                         pos.current_lock_template,
                         pos.current_lock_row_loc,
                         true, init_forUpdate, 
                         lock_operation);
             }
-            else
-            {
-                // Don't need to lock the "previous key" but still need to get
-                // the scan lock to protect the position in the btree.
-
-                latch_released =
-                    !this.getLockingPolicy().lockScan(
-                        pos.current_leaf,   // the page we are positioned on.
-                        (ControlRow) null,  // no other page to unlatch
-                        false,              // lock for read.
-                        lock_operation);    // not used.
-            }
 
             // special test to see if latch release code works
             if (SanityManager.DEBUG)
@@ -462,7 +447,9 @@
                 latch_released = 
                     test_errors(
                         this,
-                        "BTreeScan_positionAtStartPosition", true,
+                        "BTreeScan_positionAtStartPosition",
+                        null, // no need to save the position, since we'll
+                              // retry the operation if the latch is released
                         this.getLockingPolicy(), 
                         pos.current_leaf, latch_released);
             }
@@ -481,8 +468,6 @@
         }
 
         this.scan_state         = SCAN_INPROGRESS;
-        pos.current_scan_protectionHandle =
-            pos.current_leaf.page.getProtectionRecordHandle();
 
         if (SanityManager.DEBUG)
             SanityManager.ASSERT(pos.current_leaf != null);
@@ -514,7 +499,6 @@
 
             SanityManager.ASSERT(pos.current_rh          == null);
             SanityManager.ASSERT(pos.current_positionKey         == null);
-            SanityManager.ASSERT(pos.current_scan_protectionHandle == null);
         }
 
         // Loop until you can lock the row previous to the first row to be
@@ -609,7 +593,6 @@
             boolean latch_released = 
                 !this.getLockingPolicy().lockScanRow(
                     this, this.getConglomerate(), pos,
-                    true, 
                     init_lock_fetch_desc,
                     pos.current_lock_template,
                     pos.current_lock_row_loc,
@@ -621,7 +604,7 @@
                 latch_released = 
                     test_errors(
                         this,
-                        "BTreeScan_positionAtStartPosition", true,
+                        "BTreeScan_positionAtStartPosition", pos,
                         this.getLockingPolicy(), pos.current_leaf, latch_released);
             }
 
@@ -639,8 +622,6 @@
         }
 
         this.scan_state          = SCAN_INPROGRESS;
-        pos.current_scan_protectionHandle =
-            pos.current_leaf.page.getProtectionRecordHandle();
 
         if (SanityManager.DEBUG)
             SanityManager.ASSERT(pos.current_leaf != null);
@@ -654,8 +635,7 @@
      * <p>
      * Position to next page, keeping latch on previous page until we have 
      * latch on next page.  This routine releases the latch on current_page
-     * once it has successfully gotten both the latch on the next page and
-     * the scan lock on the next page.
+     * once it has successfully gotten the latch on the next page.
      *
      * @param pos           current row position of the scan.
      *
@@ -665,55 +645,11 @@
     BTreeRowPosition    pos)
         throws StandardException
     {
-        // RESOLVE (mikem) - not sure but someday in the future this
-        // assert may not be true, but for now we always have the scan
-        // lock when we call this routine.
-        if (SanityManager.DEBUG)
-            SanityManager.ASSERT(pos.current_scan_protectionHandle != null);
-
-        while (true)
-        {
-            if ((pos.next_leaf = 
-                 (LeafControlRow) pos.current_leaf.getRightSibling(this)) == null)
-            {
-                break;
-            }
 
-            boolean latch_released = 
-                !this.getLockingPolicy().lockScan(
-                    pos.next_leaf,
-                    (LeafControlRow) null, // no other latch currently
-                    false /* not for update */,
-                    ConglomerateController.LOCK_READ); // get read scan lock.
-
-            // TESTING CODE:
-            if (SanityManager.DEBUG)
-            {
-                latch_released = 
-                    test_errors(
-                        this,
-                        "BTreeScan_positionAtNextPage", true,
-                        this.getLockingPolicy(), pos.next_leaf, latch_released);
-            }
-
-            if (!latch_released)
-            {
-                break;
-            }
-        }
+        pos.next_leaf = (LeafControlRow) pos.current_leaf.getRightSibling(this);
 
-        // Now that we either have both latch and scan lock on next leaf, or 
-        // there is no next leaf we can release scan and latch on current page.
-        if (SanityManager.DEBUG)
-        {
-			if (pos.current_scan_protectionHandle.getPageNumber() !=
-                         pos.current_leaf.page.getPageNumber()) {
-				SanityManager.THROWASSERT(
-                "pos.current_scan_protectionHandle = " +
-                pos.current_scan_protectionHandle +
-                "pos.current_leaf = " + pos.current_leaf);
-            }
-        }
+        // Now that we either have the latch on next leaf, or there is no next
+        // leaf, we can release the latch on the current page.
 
         // unlock the previous row if doing read.
         if (pos.current_rh != null)
@@ -722,14 +658,9 @@
                 pos, init_forUpdate);
         }
 
-        unlockCurrentScan(pos);
         pos.current_leaf.release();
         pos.current_leaf        = pos.next_leaf;
 
-        pos.current_scan_protectionHandle =
-            (pos.current_leaf == null) ?
-            null : pos.current_leaf.page.getProtectionRecordHandle();
-
         // set up for scan to continue at beginning of next page.
         pos.current_slot        = Page.FIRST_SLOT_NUMBER;
         pos.current_rh          = null;
@@ -782,34 +713,11 @@
                 // unlock (thus why we only do the following code if we
                 // "don't" have lock, ie. pos.current_leaf== null).
 
-                if (!reposition(pos, false))
-                {
-                    if (SanityManager.DEBUG)
-                    {
-                        SanityManager.THROWASSERT(
-                            "can not fail while holding update row lock.");
-                    }
-                }
-
                 this.getLockingPolicy().unlockScanRecordAfterRead(
                     pos, init_forUpdate);
-
-                pos.current_rh   = null;
-                pos.current_leaf.release();
-                pos.current_leaf = null;
             }
         }
 
-
-        // Need to do this unlock in any case, until lock manager provides
-        // a way to release locks associated with a compatibility space.  This
-        // scan lock is special, as it is a lock on the btree container rather
-        // than the heap container.  The open container on the btree actually
-        // has a null locking policy so the close of that container does not
-        // release this lock, need to explicitly unlock it here or when the
-        // scan is closed as part of the abort the lock will not be released.
-        unlockCurrentScan(pos);
-
         pos.current_slot = Page.INVALID_SLOT_NUMBER;
         pos.current_rh   = null;
         pos.current_positionKey  = null;
@@ -835,15 +743,6 @@
         throws StandardException
     {
 
-        // Need to do this unlock in any case, until lock manager provides
-        // a way to release locks associated with a compatibility space.  This
-        // scan lock is special, as it is a lock on the btree container rather
-        // than the heap container.  The open container on the btree actually
-        // has a null locking policy so the close of that container does not
-        // release this lock, need to explicitly unlock it here or when the
-        // scan is closed as part of the abort the lock will not be released.
-        unlockCurrentScan(pos);
-
         pos.current_slot        = Page.INVALID_SLOT_NUMBER;
         pos.current_rh          = null;
         pos.current_positionKey = null;
@@ -1000,8 +899,7 @@
      *       scan it is necessary to research the tree from the top using
      *       the copy of the row.
      *
-     * If the scan has saved it's position by key (and thus has given up the
-     * scan lock on the page), there are a few cases where it is possible that
+     * There are a few cases where it is possible that
      * the key no longer exists in the table.  In the case of a scan held 
      * open across commit it is easy to imagine that the row the scan was 
      * positioned on could be deleted and subsequently purged from the table 
@@ -1011,7 +909,7 @@
      * opens scan and positions on row (1,2), transaction 2 deletes (1,2) and
      * commits, transaction 1 inserts (1,3) which goes to same page as (1,2)
      * and is going to cause a split, transaction 1 saves scan position as
-     * key, gives up scan lock and then purges row (1, 2), when transaction 
+     * key, and then purges row (1, 2), when transaction
      * 1 resumes scan (1, 2) no longer exists.  missing_row_for_key_ok 
      * parameter is added as a sanity check to make sure it ok that 
      * repositioning does not go to same row that we were repositioned on.
@@ -1048,17 +946,17 @@
                 new Integer(this.scan_state));
         }
 
-        // Either current_rh or positionKey is valid - the other is null.
+        // positionKey is always valid
         if (SanityManager.DEBUG)
         {
-			if ((pos.current_rh == null) != (pos.current_positionKey != null))
+            if (pos.current_positionKey == null)
             	SanityManager.THROWASSERT(
                 	"pos.current_rh  = (" + pos.current_rh + "), " +
                 	"pos.current_positionKey = (" + 
                     pos.current_positionKey + ").");
         }
 
-        if (!((pos.current_rh == null) == (pos.current_positionKey != null)))
+        if (pos.current_positionKey == null)
         {
             throw StandardException.newException(
                     SQLState.BTREE_SCAN_INTERNAL_ERROR, 
@@ -1066,102 +964,72 @@
                     new Boolean(pos.current_positionKey == null));
         }
 
-        if (pos.current_positionKey == null)
+        // If current_rh is non-null, we know the exact physical position of
+        // the scan before the latch on the leaf was released. Check if the
+        // row is still on that position so that we don't need to renavigate
+        // from the root of the B-tree in the common case.
+        if (pos.current_rh != null)
         {
             // Reposition to remembered spot on page.
-            if (SanityManager.DEBUG)
-                SanityManager.ASSERT(pos.current_scan_protectionHandle != null);
 
-            pos.current_leaf = (LeafControlRow)
-                ControlRow.get(this, pos.current_rh.getPageNumber());
-            pos.current_slot =
-                pos.current_leaf.page.getSlotNumber(pos.current_rh);
+            // Get the page object. If getPage() returns null, the page is
+            // not valid (could for instance have been removed by compress
+            // table) so we need to reposition by key instead.
+            Page page = container.getPage(pos.current_rh.getPageNumber());
+            if (page != null) {
+                ControlRow row =
+                        ControlRow.getControlRowForPage(container, page);
+                if (row instanceof LeafControlRow &&
+                        !row.page.isRepositionNeeded(pos.versionWhenSaved)) {
+                    // No rows have been moved off the page after we released
+                    // the latch, and the page is still a leaf page. No need
+                    // to reposition by key.
+                    pos.current_leaf = (LeafControlRow) row;
+                    pos.current_slot = row.page.getSlotNumber(pos.current_rh);
+                    pos.current_positionKey = null;
+                    return true;
+                }
+                // We couldn't use the position specified by current_rh, so we
+                // need to reposition by key and may find the row on another
+                // page. Therefore, give up the latch on this page.
+                row.release();
+            }
         }
-        else
-        {
-            // RESOLVE (mikem) - not sure but someday in the future this
-            // assert may not be true, but for now we always release the 
-            // scan lock when we save the row away as the current position.
-            if (SanityManager.DEBUG)
-                SanityManager.ASSERT(pos.current_scan_protectionHandle == null);
 
-            SearchParameters sp =
+        SearchParameters sp =
                 new SearchParameters(
                     pos.current_positionKey, 
                     // this is a full key search, so this arg is not used.
                     SearchParameters.POSITION_LEFT_OF_PARTIAL_KEY_MATCH,
                     init_template, this, false);
 
-            // latch/lock loop, continue until you can get scan lock on page
-            // while holding page latched without waiting.
-
-
-            boolean latch_released;
-            do
-            {
-                pos.current_leaf = (LeafControlRow)
+        pos.current_leaf = (LeafControlRow)
                     ControlRow.get(this, BTree.ROOTPAGEID).search(sp);
 
-                if (sp.resultExact || missing_row_for_key_ok)
-                {
-                    // RESOLVE (mikem) - we could have a scan which always 
-                    // maintained it's position by key value, or we could 
-                    // optimize and delay this lock until we were about to 
-                    // give up the latch.  But it is VERY likely we will get 
-                    // the lock since we have the latch on the page.
-                    //
-                    // In order to be successfully positioned we must get the 
-                    // scan lock again.
-                    latch_released = 
-                        !this.getLockingPolicy().lockScan(
-                            pos.current_leaf, 
-                            (LeafControlRow) null, // no other latch currently
-                            false /* not for update */,
-                            ConglomerateController.LOCK_READ); // read lock on scan position
-
-                    // TESTING CODE:
-                    if (SanityManager.DEBUG)
-                    {
-                        latch_released = 
-                            test_errors(
-                                this,
-                                "BTreeScan_reposition", true, 
-                                this.getLockingPolicy(),
-                                pos.current_leaf, latch_released);
-                    }
-                }
-                else
-                {
-                    // Did not find key to exactly position on.
+        if (!sp.resultExact && !missing_row_for_key_ok)
+        {
+            // Did not find key to exactly position on.
 
-                    pos.current_leaf.release();
-                    pos.current_leaf = null;
-                    return(false);
-                }
+            pos.current_leaf.release();
+            pos.current_leaf = null;
+            return (false);
+        }
 
-            } while (latch_released);
+        pos.current_slot = sp.resultSlot;
 
-            pos.current_scan_protectionHandle =
-                pos.current_leaf.page.getProtectionRecordHandle();
-            pos.current_slot        = sp.resultSlot;
-            pos.current_positionKey = null;
+        // Need to update current_rh to the new position. current_rh should
+        // only be non-null if the row was locked when the position was saved,
+        // so we don't set it here if its old value is null.
+        if (pos.current_rh != null) {
+            pos.current_rh = pos.current_leaf.page.
+                    getRecordHandleAtSlot(pos.current_slot);
         }
 
+        pos.current_positionKey = null;
+
         return(true);
 	}
 
-    /**
-     * Unlock the scan protection row for the current scan.
-     *
-     * @param pos position of the scan
-     */
-    private void unlockCurrentScan(BTreeRowPosition pos) {
-        if (pos.current_scan_protectionHandle != null) {
-            getLockingPolicy().unlockScan(pos.current_scan_protectionHandle);
-            pos.current_scan_protectionHandle = null;
-        }
-    }
-
 	/*
 	** Public Methods of BTreeScan
 	*/
@@ -1340,7 +1208,6 @@
                 boolean latch_released =
                     !this.getLockingPolicy().lockScanRow(
                         this, this.getConglomerate(), scan_position,
-                        false, 
                         init_lock_fetch_desc,
                         scan_position.current_lock_template,
                         scan_position.current_lock_row_loc,
@@ -1349,12 +1216,9 @@
                 if (latch_released)
                 {
                     // lost latch on page in order to wait for row lock.
-                    // Because we have scan lock on page, we need only
-                    // call reposition() which will use the saved record
-                    // handle to reposition to the same spot on the page.
-                    // We don't have to search the
-                    // tree again, as we have the a scan lock on the page
-                    // which means the current_rh is valid to reposition on.
+                    // reposition() will take care of the complexity of
+                    // positioning on the correct page if the row has been
+                    // moved to another page.
                     if (reposition(scan_position, false))
                     {
                         throw StandardException.newException(
@@ -1414,8 +1278,7 @@
             if (scan_position.current_leaf != null)
             {
                 // release latch on page
-                scan_position.current_leaf.release();
-                scan_position.current_leaf = null;
+                savePositionAndReleasePage();
             }
         }
 
@@ -1515,8 +1378,7 @@
             if (scan_position.current_leaf != null)
             {
                 // release latch on page.
-                scan_position.current_leaf.release();
-                scan_position.current_leaf = null;
+                savePositionAndReleasePage();
             }
         }
     }
@@ -1592,8 +1454,7 @@
             if (scan_position.current_leaf != null)
             {
                 // release latch on page.
-                scan_position.current_leaf.release();
-                scan_position.current_leaf = null;
+                savePositionAndReleasePage();
             }
         }
 
@@ -1707,8 +1568,7 @@
             if (scan_position.current_leaf != null)
             {
                 // release latch on page.
-                scan_position.current_leaf.release();
-                scan_position.current_leaf = null;
+                savePositionAndReleasePage();
             }
         }
 
@@ -2097,35 +1957,10 @@
         
         if (scan_position.current_rh != null)
         {
-            // reposition to get record handle if we don't have it.
-
-            if (!reposition(scan_position, false))
-            {
-                if (SanityManager.DEBUG)
-                {
-                    SanityManager.THROWASSERT(
-                        "can not fail while holding update row lock.");
-                }
-            }
-
             this.getLockingPolicy().unlockScanRecordAfterRead(
                 scan_position, init_forUpdate);
-
-            scan_position.current_rh   = null;
-            scan_position.current_leaf.release();
-            scan_position.current_leaf = null;
         }
 
-
-        // Need to do this unlock in any case, until lock manager provides
-        // a way to release locks associated with a compatibility space.  This
-        // scan lock is special, as it is a lock on the btree container rather
-        // than the heap container.  The open container on the btree actually
-        // has a null locking policy so the close of that container does not
-        // release this lock, need to explicitly unlock it here or when the
-        // scan is closed as part of the abort the lock will not be released.
-        unlockCurrentScan(scan_position);
-
         scan_position.current_slot = Page.INVALID_SLOT_NUMBER;
         scan_position.current_rh   = null;
         scan_position.current_positionKey  = null;
@@ -2263,16 +2098,16 @@
                 if (SanityManager.DEBUG)
                 {
                     SanityManager.ASSERT(scan_position != null);
+                    SanityManager.ASSERT(
+                            scan_position.current_positionKey != null,
+                            "Position must be saved by key when tx ends");
                 }
 
-                if (scan_position.current_positionKey == null)
-                {
-                    // save position of scan by key rather than location so 
-                    // that we can recover if the page with the position 
-                    // disappears while we don't have a scan lock.
+                // When the transaction ends, we release all the locks
+                // obtained in this scan, so the row we're positioned on is
+                // no longer locked.
+                scan_position.current_rh = null;
 
-                    savePosition();
-                }
                 this.scan_state = SCAN_HOLD_INPROGRESS;
             }
             else if (this.scan_state == SCAN_INIT)
@@ -2287,181 +2122,95 @@
 	}
 
     /**
-     * Do work necessary to maintain the current position in the scan.
-     * <p>
-     * Save the current position of the scan as a key.
-     * Do whatever is necessary to maintain the current position of the scan.
-     * For some conglomerates this may be a no-op.
-     *
-     * <p>
-	 * @exception  StandardException  Standard exception policy.
-     **/
-    private void savePosition()
-		throws StandardException
-    {
-        if (this.scan_state == SCAN_INPROGRESS)
-        {
-            // Either current_rh or positionKey is valid - the other is null.
-            if (SanityManager.DEBUG)
-            {
-                SanityManager.ASSERT(
-                    (scan_position.current_rh == null) == 
-                    (scan_position.current_positionKey != null));
+     * Save the current scan position by key and release the latch on the leaf
+     * that's being scanned. This method should be called if the latch on a
+     * leaf needs to be released in the middle of the scan. The scan can
+     * later reposition to the saved position by calling {@code reposition()}.
+     *
+     * @param partialKey known parts of the key that should be saved, or
+     * {@code null} if the entire key is unknown and will have to be fetched
+     * from the page
+     * @param vcols an array which tells which columns of the partial key are
+     * valid (key columns that have 0 in this array are not valid, and their
+     * values must be fetched from the page), or {@code null} if all the
+     * columns are valid
+     * @throws StandardException if an error occurs while saving the position
+     * @see #reposition(BTreeRowPosition, boolean)
+     */
+    void savePositionAndReleasePage(DataValueDescriptor[] partialKey,
+                                    int[] vcols)
+            throws StandardException {
+
+        final Page page = scan_position.current_leaf.getPage();
+
+        if (SanityManager.DEBUG) {
+            SanityManager.ASSERT(page.isLatched(), "Page is not latched");
+            SanityManager.ASSERT(scan_position.current_positionKey == null,
+                                 "Scan position already saved");
+
+            if (partialKey == null) {
+                SanityManager.ASSERT(vcols == null);
+            }
+            if (vcols != null) {
+                SanityManager.ASSERT(partialKey != null);
+                SanityManager.ASSERT(vcols.length <= partialKey.length);
             }
+        }
 
-            try
-            {
-                if (scan_position.current_rh != null)
-                {
-                    // if scan position is not saved by key, then make it so.
-
-                    // must reposition to get the page latched.
-
-                    if (reposition(scan_position, false))
-                    {
-                        scan_position.current_positionKey = 
-                            runtime_mem.get_row_for_export(getRawTran());
-
-
-                        Page page = scan_position.current_leaf.getPage();
-
-
-                        RecordHandle rh =
-                            page.fetchFromSlot(
-                                (RecordHandle) null,
-                                page.getSlotNumber(scan_position.current_rh), 
-                                scan_position.current_positionKey, 
-                                (FetchDescriptor) null,
-                                true);
-
-                        if (SanityManager.DEBUG)
-                        {
-                            SanityManager.ASSERT(rh != null);
-                        }
-
-                        scan_position.current_rh = null;
-                        scan_position.current_slot = Page.INVALID_SLOT_NUMBER;
-
-                        // release scan lock now that the row is saved away.
-                        unlockCurrentScan(scan_position);
-
-                    }
-                    else
-                    {
-                        // this should never happen as we hold the scan lock
-                        // on the page while maintaining the position by 
-                        // recordhandle - reposition should always work in this
-                        // case.
-
-                        if (SanityManager.DEBUG)
-                            SanityManager.THROWASSERT(
-                                "Must always be able to reposition.");
+        try {
+            DataValueDescriptor[] fullKey = scan_position.getKeyTemplate();
+
+            FetchDescriptor fetchDescriptor = null;
+            boolean haveAllColumns = false;
+            if (partialKey != null) {
+                int copiedCols = 0;
+                final int partialKeyLength =
+                        (vcols == null) ? partialKey.length : vcols.length;
+                for (int i = 0; i < partialKeyLength; i++) {
+                    if (vcols == null || vcols[i] != 0) {
+                        fullKey[i].setValue(partialKey[i]);
+                        copiedCols++;
                     }
                 }
-
-            }
-            finally
-            {
-
-                if (scan_position.current_leaf != null)
-                {
-                    // release latch on page
-                    scan_position.current_leaf.release();
-                    scan_position.current_leaf = null;
+                if (copiedCols < fullKey.length) {
+                    fetchDescriptor =
+                            scan_position.getFetchDescriptorForSaveKey(
+                            vcols, fullKey.length);
+                } else {
+                    haveAllColumns = true;
                 }
             }
-        }
-
-    }
-
-    /**
-     * Do work necessary to maintain the current position in the scan.
-     * <p>
-     * The latched page in the conglomerate "congomid" is changing, do
-     * whatever is necessary to maintain the current position of the scan.
-     * For some conglomerates this may be a no-op.
-     * <p>
-     *
-     * @param conglom  Conglomerate object of the conglomerate being changed.
-     * @param page      Page in the conglomerate being changed.
-     *
-	 * @exception  StandardException  Standard exception policy.
-     **/
-    public void savePosition(Conglomerate conglom, Page page)
-        throws StandardException
-	{
-        // page should be latched by split.  This scan is assuming that latch
-        // and reading off it's key from the page under the split's latch.
-        // A lock should have already been gotten on this row.
-
-
-        if (SanityManager.DEBUG)
-        {
-            SanityManager.ASSERT(page.isLatched());
-        }
-
-        /*
-        System.out.println(
-            "Saving position in btree at top: " +
-            " this.conglomerate = " +  this.conglomerate        +
-            " this.scan_state   = " +  this.scan_state);
-        SanityManager.DEBUG_PRINT("savePosition()", 
-            "Saving position in btree at top: " +
-            " this.conglomerate = " +  this.conglomerate        +
-            " this.scan_state   = " +  this.scan_state);
-        */
 
-
-        if ((this.getConglomerate() == conglom) &&
-            (this.scan_state == SCAN_INPROGRESS))
-        {
-            // Either current_rh or positionKey is valid - the other is null.
-            if (SanityManager.DEBUG)
-            {
-                SanityManager.ASSERT(
-                    (scan_position.current_rh == null) == 
-                    (scan_position.current_positionKey != null));
-            }
-
-            /*
-            SanityManager.DEBUG_PRINT("savePosition()", 
-                "Saving position in btree: " +
-                ";current_scan_pageno = " + this.current_scan_pageno +
-                "this.current_rh = " + this.current_rh +
-                ";page.getPageNumber() = " + page.getPageNumber() +
-                ((this.current_rh != null) ?
-                    (";this.current_rh.getPageNumber() = " +
-                     this.current_rh.getPageNumber()) : ""));
-            */
-
-            if (scan_position.current_rh != null &&
-                page.getPageNumber() == 
-                    scan_position.current_rh.getPageNumber())
-            {
-                scan_position.current_positionKey = 
-                    runtime_mem.get_row_for_export(getRawTran());
-
-                RecordHandle rh =
-                    page.fetchFromSlot(
+            if (!haveAllColumns) {
+                RecordHandle rh = page.fetchFromSlot(
                         (RecordHandle) null,
-                        page.getSlotNumber(scan_position.current_rh), 
-                        scan_position.current_positionKey, 
-                        (FetchDescriptor) null,
+                        scan_position.current_slot,
+                        fullKey,
+                        fetchDescriptor,
                         true);
 
-                if (SanityManager.DEBUG)
-                {
-                    SanityManager.ASSERT(rh != null);
+                if (SanityManager.DEBUG) {
+                    SanityManager.ASSERT(rh != null, "Row not found");
                 }
+            }
 
-                scan_position.current_rh = null;
-                scan_position.current_slot = Page.INVALID_SLOT_NUMBER;
+            scan_position.current_positionKey = fullKey;
+            // Don't null out current_rh, we might be able to use it later if
+            // no rows are moved off the page.
+            //scan_position.current_rh = null;
+            scan_position.versionWhenSaved = page.getPageVersion();
+            scan_position.current_slot = Page.INVALID_SLOT_NUMBER;
 
-                // release the scan lock now that we have saved away the row.
-                unlockCurrentScan(scan_position);
-            }
+        } finally {
+            scan_position.current_leaf.release();
+            scan_position.current_leaf = null;
         }
-	}
+    }
+
+    /** Shortcut for for savePositionAndReleasePage(null,null). */
+    void savePositionAndReleasePage() throws StandardException {
+        savePositionAndReleasePage(null, null);
+    }
 
     public RecordHandle getCurrentRecordHandleForDebugging()
     {

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/btree/LeafControlRow.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/btree/LeafControlRow.java?rev=754894&r1=754893&r2=754894&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/btree/LeafControlRow.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/btree/LeafControlRow.java Mon Mar 16 13:55:49 2009
@@ -629,38 +629,6 @@
                     branchrow.getRow(), splitrow, flag));
 
         }
-        // Before moving the rows on the page, while having the latch on the
-        // page, notify btree scans that the rows on this page may be moving
-        // onto another page.
-        //
-        // RESOLVE (mikem) - need to pass conlgomid.
-        // RESOLVE (mikem) - some optimization later, we only need to notify
-        // the scans which are positioned on moving rows.
-        if (SanityManager.DEBUG)
-            SanityManager.ASSERT(open_btree.init_open_user_scans != null);
-
-        open_btree.init_open_user_scans.saveScanPositions(
-                open_btree.getConglomerate(), this.page);
-
-        // Get exclusive RECORD_ID_PROTECTION_HANDLE lock to make sure that
-        // we wait for scans in other transactions to move off of this page
-        // before we split.
-
-        if (!open_btree.getLockingPolicy().lockScan(
-                this, parent_page, true /* for update */, 
-                ConglomerateController.LOCK_UPD))
-        {
-            // we had to give up latches on this and parent_page to get the
-            // split lock.  Redo the whole split pass as we have lost our
-            // latches.  Just returning is ok, as the caller can not assume
-            // that split has succeeded in making space.  Note that at this
-            // point in the split no write work has been done in the current
-            // internal transaction, so giving up here is fairly cheap.
-
-            // RESOLVE RLL PERFORMANCE - we could keep a stack of visited
-            // pages so as to not have to redo the complete search.
-            return(current_leaf_pageno);
-        }
 
         // Create a new leaf page under the parent.
         LeafControlRow newleaf = 
@@ -786,6 +754,10 @@
             }
         }
 
+        // Set a hint in the page that any scan positioned on it needs
+        // to reposition because rows may have moved off the page.
+        page.setRepositionNeeded();
+
         // At this point a unit of work in the split down the tree has
         // been performed in an internal transaction.  This work must
         // be committed before any latches are released.
@@ -827,36 +799,6 @@
 		BranchControlRow branchroot =  null;
 		LeafControlRow   newleaf    =  null; 
 
-
-        // Before moving the rows on the page, while having the latch on the
-        // page, notify btree scans that the rows on this page may be moving
-        // onto another page.
-        //
-        open_btree.init_open_user_scans.saveScanPositions(
-                open_btree.getConglomerate(), leafroot.page);
-
-        // Get exclusive RECORD_ID_PROTECTION_HANDLE lock to make sure that
-        // we wait for scans in other transactions to move off of this page
-        // before we grow root.  If we don't wait, scanners in other 
-        // transactions may be positioned on the leaf page which we are 
-        // about to make into a branch page.
-
-        if (!open_btree.getLockingPolicy().lockScan(
-                leafroot, (ControlRow) null, 
-                true /* for update */,
-                ConglomerateController.LOCK_UPD))
-        {
-            // We had to give up latches on leafroot to get the
-            // split lock.  Redo the whole split pass as we have lost our
-            // latches - which may mean that the root has grown when we gave
-            // up the latch.  Just returning is ok, as the caller can not assume
-            // that grow root has succeeded in making space.  Note that at this
-            // point in the split no write work has been done in the current
-            // internal transaction, so giving up here is fairly cheap.
-
-            return;
-        }
-
         // Allocate a new leaf page under the existing leaf root.
 
         newleaf = LeafControlRow.allocate(open_btree, leafroot);
@@ -941,6 +883,10 @@
                 branchroot.checkConsistency(open_btree, null, false);
             }
         }
+
+        // Set a hint in the page that any scan positioned on it needs
+        // to reposition because the page is no longer a leaf.
+        branchroot.page.setRepositionNeeded();
         
         // At this point a unit of work in the split down the tree has
         // been performed in an internal transaction.  This work must



Mime
View raw message