Merge branch 'master' into yingyi/fullstack_fix
diff --git a/hyracks/hyracks-control/hyracks-control-common/src/main/java/edu/uci/ics/hyracks/control/common/application/ApplicationContext.java b/hyracks/hyracks-control/hyracks-control-common/src/main/java/edu/uci/ics/hyracks/control/common/application/ApplicationContext.java
index 2ca7ccf..828f2fb 100644
--- a/hyracks/hyracks-control/hyracks-control-common/src/main/java/edu/uci/ics/hyracks/control/common/application/ApplicationContext.java
+++ b/hyracks/hyracks-control/hyracks-control-common/src/main/java/edu/uci/ics/hyracks/control/common/application/ApplicationContext.java
@@ -31,7 +31,9 @@
     protected IJobSerializerDeserializerContainer jobSerDeContainer = new JobSerializerDeserializerContainer();
     protected ThreadFactory threadFactory = new ThreadFactory() {
         public Thread newThread(Runnable r) {
-            return new Thread(r);
+            Thread t = new Thread(r);
+            t.setDaemon(true);
+            return t;
         }
     };
 
diff --git a/hyracks/hyracks-storage-am-bloomfilter/src/main/java/edu/uci/ics/hyracks/storage/am/bloomfilter/impls/BloomFilter.java b/hyracks/hyracks-storage-am-bloomfilter/src/main/java/edu/uci/ics/hyracks/storage/am/bloomfilter/impls/BloomFilter.java
index fe25db8..19200ee 100644
--- a/hyracks/hyracks-storage-am-bloomfilter/src/main/java/edu/uci/ics/hyracks/storage/am/bloomfilter/impls/BloomFilter.java
+++ b/hyracks/hyracks-storage-am-bloomfilter/src/main/java/edu/uci/ics/hyracks/storage/am/bloomfilter/impls/BloomFilter.java
@@ -133,7 +133,7 @@
         metaPage.getBuffer().putInt(NUM_HASHES_USED_OFFSET, 0);
         metaPage.getBuffer().putLong(NUM_ELEMENTS_OFFSET, 0L);
         metaPage.getBuffer().putLong(NUM_BITS_OFFSET, 0L);
-        metaPage.releaseWriteLatch();
+        metaPage.releaseWriteLatch(true);
         bufferCache.unpin(metaPage);
         bufferCache.closeFile(fileId);
     }
@@ -249,7 +249,7 @@
             metaPage.getBuffer().putInt(NUM_HASHES_USED_OFFSET, numHashes);
             metaPage.getBuffer().putLong(NUM_ELEMENTS_OFFSET, numElements);
             metaPage.getBuffer().putLong(NUM_BITS_OFFSET, numBits);
-            metaPage.releaseWriteLatch();
+            metaPage.releaseWriteLatch(true);
             bufferCache.unpin(metaPage);
         }
 
@@ -273,7 +273,7 @@
         public void end() throws HyracksDataException, IndexException {
             for (int i = 0; i < numPages; ++i) {
                 ICachedPage page = bloomFilterPages.get(i);
-                page.releaseWriteLatch();
+                page.releaseWriteLatch(true);
             }
         }
 
diff --git a/hyracks/hyracks-storage-am-btree/src/main/java/edu/uci/ics/hyracks/storage/am/btree/impls/BTree.java b/hyracks/hyracks-storage-am-btree/src/main/java/edu/uci/ics/hyracks/storage/am/btree/impls/BTree.java
index ff94040..8cf4aa4 100644
--- a/hyracks/hyracks-storage-am-btree/src/main/java/edu/uci/ics/hyracks/storage/am/btree/impls/BTree.java
+++ b/hyracks/hyracks-storage-am-btree/src/main/java/edu/uci/ics/hyracks/storage/am/btree/impls/BTree.java
@@ -217,7 +217,7 @@
                 ctx.interiorFrame.setPage(smPage);
                 ctx.interiorFrame.setSmFlag(false);
             } finally {
-                smPage.releaseWriteLatch();
+                smPage.releaseWriteLatch(true);
                 bufferCache.unpin(smPage);
             }
         }
@@ -261,11 +261,11 @@
                 int targetTupleIndex = ctx.interiorFrame.findInsertTupleIndex(ctx.splitKey.getTuple());
                 ctx.interiorFrame.insert(ctx.splitKey.getTuple(), targetTupleIndex);
             } finally {
-                newLeftNode.releaseWriteLatch();
+                newLeftNode.releaseWriteLatch(true);
                 bufferCache.unpin(newLeftNode);
             }
         } finally {
-            leftNode.releaseWriteLatch();
+            leftNode.releaseWriteLatch(true);
             bufferCache.unpin(leftNode);
         }
     }
@@ -447,7 +447,7 @@
             treeLatch.writeLock().unlock();
             throw e;
         } finally {
-            rightNode.releaseWriteLatch();
+            rightNode.releaseWriteLatch(true);
             bufferCache.unpin(rightNode);
         }
         return false;
@@ -533,7 +533,7 @@
 
                     ctx.splitKey.setPages(pageId, rightPageId);
                 } finally {
-                    rightNode.releaseWriteLatch();
+                    rightNode.releaseWriteLatch(true);
                     bufferCache.unpin(rightNode);
                 }
                 break;
@@ -616,7 +616,7 @@
                 if (parentIsReadLatched) {
                     parent.releaseReadLatch();
                 } else {
-                    parent.releaseWriteLatch();
+                    parent.releaseWriteLatch(true);
                 }
                 bufferCache.unpin(parent);
             }
@@ -664,7 +664,7 @@
                                         // Insert or update op. Both can cause split keys to propagate upwards. 
                                         insertInterior(interiorNode, pageId, ctx.splitKey.getTuple(), ctx);
                                     } finally {
-                                        interiorNode.releaseWriteLatch();
+                                        interiorNode.releaseWriteLatch(true);
                                         bufferCache.unpin(interiorNode);
                                     }
                                 } else {
@@ -694,7 +694,7 @@
                     if (isReadLatched) {
                         node.releaseReadLatch();
                     } else {
-                        node.releaseWriteLatch();
+                        node.releaseWriteLatch(true);
                     }
                     bufferCache.unpin(node);
 
@@ -747,7 +747,7 @@
                     }
                 }
                 if (ctx.op != IndexOperation.SEARCH) {
-                    node.releaseWriteLatch();
+                    node.releaseWriteLatch(true);
                     bufferCache.unpin(node);
                 }
                 if (restartOp) {
@@ -764,7 +764,7 @@
                     if (isReadLatched) {
                         node.releaseReadLatch();
                     } else {
-                        node.releaseWriteLatch();
+                        node.releaseWriteLatch(true);
                     }
                     bufferCache.unpin(node);
                     ctx.exceptionHandled = true;
@@ -777,7 +777,7 @@
                 if (isReadLatched) {
                     node.releaseReadLatch();
                 } else {
-                    node.releaseWriteLatch();
+                    node.releaseWriteLatch(true);
                 }
                 bufferCache.unpin(node);
             }
@@ -990,7 +990,7 @@
                     leafFrontier.pageId = freePageManager.getFreePage(metaFrame);
 
                     ((IBTreeLeafFrame) leafFrame).setNextLeaf(leafFrontier.pageId);
-                    leafFrontier.page.releaseWriteLatch();
+                    leafFrontier.page.releaseWriteLatch(true);
                     bufferCache.unpin(leafFrontier.page);
 
                     splitKey.setRightPage(leafFrontier.pageId);
@@ -1062,7 +1062,7 @@
 
                 ((IBTreeInteriorFrame) interiorFrame).deleteGreatest();
 
-                frontier.page.releaseWriteLatch();
+                frontier.page.releaseWriteLatch(true);
                 bufferCache.unpin(frontier.page);
                 frontier.pageId = freePageManager.getFreePage(metaFrame);
 
diff --git a/hyracks/hyracks-storage-am-btree/src/main/java/edu/uci/ics/hyracks/storage/am/btree/impls/BTreeCountingSearchCursor.java b/hyracks/hyracks-storage-am-btree/src/main/java/edu/uci/ics/hyracks/storage/am/btree/impls/BTreeCountingSearchCursor.java
index ee65a46..38c1624 100644
--- a/hyracks/hyracks-storage-am-btree/src/main/java/edu/uci/ics/hyracks/storage/am/btree/impls/BTreeCountingSearchCursor.java
+++ b/hyracks/hyracks-storage-am-btree/src/main/java/edu/uci/ics/hyracks/storage/am/btree/impls/BTreeCountingSearchCursor.java
@@ -51,6 +51,7 @@
     private final IBTreeLeafFrame frame;
     private final ITreeIndexTupleReference frameTuple;
     private final boolean exclusiveLatchNodes;
+    private boolean isPageDirty;
 
     private RangePredicate pred;
     private MultiComparator lowKeyCmp;
@@ -61,8 +62,8 @@
     // For storing the count.
     private byte[] countBuf = new byte[4];
     private ArrayTupleBuilder tupleBuilder = new ArrayTupleBuilder(1);
-    private ArrayTupleReference countTuple = new ArrayTupleReference();    
-    
+    private ArrayTupleReference countTuple = new ArrayTupleReference();
+
     public BTreeCountingSearchCursor(IBTreeLeafFrame frame, boolean exclusiveLatchNodes) {
         this.frame = frame;
         this.frameTuple = frame.createTupleReference();
@@ -74,7 +75,7 @@
         // in case open is called multiple times without closing
         if (page != null) {
             if (exclusiveLatchNodes) {
-                page.releaseWriteLatch();
+                page.releaseWriteLatch(isPageDirty);
             } else {
                 page.releaseReadLatch();
             }
@@ -82,6 +83,7 @@
         }
 
         page = ((BTreeCursorInitialState) initialState).getPage();
+        isPageDirty = false;
         frame.setPage(page);
 
         pred = (RangePredicate) searchPred;
@@ -107,7 +109,7 @@
         }
 
         tupleIndex = getLowKeyIndex();
-        stopTupleIndex = getHighKeyIndex();        
+        stopTupleIndex = getHighKeyIndex();
     }
 
     private void fetchNextLeafPage(int nextLeafPage) throws HyracksDataException {
@@ -115,13 +117,14 @@
             ICachedPage nextLeaf = bufferCache.pin(BufferedFileHandle.getDiskPageId(fileId, nextLeafPage), false);
             if (exclusiveLatchNodes) {
                 nextLeaf.acquireWriteLatch();
-                page.releaseWriteLatch();
+                page.releaseWriteLatch(isPageDirty);
             } else {
                 nextLeaf.acquireReadLatch();
                 page.releaseReadLatch();
             }
             bufferCache.unpin(page);
             page = nextLeaf;
+            isPageDirty = false;
             frame.setPage(page);
             nextLeafPage = frame.getNextLeaf();
         } while (frame.getTupleCount() == 0 && nextLeafPage > 0);
@@ -199,7 +202,7 @@
     public void close() throws HyracksDataException {
         if (page != null) {
             if (exclusiveLatchNodes) {
-                page.releaseWriteLatch();
+                page.releaseWriteLatch(isPageDirty);
             } else {
                 page.releaseReadLatch();
             }
@@ -208,6 +211,7 @@
         tupleBuilder.reset();
         tupleIndex = 0;
         page = null;
+        isPageDirty = false;
         pred = null;
         count = -1;
     }
@@ -218,7 +222,7 @@
             close();
         } catch (Exception e) {
             e.printStackTrace();
-        }        
+        }
     }
 
     @Override
@@ -246,4 +250,13 @@
         return exclusiveLatchNodes;
     }
 
+    @Override
+    public void markCurrentTupleAsUpdated() throws HyracksDataException {
+        if (exclusiveLatchNodes) {
+            isPageDirty = true;
+        } else {
+            throw new HyracksDataException("This cursor has not been created with the intention to allow updates.");
+        }
+    }
+
 }
diff --git a/hyracks/hyracks-storage-am-btree/src/main/java/edu/uci/ics/hyracks/storage/am/btree/impls/BTreeRangeSearchCursor.java b/hyracks/hyracks-storage-am-btree/src/main/java/edu/uci/ics/hyracks/storage/am/btree/impls/BTreeRangeSearchCursor.java
index 4546b0e..584af4e 100644
--- a/hyracks/hyracks-storage-am-btree/src/main/java/edu/uci/ics/hyracks/storage/am/btree/impls/BTreeRangeSearchCursor.java
+++ b/hyracks/hyracks-storage-am-btree/src/main/java/edu/uci/ics/hyracks/storage/am/btree/impls/BTreeRangeSearchCursor.java
@@ -40,6 +40,7 @@
     private final IBTreeLeafFrame frame;
     private final ITreeIndexTupleReference frameTuple;
     private final boolean exclusiveLatchNodes;
+    private boolean isPageDirty;
 
     private IBufferCache bufferCache = null;
     private int fileId = -1;
@@ -80,7 +81,7 @@
     public void close() throws HyracksDataException {
         if (page != null) {
             if (exclusiveLatchNodes) {
-                page.releaseWriteLatch();
+                page.releaseWriteLatch(isPageDirty);
             } else {
                 page.releaseReadLatch();
             }
@@ -89,6 +90,7 @@
 
         tupleIndex = 0;
         page = null;
+        isPageDirty = false;
         pred = null;
     }
 
@@ -114,7 +116,7 @@
             ICachedPage nextLeaf = bufferCache.pin(BufferedFileHandle.getDiskPageId(fileId, nextLeafPage), false);
             if (exclusiveLatchNodes) {
                 nextLeaf.acquireWriteLatch();
-                page.releaseWriteLatch();
+                page.releaseWriteLatch(isPageDirty);
             } else {
                 nextLeaf.acquireReadLatch();
                 page.releaseReadLatch();
@@ -122,6 +124,7 @@
             bufferCache.unpin(page);
 
             page = nextLeaf;
+            isPageDirty = false;
             frame.setPage(page);
             pageId = nextLeafPage;
             nextLeafPage = frame.getNextLeaf();
@@ -163,12 +166,13 @@
 
                 // unlatch/unpin
                 if (exclusiveLatchNodes) {
-                    page.releaseWriteLatch();
+                    page.releaseWriteLatch(isPageDirty);
                 } else {
                     page.releaseReadLatch();
                 }
                 bufferCache.unpin(page);
                 page = null;
+                isPageDirty = false;
 
                 // reconcile
                 searchCb.reconcile(reconciliationTuple);
@@ -240,7 +244,7 @@
         // in case open is called multiple times without closing
         if (page != null) {
             if (exclusiveLatchNodes) {
-                page.releaseWriteLatch();
+                page.releaseWriteLatch(isPageDirty);
             } else {
                 page.releaseReadLatch();
             }
@@ -251,6 +255,7 @@
         originalKeyCmp = initialState.getOriginalKeyComparator();
         pageId = ((BTreeCursorInitialState) initialState).getPageId();
         page = initialState.getPage();
+        isPageDirty = false;
         frame.setPage(page);
 
         pred = (RangePredicate) searchPred;
@@ -300,4 +305,13 @@
     public boolean exclusiveLatchNodes() {
         return exclusiveLatchNodes;
     }
+
+    @Override
+    public void markCurrentTupleAsUpdated() throws HyracksDataException {
+        if (exclusiveLatchNodes) {
+            isPageDirty = true;
+        } else {
+            throw new HyracksDataException("This cursor has not been created with the intention to allow updates.");
+        }
+    }
 }
\ No newline at end of file
diff --git a/hyracks/hyracks-storage-am-common/src/main/java/edu/uci/ics/hyracks/storage/am/common/api/ITreeIndexCursor.java b/hyracks/hyracks-storage-am-common/src/main/java/edu/uci/ics/hyracks/storage/am/common/api/ITreeIndexCursor.java
index 5102d27..a097425 100644
--- a/hyracks/hyracks-storage-am-common/src/main/java/edu/uci/ics/hyracks/storage/am/common/api/ITreeIndexCursor.java
+++ b/hyracks/hyracks-storage-am-common/src/main/java/edu/uci/ics/hyracks/storage/am/common/api/ITreeIndexCursor.java
@@ -15,17 +15,20 @@
 
 package edu.uci.ics.hyracks.storage.am.common.api;
 
+import edu.uci.ics.hyracks.api.exceptions.HyracksDataException;
 import edu.uci.ics.hyracks.storage.common.buffercache.IBufferCache;
 import edu.uci.ics.hyracks.storage.common.buffercache.ICachedPage;
 
 public interface ITreeIndexCursor extends IIndexCursor {
 
-	public ICachedPage getPage();
+    public ICachedPage getPage();
 
-	public void setBufferCache(IBufferCache bufferCache);
+    public void setBufferCache(IBufferCache bufferCache);
 
-	public void setFileId(int fileId);
+    public void setFileId(int fileId);
 
-	// For allowing updates.
-	public boolean exclusiveLatchNodes();
+    // For allowing updates.
+    public boolean exclusiveLatchNodes();
+
+    public void markCurrentTupleAsUpdated() throws HyracksDataException;
 }
diff --git a/hyracks/hyracks-storage-am-common/src/main/java/edu/uci/ics/hyracks/storage/am/common/freepage/LinkedListFreePageManager.java b/hyracks/hyracks-storage-am-common/src/main/java/edu/uci/ics/hyracks/storage/am/common/freepage/LinkedListFreePageManager.java
index 2e25f4c..a51ce98 100644
--- a/hyracks/hyracks-storage-am-common/src/main/java/edu/uci/ics/hyracks/storage/am/common/freepage/LinkedListFreePageManager.java
+++ b/hyracks/hyracks-storage-am-common/src/main/java/edu/uci/ics/hyracks/storage/am/common/freepage/LinkedListFreePageManager.java
@@ -77,14 +77,14 @@
 					metaFrame.setMaxPage(metaMaxPage);
 					metaFrame.addFreePage(freePage);
 				} finally {
-					newNode.releaseWriteLatch();
+					newNode.releaseWriteLatch(true);
 					bufferCache.unpin(newNode);
 				}
 			}
 		} catch (Exception e) {
 			e.printStackTrace();
 		} finally {
-			metaNode.releaseWriteLatch();
+			metaNode.releaseWriteLatch(true);
 			bufferCache.unpin(metaNode);
 		}
 	}
@@ -136,7 +136,7 @@
 							metaFrame.addFreePage(nextPage);
 						}
 					} finally {
-						nextNode.releaseWriteLatch();
+						nextNode.releaseWriteLatch(true);
 						bufferCache.unpin(nextNode);
 					}
 				} else {
@@ -146,7 +146,7 @@
 				}
 			}
 		} finally {
-			metaNode.releaseWriteLatch();
+			metaNode.releaseWriteLatch(true);
 			bufferCache.unpin(metaNode);
 		}
 
@@ -164,7 +164,7 @@
 			metaFrame.setPage(metaNode);
 			maxPage = metaFrame.getMaxPage();
 		} finally {
-			metaNode.releaseWriteLatch();
+			metaNode.releaseWriteLatch(true);
 			bufferCache.unpin(metaNode);
 		}
 		return maxPage;
@@ -183,7 +183,7 @@
 			metaFrame.initBuffer(META_PAGE_LEVEL_INDICATOR);
 			metaFrame.setMaxPage(currentMaxPage);
 		} finally {
-			metaNode.releaseWriteLatch();
+			metaNode.releaseWriteLatch(true);
 			bufferCache.unpin(metaNode);
 		}
 	}
diff --git a/hyracks/hyracks-storage-am-common/src/main/java/edu/uci/ics/hyracks/storage/am/common/impls/AbstractTreeIndex.java b/hyracks/hyracks-storage-am-common/src/main/java/edu/uci/ics/hyracks/storage/am/common/impls/AbstractTreeIndex.java
index 3e4ecf8..e191fd0 100644
--- a/hyracks/hyracks-storage-am-common/src/main/java/edu/uci/ics/hyracks/storage/am/common/impls/AbstractTreeIndex.java
+++ b/hyracks/hyracks-storage-am-common/src/main/java/edu/uci/ics/hyracks/storage/am/common/impls/AbstractTreeIndex.java
@@ -111,7 +111,7 @@
             frame.setPage(rootNode);
             frame.initBuffer((byte) 0);
         } finally {
-            rootNode.releaseWriteLatch();
+            rootNode.releaseWriteLatch(true);
             bufferCache.unpin(rootNode);
         }
     }
@@ -293,7 +293,7 @@
         protected void handleException() throws HyracksDataException {
             // Unlatch and unpin pages.
             for (NodeFrontier nodeFrontier : nodeFrontiers) {
-                nodeFrontier.page.releaseWriteLatch();
+                nodeFrontier.page.releaseWriteLatch(true);
                 bufferCache.unpin(nodeFrontier.page);
             }
             releasedLatches = true;
@@ -309,7 +309,7 @@
                 System.arraycopy(lastNodeFrontier.page.getBuffer().array(), 0, newRoot.getBuffer().array(), 0,
                         lastNodeFrontier.page.getBuffer().capacity());
             } finally {
-                newRoot.releaseWriteLatch();
+                newRoot.releaseWriteLatch(true);
                 bufferCache.unpin(newRoot);
 
                 // register old root as a free page
@@ -318,7 +318,7 @@
                 if (!releasedLatches) {
                     for (int i = 0; i < nodeFrontiers.size(); i++) {
                         try {
-                            nodeFrontiers.get(i).page.releaseWriteLatch();
+                            nodeFrontiers.get(i).page.releaseWriteLatch(true);
                         } catch (Exception e) {
                             //ignore illegal monitor state exception
                         }
diff --git a/hyracks/hyracks-storage-am-common/src/main/java/edu/uci/ics/hyracks/storage/am/common/impls/TreeIndexDiskOrderScanCursor.java b/hyracks/hyracks-storage-am-common/src/main/java/edu/uci/ics/hyracks/storage/am/common/impls/TreeIndexDiskOrderScanCursor.java
index 0f97b0d..7592348 100644
--- a/hyracks/hyracks-storage-am-common/src/main/java/edu/uci/ics/hyracks/storage/am/common/impls/TreeIndexDiskOrderScanCursor.java
+++ b/hyracks/hyracks-storage-am-common/src/main/java/edu/uci/ics/hyracks/storage/am/common/impls/TreeIndexDiskOrderScanCursor.java
@@ -147,4 +147,9 @@
     public boolean exclusiveLatchNodes() {
         return false;
     }
+
+    @Override
+    public void markCurrentTupleAsUpdated() throws HyracksDataException {
+        throw new HyracksDataException("Updating tuples is not supported with this cursor.");
+    }
 }
diff --git a/hyracks/hyracks-storage-am-lsm-btree/src/main/java/edu/uci/ics/hyracks/storage/am/lsm/btree/impls/LSMBTreePointSearchCursor.java b/hyracks/hyracks-storage-am-lsm-btree/src/main/java/edu/uci/ics/hyracks/storage/am/lsm/btree/impls/LSMBTreePointSearchCursor.java
index fc09a74..7aba7b3 100644
--- a/hyracks/hyracks-storage-am-lsm-btree/src/main/java/edu/uci/ics/hyracks/storage/am/lsm/btree/impls/LSMBTreePointSearchCursor.java
+++ b/hyracks/hyracks-storage-am-lsm-btree/src/main/java/edu/uci/ics/hyracks/storage/am/lsm/btree/impls/LSMBTreePointSearchCursor.java
@@ -219,4 +219,9 @@
     public boolean exclusiveLatchNodes() {
         return false;
     }
+
+    @Override
+    public void markCurrentTupleAsUpdated() throws HyracksDataException {
+        throw new HyracksDataException("Updating tuples is not supported with this cursor.");
+    }
 }
\ No newline at end of file
diff --git a/hyracks/hyracks-storage-am-lsm-btree/src/main/java/edu/uci/ics/hyracks/storage/am/lsm/btree/impls/LSMBTreeSearchCursor.java b/hyracks/hyracks-storage-am-lsm-btree/src/main/java/edu/uci/ics/hyracks/storage/am/lsm/btree/impls/LSMBTreeSearchCursor.java
index 366fc10..dd99833 100644
--- a/hyracks/hyracks-storage-am-lsm-btree/src/main/java/edu/uci/ics/hyracks/storage/am/lsm/btree/impls/LSMBTreeSearchCursor.java
+++ b/hyracks/hyracks-storage-am-lsm-btree/src/main/java/edu/uci/ics/hyracks/storage/am/lsm/btree/impls/LSMBTreeSearchCursor.java
@@ -129,4 +129,8 @@
         return currentCursor.exclusiveLatchNodes();
     }
 
+    @Override
+    public void markCurrentTupleAsUpdated() throws HyracksDataException {
+        throw new HyracksDataException("Updating tuples is not supported with this cursor.");
+    }
 }
\ No newline at end of file
diff --git a/hyracks/hyracks-storage-am-lsm-common/src/main/java/edu/uci/ics/hyracks/storage/am/lsm/common/impls/AbstractLSMIndex.java b/hyracks/hyracks-storage-am-lsm-common/src/main/java/edu/uci/ics/hyracks/storage/am/lsm/common/impls/AbstractLSMIndex.java
index 44bcfc2..6ec8f9f 100644
--- a/hyracks/hyracks-storage-am-lsm-common/src/main/java/edu/uci/ics/hyracks/storage/am/lsm/common/impls/AbstractLSMIndex.java
+++ b/hyracks/hyracks-storage-am-lsm-common/src/main/java/edu/uci/ics/hyracks/storage/am/lsm/common/impls/AbstractLSMIndex.java
@@ -132,7 +132,7 @@
             // Force modified metadata page to disk.
             bufferCache.force(fileId, true);
         } finally {
-            metadataPage.releaseWriteLatch();
+            metadataPage.releaseWriteLatch(true);
             bufferCache.unpin(metadataPage);
         }
     }
diff --git a/hyracks/hyracks-storage-am-lsm-common/src/main/java/edu/uci/ics/hyracks/storage/am/lsm/common/impls/LSMIndexSearchCursor.java b/hyracks/hyracks-storage-am-lsm-common/src/main/java/edu/uci/ics/hyracks/storage/am/lsm/common/impls/LSMIndexSearchCursor.java
index 2bc45a9..5a4699e 100644
--- a/hyracks/hyracks-storage-am-lsm-common/src/main/java/edu/uci/ics/hyracks/storage/am/lsm/common/impls/LSMIndexSearchCursor.java
+++ b/hyracks/hyracks-storage-am-lsm-common/src/main/java/edu/uci/ics/hyracks/storage/am/lsm/common/impls/LSMIndexSearchCursor.java
@@ -263,4 +263,9 @@
     protected int compare(MultiComparator cmp, ITupleReference tupleA, ITupleReference tupleB) {
         return cmp.compare(tupleA, tupleB);
     }
+    
+    @Override
+    public void markCurrentTupleAsUpdated() throws HyracksDataException {
+        throw new HyracksDataException("Updating tuples is not supported with this cursor.");
+    }
 }
\ No newline at end of file
diff --git a/hyracks/hyracks-storage-am-lsm-common/src/main/java/edu/uci/ics/hyracks/storage/am/lsm/common/impls/VirtualBufferCache.java b/hyracks/hyracks-storage-am-lsm-common/src/main/java/edu/uci/ics/hyracks/storage/am/lsm/common/impls/VirtualBufferCache.java
index bd3b278..7f804c1 100644
--- a/hyracks/hyracks-storage-am-lsm-common/src/main/java/edu/uci/ics/hyracks/storage/am/lsm/common/impls/VirtualBufferCache.java
+++ b/hyracks/hyracks-storage-am-lsm-common/src/main/java/edu/uci/ics/hyracks/storage/am/lsm/common/impls/VirtualBufferCache.java
@@ -336,7 +336,7 @@
         }
 
         @Override
-        public void releaseWriteLatch() {
+        public void releaseWriteLatch(boolean markDirty) {
             latch.writeLock().unlock();
         }
 
diff --git a/hyracks/hyracks-storage-am-lsm-invertedindex/src/main/java/edu/uci/ics/hyracks/storage/am/lsm/invertedindex/ondisk/OnDiskInvertedIndex.java b/hyracks/hyracks-storage-am-lsm-invertedindex/src/main/java/edu/uci/ics/hyracks/storage/am/lsm/invertedindex/ondisk/OnDiskInvertedIndex.java
index 4f586f9..52dc815 100644
--- a/hyracks/hyracks-storage-am-lsm-invertedindex/src/main/java/edu/uci/ics/hyracks/storage/am/lsm/invertedindex/ondisk/OnDiskInvertedIndex.java
+++ b/hyracks/hyracks-storage-am-lsm-invertedindex/src/main/java/edu/uci/ics/hyracks/storage/am/lsm/invertedindex/ondisk/OnDiskInvertedIndex.java
@@ -325,7 +325,7 @@
         }
 
         public void pinNextPage() throws HyracksDataException {
-            currentPage.releaseWriteLatch();
+            currentPage.releaseWriteLatch(true);
             bufferCache.unpin(currentPage);
             currentPageId++;
             currentPage = bufferCache.pin(BufferedFileHandle.getDiskPageId(fileId, currentPageId), true);
@@ -431,7 +431,7 @@
             btreeBulkloader.end();
 
             if (currentPage != null) {
-                currentPage.releaseWriteLatch();
+                currentPage.releaseWriteLatch(true);
                 bufferCache.unpin(currentPage);
             }
             invListsMaxPageId = currentPageId;
diff --git a/hyracks/hyracks-storage-am-lsm-rtree/src/main/java/edu/uci/ics/hyracks/storage/am/lsm/rtree/impls/LSMRTreeAbstractCursor.java b/hyracks/hyracks-storage-am-lsm-rtree/src/main/java/edu/uci/ics/hyracks/storage/am/lsm/rtree/impls/LSMRTreeAbstractCursor.java
index 4e322d4..32f3174 100644
--- a/hyracks/hyracks-storage-am-lsm-rtree/src/main/java/edu/uci/ics/hyracks/storage/am/lsm/rtree/impls/LSMRTreeAbstractCursor.java
+++ b/hyracks/hyracks-storage-am-lsm-rtree/src/main/java/edu/uci/ics/hyracks/storage/am/lsm/rtree/impls/LSMRTreeAbstractCursor.java
@@ -163,4 +163,8 @@
         return false;
     }
 
+    @Override
+    public void markCurrentTupleAsUpdated() throws HyracksDataException {
+        throw new HyracksDataException("Updating tuples is not supported with this cursor.");
+    }
 }
\ No newline at end of file
diff --git a/hyracks/hyracks-storage-am-lsm-rtree/src/main/java/edu/uci/ics/hyracks/storage/am/lsm/rtree/impls/LSMRTreeWithAntiMatterTuplesFlushCursor.java b/hyracks/hyracks-storage-am-lsm-rtree/src/main/java/edu/uci/ics/hyracks/storage/am/lsm/rtree/impls/LSMRTreeWithAntiMatterTuplesFlushCursor.java
index 0dd2281..aa3fad8 100644
--- a/hyracks/hyracks-storage-am-lsm-rtree/src/main/java/edu/uci/ics/hyracks/storage/am/lsm/rtree/impls/LSMRTreeWithAntiMatterTuplesFlushCursor.java
+++ b/hyracks/hyracks-storage-am-lsm-rtree/src/main/java/edu/uci/ics/hyracks/storage/am/lsm/rtree/impls/LSMRTreeWithAntiMatterTuplesFlushCursor.java
@@ -145,20 +145,21 @@
 
     @Override
     public void setBufferCache(IBufferCache bufferCache) {
-        // TODO Auto-generated method stub
 
     }
 
     @Override
     public void setFileId(int fileId) {
-        // TODO Auto-generated method stub
 
     }
 
     @Override
     public boolean exclusiveLatchNodes() {
-        // TODO Auto-generated method stub
         return false;
     }
 
+    @Override
+    public void markCurrentTupleAsUpdated() throws HyracksDataException {
+        throw new HyracksDataException("Updating tuples is not supported with this cursor.");
+    }
 }
diff --git a/hyracks/hyracks-storage-am-lsm-rtree/src/main/java/edu/uci/ics/hyracks/storage/am/lsm/rtree/impls/TreeTupleSorter.java b/hyracks/hyracks-storage-am-lsm-rtree/src/main/java/edu/uci/ics/hyracks/storage/am/lsm/rtree/impls/TreeTupleSorter.java
index 03d9043..7946529 100644
--- a/hyracks/hyracks-storage-am-lsm-rtree/src/main/java/edu/uci/ics/hyracks/storage/am/lsm/rtree/impls/TreeTupleSorter.java
+++ b/hyracks/hyracks-storage-am-lsm-rtree/src/main/java/edu/uci/ics/hyracks/storage/am/lsm/rtree/impls/TreeTupleSorter.java
@@ -222,4 +222,8 @@
         return false;
     }
 
+    @Override
+    public void markCurrentTupleAsUpdated() throws HyracksDataException {
+        throw new HyracksDataException("Updating tuples is not supported with this cursor.");
+    }
 }
\ No newline at end of file
diff --git a/hyracks/hyracks-storage-am-rtree/src/main/java/edu/uci/ics/hyracks/storage/am/rtree/impls/RTree.java b/hyracks/hyracks-storage-am-rtree/src/main/java/edu/uci/ics/hyracks/storage/am/rtree/impls/RTree.java
index 7bb3583..e744a81 100644
--- a/hyracks/hyracks-storage-am-rtree/src/main/java/edu/uci/ics/hyracks/storage/am/rtree/impls/RTree.java
+++ b/hyracks/hyracks-storage-am-rtree/src/main/java/edu/uci/ics/hyracks/storage/am/rtree/impls/RTree.java
@@ -201,7 +201,7 @@
                 ICachedPage node = ctx.LSNUpdates.get(i);
                 ctx.interiorFrame.setPage(node);
                 ctx.interiorFrame.setPageLsn(incrementGlobalNsn());
-                node.releaseWriteLatch();
+                node.releaseWriteLatch(true);
                 bufferCache.unpin(node);
             }
         }
@@ -228,7 +228,7 @@
                         writeLatched = true;
 
                         if (!ctx.interiorFrame.isLeaf()) {
-                            node.releaseWriteLatch();
+                            node.releaseWriteLatch(true);
                             writeLatched = false;
                             bufferCache.unpin(node);
                             continue;
@@ -246,7 +246,7 @@
                     // Concurrent split detected, go back to parent and
                     // re-choose the best child
                     if (writeLatched) {
-                        node.releaseWriteLatch();
+                        node.releaseWriteLatch(true);
                         writeLatched = false;
                         bufferCache.unpin(node);
                     } else {
@@ -294,7 +294,7 @@
                         // already pointing to the best child
                         ctx.interiorFrame.enlarge(ctx.getTuple(), ctx.cmp);
 
-                        node.releaseWriteLatch();
+                        node.releaseWriteLatch(true);
                         writeLatched = false;
                         bufferCache.unpin(node);
                     } else {
@@ -303,7 +303,7 @@
                             readLatched = false;
                             bufferCache.unpin(node);
                         } else if (writeLatched) {
-                            node.releaseWriteLatch();
+                            node.releaseWriteLatch(true);
                             writeLatched = false;
                             bufferCache.unpin(node);
                         }
@@ -324,7 +324,7 @@
                     readLatched = false;
                     bufferCache.unpin(node);
                 } else if (writeLatched) {
-                    node.releaseWriteLatch();
+                    node.releaseWriteLatch(true);
                     writeLatched = false;
                     bufferCache.unpin(node);
                 }
@@ -359,7 +359,7 @@
                     } else if (isLeaf) {
                         // In case of a crash, we un-latch the interior node
                         // inside updateParentForInsert.
-                        node.releaseWriteLatch();
+                        node.releaseWriteLatch(true);
                         bufferCache.unpin(node);
                     }
                 }
@@ -384,7 +384,7 @@
                     } else if (isLeaf) {
                         // In case of a crash, we un-latch the interior node
                         // inside updateParentForInsert.
-                        node.releaseWriteLatch();
+                        node.releaseWriteLatch(true);
                         bufferCache.unpin(node);
                     }
                 }
@@ -424,12 +424,12 @@
                     } else if (isLeaf) {
                         // In case of a crash, we un-latch the interior node
                         // inside updateParentForInsert.
-                        node.releaseWriteLatch();
+                        node.releaseWriteLatch(true);
                         bufferCache.unpin(node);
-                        rightNode.releaseWriteLatch();
+                        rightNode.releaseWriteLatch(true);
                         bufferCache.unpin(rightNode);
                     } else {
-                        rightNode.releaseWriteLatch();
+                        rightNode.releaseWriteLatch(true);
                         bufferCache.unpin(rightNode);
                     }
 
@@ -469,16 +469,16 @@
                         } else if (isLeaf) {
                             // In case of a crash, we un-latch the interior node
                             // inside updateParentForInsert.
-                            node.releaseWriteLatch();
+                            node.releaseWriteLatch(true);
                             bufferCache.unpin(node);
-                            rightNode.releaseWriteLatch();
+                            rightNode.releaseWriteLatch(true);
                             bufferCache.unpin(rightNode);
-                            newLeftNode.releaseWriteLatch();
+                            newLeftNode.releaseWriteLatch(true);
                             bufferCache.unpin(newLeftNode);
                         } else {
-                            rightNode.releaseWriteLatch();
+                            rightNode.releaseWriteLatch(true);
                             bufferCache.unpin(rightNode);
-                            newLeftNode.releaseWriteLatch();
+                            newLeftNode.releaseWriteLatch(true);
                             bufferCache.unpin(newLeftNode);
                         }
                     }
@@ -508,7 +508,7 @@
                         break;
                     }
                     int rightPage = ctx.interiorFrame.getRightPage();
-                    parentNode.releaseWriteLatch();
+                    parentNode.releaseWriteLatch(true);
                     writeLatched = false;
                     bufferCache.unpin(parentNode);
 
@@ -529,7 +529,7 @@
                     ctx.interiorFrame.adjustKey(ctx.splitKey.getLeftTuple(), -1, ctx.cmp);
                 } catch (TreeIndexException e) {
                     if (writeLatched) {
-                        parentNode.releaseWriteLatch();
+                        parentNode.releaseWriteLatch(true);
                         writeLatched = false;
                         bufferCache.unpin(parentNode);
                     }
@@ -544,7 +544,7 @@
         } finally {
             if (!succeeded) {
                 if (writeLatched) {
-                    parentNode.releaseWriteLatch();
+                    parentNode.releaseWriteLatch(true);
                     writeLatched = false;
                     bufferCache.unpin(parentNode);
                 }
@@ -634,7 +634,7 @@
             try {
                 deleteTuple(tupleIndex, ctx);
             } finally {
-                ctx.leafFrame.getPage().releaseWriteLatch();
+                ctx.leafFrame.getPage().releaseWriteLatch(true);
                 bufferCache.unpin(ctx.leafFrame.getPage());
             }
         }
@@ -694,7 +694,7 @@
                         if (!ctx.leafFrame.isLeaf()) {
                             ctx.pathList.add(pageId, -1, -1);
 
-                            node.releaseWriteLatch();
+                            node.releaseWriteLatch(true);
                             writeLatched = false;
                             bufferCache.unpin(node);
                             continue;
@@ -707,7 +707,7 @@
                             if (tupleIndex == -1) {
                                 ctx.pathList.add(pageId, parentLsn, -1);
 
-                                node.releaseWriteLatch();
+                                node.releaseWriteLatch(true);
                                 writeLatched = false;
                                 bufferCache.unpin(node);
                                 continue;
@@ -732,7 +732,7 @@
                     readLatched = false;
                     bufferCache.unpin(node);
                 } else if (writeLatched) {
-                    node.releaseWriteLatch();
+                    node.releaseWriteLatch(true);
                     writeLatched = false;
                     bufferCache.unpin(node);
                 }
@@ -907,7 +907,7 @@
 
                     leafFrontier.pageId = freePageManager.getFreePage(metaFrame);
 
-                    leafFrontier.page.releaseWriteLatch();
+                    leafFrontier.page.releaseWriteLatch(true);
                     bufferCache.unpin(leafFrontier.page);
 
                     leafFrontier.page = bufferCache.pin(BufferedFileHandle.getDiskPageId(fileId, leafFrontier.pageId),
@@ -974,7 +974,7 @@
                 propagateBulk(level + 1, toRoot);
                 propagated = true;
 
-                frontier.page.releaseWriteLatch();
+                frontier.page.releaseWriteLatch(true);
                 bufferCache.unpin(frontier.page);
                 frontier.pageId = freePageManager.getFreePage(metaFrame);
 
diff --git a/hyracks/hyracks-storage-am-rtree/src/main/java/edu/uci/ics/hyracks/storage/am/rtree/impls/RTreeSearchCursor.java b/hyracks/hyracks-storage-am-rtree/src/main/java/edu/uci/ics/hyracks/storage/am/rtree/impls/RTreeSearchCursor.java
index c71b3eb..ab82f08 100644
--- a/hyracks/hyracks-storage-am-rtree/src/main/java/edu/uci/ics/hyracks/storage/am/rtree/impls/RTreeSearchCursor.java
+++ b/hyracks/hyracks-storage-am-rtree/src/main/java/edu/uci/ics/hyracks/storage/am/rtree/impls/RTreeSearchCursor.java
@@ -252,4 +252,9 @@
     public boolean exclusiveLatchNodes() {
         return false;
     }
+    
+    @Override
+    public void markCurrentTupleAsUpdated() throws HyracksDataException {
+        throw new HyracksDataException("Updating tuples is not supported with this cursor.");
+    }
 }
\ No newline at end of file
diff --git a/hyracks/hyracks-storage-common/src/main/java/edu/uci/ics/hyracks/storage/common/buffercache/BufferCache.java b/hyracks/hyracks-storage-common/src/main/java/edu/uci/ics/hyracks/storage/common/buffercache/BufferCache.java
index ac722e2..4162dc2 100644
--- a/hyracks/hyracks-storage-common/src/main/java/edu/uci/ics/hyracks/storage/common/buffercache/BufferCache.java
+++ b/hyracks/hyracks-storage-common/src/main/java/edu/uci/ics/hyracks/storage/common/buffercache/BufferCache.java
@@ -474,23 +474,9 @@
             latch.readLock().lock();
         }
 
-        private void acquireWriteLatch(boolean markDirty) {
-            latch.writeLock().lock();
-            if (markDirty) {
-                markDirty();
-            }
-        }
-
-        @Override
-        public void markDirty() {
-            if (dirty.compareAndSet(false, true)) {
-                pinCount.incrementAndGet();
-            }
-        }
-
         @Override
         public void acquireWriteLatch() {
-            acquireWriteLatch(true);
+            latch.writeLock().lock();
         }
 
         @Override
@@ -499,7 +485,12 @@
         }
 
         @Override
-        public void releaseWriteLatch() {
+        public void releaseWriteLatch(boolean markDirty) {
+            if (markDirty) {
+                if (dirty.compareAndSet(false, true)) {
+                    pinCount.incrementAndGet();
+                }
+            }
             latch.writeLock().unlock();
         }
     }
diff --git a/hyracks/hyracks-storage-common/src/main/java/edu/uci/ics/hyracks/storage/common/buffercache/ICachedPage.java b/hyracks/hyracks-storage-common/src/main/java/edu/uci/ics/hyracks/storage/common/buffercache/ICachedPage.java
index b5bf3bb..6c86597 100644
--- a/hyracks/hyracks-storage-common/src/main/java/edu/uci/ics/hyracks/storage/common/buffercache/ICachedPage.java
+++ b/hyracks/hyracks-storage-common/src/main/java/edu/uci/ics/hyracks/storage/common/buffercache/ICachedPage.java
@@ -25,5 +25,5 @@
 
     public void acquireWriteLatch();
 
-    public void releaseWriteLatch();
+    public void releaseWriteLatch(boolean markDirty);
 }
\ No newline at end of file
diff --git a/hyracks/hyracks-tests/hyracks-storage-am-btree-test/src/test/java/edu/uci/ics/hyracks/storage/am/btree/StorageManagerTest.java b/hyracks/hyracks-tests/hyracks-storage-am-btree-test/src/test/java/edu/uci/ics/hyracks/storage/am/btree/StorageManagerTest.java
index 29da625..5f77d68 100644
--- a/hyracks/hyracks-tests/hyracks-storage-am-btree-test/src/test/java/edu/uci/ics/hyracks/storage/am/btree/StorageManagerTest.java
+++ b/hyracks/hyracks-tests/hyracks-storage-am-btree-test/src/test/java/edu/uci/ics/hyracks/storage/am/btree/StorageManagerTest.java
@@ -154,7 +154,7 @@
                         if (LOGGER.isLoggable(Level.INFO)) {
                             LOGGER.info(workerId + " X UNLATCHING: " + plPage.pageId);
                         }
-                        plPage.page.releaseWriteLatch();
+                        plPage.page.releaseWriteLatch(true);
                     }
                 }
                 if (LOGGER.isLoggable(Level.INFO)) {
diff --git a/hyracks/hyracks-tests/hyracks-storage-common-test/src/test/java/edu/uci/ics/hyracks/storage/common/BufferCacheRegressionTest.java b/hyracks/hyracks-tests/hyracks-storage-common-test/src/test/java/edu/uci/ics/hyracks/storage/common/BufferCacheRegressionTest.java
index 577abbb..ba1715f 100644
--- a/hyracks/hyracks-tests/hyracks-storage-common-test/src/test/java/edu/uci/ics/hyracks/storage/common/BufferCacheRegressionTest.java
+++ b/hyracks/hyracks-tests/hyracks-storage-common-test/src/test/java/edu/uci/ics/hyracks/storage/common/BufferCacheRegressionTest.java
@@ -81,7 +81,7 @@
                 buf.put(Byte.MAX_VALUE);
             }
         } finally {
-            writePage.releaseWriteLatch();
+            writePage.releaseWriteLatch(true);
             bufferCache.unpin(writePage);
         }
         bufferCache.closeFile(firstFileId);
diff --git a/hyracks/hyracks-tests/hyracks-storage-common-test/src/test/java/edu/uci/ics/hyracks/storage/common/BufferCacheTest.java b/hyracks/hyracks-tests/hyracks-storage-common-test/src/test/java/edu/uci/ics/hyracks/storage/common/BufferCacheTest.java
index c67386e..118a27c 100644
--- a/hyracks/hyracks-tests/hyracks-storage-common-test/src/test/java/edu/uci/ics/hyracks/storage/common/BufferCacheTest.java
+++ b/hyracks/hyracks-tests/hyracks-storage-common-test/src/test/java/edu/uci/ics/hyracks/storage/common/BufferCacheTest.java
@@ -91,7 +91,7 @@
             bufferCache.unpin(page2);
 
         } finally {
-            page.releaseWriteLatch();
+            page.releaseWriteLatch(true);
             bufferCache.unpin(page);
         }
 
@@ -228,7 +228,7 @@
                 }
                 pageContents.put(fileId, values);
             } finally {
-                page.releaseWriteLatch();
+                page.releaseWriteLatch(true);
                 bufferCache.unpin(page);
             }
         }