Merge branch 'gerrit/neo' into 'gerrit/trinity'

Change-Id: I8d7c74e8c0ba301339bff30bb757779531d0d9c1
diff --git a/hyracks-fullstack/hyracks/hyracks-storage-am-btree/src/main/java/org/apache/hyracks/storage/am/btree/impls/BTree.java b/hyracks-fullstack/hyracks/hyracks-storage-am-btree/src/main/java/org/apache/hyracks/storage/am/btree/impls/BTree.java
index 40b2f5c..5b1dd8c 100644
--- a/hyracks-fullstack/hyracks/hyracks-storage-am-btree/src/main/java/org/apache/hyracks/storage/am/btree/impls/BTree.java
+++ b/hyracks-fullstack/hyracks/hyracks-storage-am-btree/src/main/java/org/apache/hyracks/storage/am/btree/impls/BTree.java
@@ -99,7 +99,7 @@
         RangePredicate diskOrderScanPred = new RangePredicate(null, null, true, true, ctx.getCmp(), ctx.getCmp());
         int maxPageId = freePageManager.getMaxPageId(ctx.getMetaFrame());
         int currentPageId = bulkloadLeafStart;
-        ICachedPage page = bufferCache.pin(BufferedFileHandle.getDiskPageId(getFileId(), currentPageId), false);
+        final ICachedPage page = bufferCache.pin(BufferedFileHandle.getDiskPageId(getFileId(), currentPageId), false);
         page.acquireReadLatch();
         try {
             cursor.setBufferCache(bufferCache);
@@ -110,7 +110,7 @@
             ctx.getCursorInitialState().setSearchOperationCallback(ctx.getSearchCallback());
             ctx.getCursorInitialState().setOriginialKeyComparator(ctx.getCmp());
             cursor.open(ctx.getCursorInitialState(), diskOrderScanPred);
-        } catch (Exception e) {
+        } catch (Throwable e) {
             page.releaseReadLatch();
             bufferCache.unpin(page);
             throw HyracksDataException.create(e);
@@ -196,8 +196,7 @@
         }
         // we use this loop to deal with possibly multiple operation restarts
         // due to ongoing structure modifications during the descent
-        boolean repeatOp = true;
-        while (repeatOp && ctx.getOpRestarts() < MAX_RESTARTS) {
+        while (true) {
             performOp(rootPage, null, true, ctx);
             // if we reach this stage then we need to restart from the (possibly
             // new) root
@@ -205,7 +204,7 @@
                 ctx.getPageLsns().removeLast(); // pop the restart op indicator
                 continue;
             }
-            repeatOp = false;
+            break;
         }
         cursor.setBufferCache(bufferCache);
         cursor.setFileId(getFileId());
@@ -225,12 +224,8 @@
                 bufferCache.unpin(smPage);
             }
         }
-        if (ctx.getSmPages().size() > 0) {
-            if (ctx.getSmoCount() == Integer.MAX_VALUE) {
-                smoCounter.set(0);
-            } else {
-                smoCounter.incrementAndGet();
-            }
+        if (!ctx.getSmPages().isEmpty()) {
+            smoCounter.updateAndGet(i -> i == Integer.MAX_VALUE ? 0 : i + 1);
             treeLatch.writeLock().unlock();
             ctx.getSmPages().clear();
         }
@@ -593,8 +588,7 @@
                     // We use this loop to deal with possibly multiple operation
                     // restarts due to ongoing structure modifications during
                     // the descent.
-                    boolean repeatOp = true;
-                    while (repeatOp && ctx.getOpRestarts() < MAX_RESTARTS) {
+                    while (true) {
                         int childPageId = ctx.getInteriorFrame().getChildPageId(ctx.getPred());
                         performOp(childPageId, node, isReadLatched, ctx);
                         node = null;
@@ -609,6 +603,10 @@
                                 if (node != null) {
                                     isReadLatched = true;
                                     // Descend the tree again.
+                                    if (ctx.getOpRestarts() >= MAX_RESTARTS) {
+                                        throw HyracksDataException.create(ErrorCode.OPERATION_EXCEEDED_MAX_RESTARTS,
+                                                MAX_RESTARTS);
+                                    }
                                     continue;
                                 } else {
                                     // Pop pageLsn of this page (version seen by this op during descent).
@@ -656,7 +654,7 @@
                             }
                         }
                         // Operation completed.
-                        repeatOp = false;
+                        break;
                     } // end while
                 } else { // smFlag
                     ctx.setOpRestarts(ctx.getOpRestarts() + 1);
@@ -728,21 +726,8 @@
                     ctx.getPageLsns().add(FULL_RESTART_OP);
                 }
             }
-        } catch (HyracksDataException e) {
-            if (!ctx.isExceptionHandled()) {
-                if (node != null) {
-                    if (isReadLatched) {
-                        node.releaseReadLatch();
-                    } else {
-                        node.releaseWriteLatch(true);
-                    }
-                    bufferCache.unpin(node);
-                    ctx.setExceptionHandled(true);
-                }
-            }
-            throw e;
-        } catch (Exception e) {
-            if (node != null) {
+        } catch (Throwable e) {
+            if (!ctx.isExceptionHandled() && node != null) {
                 if (isReadLatched) {
                     node.releaseReadLatch();
                 } else {
@@ -750,9 +735,8 @@
                 }
                 bufferCache.unpin(node);
             }
-            HyracksDataException wrappedException = HyracksDataException.create(e);
             ctx.setExceptionHandled(true);
-            throw wrappedException;
+            throw HyracksDataException.create(e);
         }
     }
 
@@ -779,7 +763,7 @@
         ICachedPage node = bufferCache.pin(BufferedFileHandle.getDiskPageId(getFileId(), pageId), false);
         node.acquireReadLatch();
         try {
-            if (parent != null && unpin == true) {
+            if (parent != null && unpin) {
                 parent.releaseReadLatch();
                 bufferCache.unpin(parent);
             }
diff --git a/hyracks-fullstack/hyracks/hyracks-storage-am-btree/src/main/java/org/apache/hyracks/storage/am/btree/impls/BTreeCountingSearchCursor.java b/hyracks-fullstack/hyracks/hyracks-storage-am-btree/src/main/java/org/apache/hyracks/storage/am/btree/impls/BTreeCountingSearchCursor.java
index 1491424..71df593 100644
--- a/hyracks-fullstack/hyracks/hyracks-storage-am-btree/src/main/java/org/apache/hyracks/storage/am/btree/impls/BTreeCountingSearchCursor.java
+++ b/hyracks-fullstack/hyracks/hyracks-storage-am-btree/src/main/java/org/apache/hyracks/storage/am/btree/impls/BTreeCountingSearchCursor.java
@@ -119,13 +119,21 @@
 
     private void fetchNextLeafPage(int nextLeafPage) throws HyracksDataException {
         do {
-            ICachedPage nextLeaf = bufferCache.pin(BufferedFileHandle.getDiskPageId(fileId, nextLeafPage), false);
-            if (exclusiveLatchNodes) {
-                nextLeaf.acquireWriteLatch();
-                page.releaseWriteLatch(isPageDirty);
-            } else {
-                nextLeaf.acquireReadLatch();
-                page.releaseReadLatch();
+            final ICachedPage nextLeaf;
+            try {
+                nextLeaf = bufferCache.pin(BufferedFileHandle.getDiskPageId(fileId, nextLeafPage), false);
+                if (exclusiveLatchNodes) {
+                    nextLeaf.acquireWriteLatch();
+                } else {
+                    nextLeaf.acquireReadLatch();
+                }
+            } finally {
+                // release latches in finally, don't leak locks on pin failure
+                if (exclusiveLatchNodes) {
+                    page.releaseWriteLatch(isPageDirty);
+                } else {
+                    page.releaseReadLatch();
+                }
             }
             bufferCache.unpin(page);
             page = nextLeaf;
diff --git a/hyracks-fullstack/hyracks/hyracks-storage-am-btree/src/main/java/org/apache/hyracks/storage/am/btree/impls/BTreeRangeSearchCursor.java b/hyracks-fullstack/hyracks/hyracks-storage-am-btree/src/main/java/org/apache/hyracks/storage/am/btree/impls/BTreeRangeSearchCursor.java
index 9ccd881..cf3727a 100644
--- a/hyracks-fullstack/hyracks/hyracks-storage-am-btree/src/main/java/org/apache/hyracks/storage/am/btree/impls/BTreeRangeSearchCursor.java
+++ b/hyracks-fullstack/hyracks/hyracks-storage-am-btree/src/main/java/org/apache/hyracks/storage/am/btree/impls/BTreeRangeSearchCursor.java
@@ -110,8 +110,13 @@
 
     protected void fetchNextLeafPage(int nextLeafPage) throws HyracksDataException {
         do {
-            ICachedPage nextLeaf = acquirePage(nextLeafPage);
-            releasePage();
+            ICachedPage nextLeaf;
+            try {
+                nextLeaf = acquirePage(nextLeafPage);
+            } finally {
+                // release page in finally, don't leak lock on pin failure
+                releasePage();
+            }
             page = nextLeaf;
             isPageDirty = false;
             frame.setPage(page);
diff --git a/hyracks-fullstack/hyracks/hyracks-storage-am-btree/src/main/java/org/apache/hyracks/storage/am/btree/impls/DiskBTree.java b/hyracks-fullstack/hyracks/hyracks-storage-am-btree/src/main/java/org/apache/hyracks/storage/am/btree/impls/DiskBTree.java
index 179f1da..f58d43f 100644
--- a/hyracks-fullstack/hyracks/hyracks-storage-am-btree/src/main/java/org/apache/hyracks/storage/am/btree/impls/DiskBTree.java
+++ b/hyracks-fullstack/hyracks/hyracks-storage-am-btree/src/main/java/org/apache/hyracks/storage/am/btree/impls/DiskBTree.java
@@ -135,19 +135,12 @@
             ctx.getCursorInitialState().setPageId(childPageId);
             ctx.getLeafFrame().setPage(currentPage);
             cursor.open(ctx.getCursorInitialState(), ctx.getPred());
-        } catch (HyracksDataException e) {
+        } catch (Exception e) {
             if (!ctx.isExceptionHandled() && currentPage != null) {
                 bufferCache.unpin(currentPage);
-                ctx.setExceptionHandled(true);
             }
-            throw e;
-        } catch (Exception e) {
-            if (currentPage != null) {
-                bufferCache.unpin(currentPage);
-            }
-            HyracksDataException wrappedException = HyracksDataException.create(e);
             ctx.setExceptionHandled(true);
-            throw wrappedException;
+            throw HyracksDataException.create(e);
         }
     }
 
diff --git a/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-common/src/main/java/org/apache/hyracks/storage/am/lsm/common/freepage/VirtualFreePageManager.java b/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-common/src/main/java/org/apache/hyracks/storage/am/lsm/common/freepage/VirtualFreePageManager.java
index 9d62c0d..0e4f835 100644
--- a/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-common/src/main/java/org/apache/hyracks/storage/am/lsm/common/freepage/VirtualFreePageManager.java
+++ b/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-common/src/main/java/org/apache/hyracks/storage/am/lsm/common/freepage/VirtualFreePageManager.java
@@ -104,10 +104,13 @@
         page = bufferCache.pin(BufferedFileHandle.getDiskPageId(fileId, currentPageId.get()), true);
         if (leafFrameFactory != null) {
             page.acquireWriteLatch();
-            ITreeIndexFrame leafFrame = leafFrameFactory.createFrame();
-            leafFrame.setPage(page);
-            leafFrame.initBuffer((byte) 0);
-            page.releaseWriteLatch(true);
+            try {
+                ITreeIndexFrame leafFrame = leafFrameFactory.createFrame();
+                leafFrame.setPage(page);
+                leafFrame.initBuffer((byte) 0);
+            } finally {
+                page.releaseWriteLatch(true);
+            }
         }
         bufferCache.unpin(page);
     }
diff --git a/hyracks-fullstack/hyracks/hyracks-util/src/main/java/org/apache/hyracks/util/ReflectionUtils.java b/hyracks-fullstack/hyracks/hyracks-util/src/main/java/org/apache/hyracks/util/ReflectionUtils.java
index a5c83f0..7cc5cf8 100644
--- a/hyracks-fullstack/hyracks/hyracks-util/src/main/java/org/apache/hyracks/util/ReflectionUtils.java
+++ b/hyracks-fullstack/hyracks/hyracks-util/src/main/java/org/apache/hyracks/util/ReflectionUtils.java
@@ -20,6 +20,7 @@
 
 import java.io.IOException;
 import java.lang.reflect.Field;
+import java.lang.reflect.Method;
 
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
@@ -103,4 +104,10 @@
             throw new IOException(e);
         }
     }
+
+    public static Method getAccessibleMethod(Class<?> clazz, String methodName) throws NoSuchMethodException {
+        Method m = clazz.getDeclaredMethod(methodName);
+        m.setAccessible(true);
+        return m;
+    }
 }