Fixed a BTree concurrency bug where a restarting operation sometimes did not re-pin and re-latch it's page which was released during latch coupling downwards.

git-svn-id: https://hyracks.googlecode.com/svn/branches/hyracks_lsm_tree@1115 123451ca-8445-de46-9d55-352943316053
diff --git a/hyracks-storage-am-btree/src/main/java/edu/uci/ics/hyracks/storage/am/btree/impls/BTree.java b/hyracks-storage-am-btree/src/main/java/edu/uci/ics/hyracks/storage/am/btree/impls/BTree.java
index 7d5e87f..07a52be 100644
--- a/hyracks-storage-am-btree/src/main/java/edu/uci/ics/hyracks/storage/am/btree/impls/BTree.java
+++ b/hyracks-storage-am-btree/src/main/java/edu/uci/ics/hyracks/storage/am/btree/impls/BTree.java
@@ -309,6 +309,10 @@
     }
     
     private boolean performLeafSplit(int pageId, ITupleReference tuple, BTreeOpContext ctx) throws Exception {    	
+        // We must never hold a latch on a page while waiting to obtain the tree
+        // latch, because it this could lead to a latch-deadlock.
+        // If we can't get the tree latch, we return, release our page latches,
+        // and restart the operation from one level above.
         // Lock is released in unsetSmPages(), after sm has fully completed.
         if (!treeLatch.writeLock().tryLock()) {
             return true;
@@ -529,11 +533,13 @@
 
                         if (!ctx.pageLsns.isEmpty() && ctx.pageLsns.getLast() == RESTART_OP) {
                             // Pop the restart op indicator.
-                            ctx.pageLsns.removeLast();
+                            ctx.pageLsns.removeLast();                            
                             if (isConsistent(pageId, ctx)) {
-                                // Don't unpin and unlatch node again in recursive call.
-                                node = null; 
-                                // Descend the tree again.
+                                // Pin and latch page again, since it was unpinned and unlatched in call to performOp (passed as parent).
+                                node = bufferCache.pin(BufferedFileHandle.getDiskPageId(fileId, pageId), false);
+                                node.acquireReadLatch();
+                                ctx.interiorFrame.setPage(node);
+                                // Descend the tree again.                                
                                 continue;
                             } else {
                                 // Pop pageLsn of this page (version seen by this op during descent).
diff --git a/hyracks-tests/hyracks-storage-am-btree-test/src/test/java/edu/uci/ics/hyracks/storage/am/btree/multithread/BTreeMultiThreadTest.java b/hyracks-tests/hyracks-storage-am-btree-test/src/test/java/edu/uci/ics/hyracks/storage/am/btree/multithread/BTreeMultiThreadTest.java
index 15d4d73..c7e13f7 100644
--- a/hyracks-tests/hyracks-storage-am-btree-test/src/test/java/edu/uci/ics/hyracks/storage/am/btree/multithread/BTreeMultiThreadTest.java
+++ b/hyracks-tests/hyracks-storage-am-btree-test/src/test/java/edu/uci/ics/hyracks/storage/am/btree/multithread/BTreeMultiThreadTest.java
@@ -37,6 +37,7 @@
 public class BTreeMultiThreadTest {    
     
     private final int PAGE_SIZE = 8192;
+    //private final int PAGE_SIZE = 64;
     private final int NUM_PAGES = 1000;
     private final int MAX_OPEN_FILES = 10;
     private final int HYRACKS_FRAME_SIZE = 32768;
@@ -71,8 +72,7 @@
         
         TreeIndexMultiThreadTestDriver driver = new TreeIndexMultiThreadTestDriver(btree, workerFactory, fieldSerdes, ops, opProbs);
         
-        //driver.run(10, 1, 10000000, 1000);
-        driver.run(6, 1, 10000000, 1000);
+        driver.run(10, 1, 10000000, 1000);
         
         btree.close();
     }