Repository: hbase
Updated Branches:
  refs/heads/branch-1.3 25995a2bf -> 70daa23ea


HBASE-16304 HRegion#RegionScannerImpl#handleFileNotFoundException may lead to 
deadlock when trying to obtain write lock on updatesLock


Project: http://git-wip-us.apache.org/repos/asf/hbase/repo
Commit: http://git-wip-us.apache.org/repos/asf/hbase/commit/70daa23e
Tree: http://git-wip-us.apache.org/repos/asf/hbase/tree/70daa23e
Diff: http://git-wip-us.apache.org/repos/asf/hbase/diff/70daa23e

Branch: refs/heads/branch-1.3
Commit: 70daa23ea79b21b9ae337bcf962ada26ac95c1a2
Parents: 25995a2
Author: tedyu <yuzhih...@gmail.com>
Authored: Wed Aug 24 11:28:24 2016 -0700
Committer: tedyu <yuzhih...@gmail.com>
Committed: Wed Aug 24 11:28:24 2016 -0700

----------------------------------------------------------------------
 .../hadoop/hbase/regionserver/HRegion.java      | 52 ++++++++++++++++++--
 1 file changed, 49 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/hbase/blob/70daa23e/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegion.java
----------------------------------------------------------------------
diff --git 
a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegion.java 
b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegion.java
index b56c887..d43e838 100644
--- 
a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegion.java
+++ 
b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegion.java
@@ -252,6 +252,9 @@ public class HRegion implements HeapSize, 
PropagatingConfigurationObserver, Regi
    */
   protected volatile long lastReplayedOpenRegionSeqId = -1L;
   protected volatile long lastReplayedCompactionSeqId = -1L;
+  
+  // collects Map(s) of Store to sequence Id when handleFileNotFound() is 
involved
+  protected List<Map> storeSeqIds = new ArrayList<>();
 
   
//////////////////////////////////////////////////////////////////////////////
   // Members
@@ -5036,6 +5039,7 @@ public class HRegion implements HeapSize, 
PropagatingConfigurationObserver, Regi
 
     startRegionOperation(); // obtain region close lock
     try {
+      Map<Store, Long> map = new HashMap<Store, Long>();
       synchronized (writestate) {
         for (Store store : getStores()) {
           // TODO: some stores might see new data from flush, while others do 
not which
@@ -5068,8 +5072,7 @@ public class HRegion implements HeapSize, 
PropagatingConfigurationObserver, Regi
               }
             }
 
-            // Drop the memstore contents if they are now smaller than the 
latest seen flushed file
-            totalFreedSize += dropMemstoreContentsForSeqId(storeSeqId, store);
+            map.put(store, storeSeqId);
           }
         }
 
@@ -5092,6 +5095,19 @@ public class HRegion implements HeapSize, 
PropagatingConfigurationObserver, Regi
           this.lastReplayedOpenRegionSeqId = smallestSeqIdInStores;
         }
       }
+      if (!map.isEmpty()) {
+        if (!force) {
+          for (Map.Entry<Store, Long> entry : map.entrySet()) {
+            // Drop the memstore contents if they are now smaller than the 
latest seen flushed file
+            totalFreedSize += dropMemstoreContentsForSeqId(entry.getValue(), 
entry.getKey());
+          }
+        } else {
+          synchronized (storeSeqIds) {
+            // don't try to acquire write lock of updatesLock now
+            storeSeqIds.add(map);
+          }
+        }
+      }
       // C. Finally notify anyone waiting on memstore to clear:
       // e.g. checkResources().
       synchronized (this) {
@@ -7364,6 +7380,28 @@ public class HRegion implements HeapSize, 
PropagatingConfigurationObserver, Regi
   // We should refactor append and increment as local get-mutate-put
   // transactions, so all stores only go through one code path for puts.
 
+  // dropMemstoreContentsForSeqId() would acquire write lock of updatesLock
+  // We perform this operation outside of the read lock of updatesLock to 
avoid dead lock
+  // See HBASE-16304
+  @SuppressWarnings("unchecked")
+  private void dropMemstoreContents() throws IOException {
+    long totalFreedSize = 0;
+    while (!storeSeqIds.isEmpty()) {
+      Map<Store, Long> map = null;
+      synchronized (storeSeqIds) {
+        if (storeSeqIds.isEmpty()) break;
+        map = storeSeqIds.remove(storeSeqIds.size()-1);
+      }
+      for (Map.Entry<Store, Long> entry : map.entrySet()) {
+        // Drop the memstore contents if they are now smaller than the latest 
seen flushed file
+        totalFreedSize += dropMemstoreContentsForSeqId(entry.getValue(), 
entry.getKey());
+      }
+    }
+    if (totalFreedSize > 0) {
+      LOG.debug("Freed " + totalFreedSize + " bytes from memstore");
+    }
+  }
+
   @Override
   public Result append(Append mutate, long nonceGroup, long nonce) throws 
IOException {
     Operation op = Operation.APPEND;
@@ -7522,6 +7560,10 @@ public class HRegion implements HeapSize, 
PropagatingConfigurationObserver, Regi
           }
         } finally {
           this.updatesLock.readLock().unlock();
+          // For increment/append, a region scanner for doing a get operation 
could throw 
+          // FileNotFoundException. So we call dropMemstoreContents() in 
finally block
+          // after releasing read lock
+          dropMemstoreContents();
         }
 
       } finally {
@@ -7745,6 +7787,10 @@ public class HRegion implements HeapSize, 
PropagatingConfigurationObserver, Regi
           }
         } finally {
           this.updatesLock.readLock().unlock();
+          // For increment/append, a region scanner for doing a get operation 
could throw 
+          // FileNotFoundException. So we call dropMemstoreContents() in 
finally block
+          // after releasing read lock
+          dropMemstoreContents();
         }
       } finally {
         rowLock.release();
@@ -7928,7 +7974,7 @@ public class HRegion implements HeapSize, 
PropagatingConfigurationObserver, Regi
   public static final long FIXED_OVERHEAD = ClassSize.align(
       ClassSize.OBJECT +
       ClassSize.ARRAY +
-      45 * ClassSize.REFERENCE + 3 * Bytes.SIZEOF_INT +
+      46 * ClassSize.REFERENCE + 3 * Bytes.SIZEOF_INT +
       (14 * Bytes.SIZEOF_LONG) +
       5 * Bytes.SIZEOF_BOOLEAN);
 

Reply via email to