You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hbase.apache.org by st...@apache.org on 2011/11/24 00:31:13 UTC

svn commit: r1205660 - in /hbase/branches/0.92: CHANGES.txt src/main/java/org/apache/hadoop/hbase/client/HConnectionManager.java src/main/java/org/apache/hadoop/hbase/util/SoftValueSortedMap.java

Author: stack
Date: Wed Nov 23 23:31:12 2011
New Revision: 1205660

URL: http://svn.apache.org/viewvc?rev=1205660&view=rev
Log:
HBASE-4785 Improve recovery time of HBase client when a region server dies

Modified:
    hbase/branches/0.92/CHANGES.txt
    hbase/branches/0.92/src/main/java/org/apache/hadoop/hbase/client/HConnectionManager.java
    hbase/branches/0.92/src/main/java/org/apache/hadoop/hbase/util/SoftValueSortedMap.java

Modified: hbase/branches/0.92/CHANGES.txt
URL: http://svn.apache.org/viewvc/hbase/branches/0.92/CHANGES.txt?rev=1205660&r1=1205659&r2=1205660&view=diff
==============================================================================
--- hbase/branches/0.92/CHANGES.txt (original)
+++ hbase/branches/0.92/CHANGES.txt Wed Nov 23 23:31:12 2011
@@ -442,6 +442,7 @@ Release 0.92.0 - Unreleased
    HBASE-4308  Race between RegionOpenedHandler and AssignmentManager (Ram)
    HBASE-4857  Recursive loop on KeeperException in
                AuthenticationTokenSecretManager/ZKLeaderManager
+   HBASE-4785  Improve recovery time of HBase client when a region server dies
 
   TESTS
    HBASE-4492  TestRollingRestart fails intermittently

Modified: hbase/branches/0.92/src/main/java/org/apache/hadoop/hbase/client/HConnectionManager.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.92/src/main/java/org/apache/hadoop/hbase/client/HConnectionManager.java?rev=1205660&r1=1205659&r2=1205660&view=diff
==============================================================================
--- hbase/branches/0.92/src/main/java/org/apache/hadoop/hbase/client/HConnectionManager.java (original)
+++ hbase/branches/0.92/src/main/java/org/apache/hadoop/hbase/client/HConnectionManager.java Wed Nov 23 23:31:12 2011
@@ -23,7 +23,9 @@ import java.io.Closeable;
 import java.io.IOException;
 import java.lang.reflect.Proxy;
 import java.lang.reflect.UndeclaredThrowableException;
+import java.net.ConnectException;
 import java.net.InetSocketAddress;
+import java.net.SocketTimeoutException;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
@@ -31,8 +33,8 @@ import java.util.HashSet;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.NoSuchElementException;
 import java.util.Map.Entry;
+import java.util.NoSuchElementException;
 import java.util.Set;
 import java.util.TreeMap;
 import java.util.concurrent.Callable;
@@ -512,6 +514,13 @@ public class HConnectionManager {
       cachedRegionLocations =
         new HashMap<Integer, SoftValueSortedMap<byte [], HRegionLocation>>();
 
+    // The presence of a server in the map implies it's likely that there is an
+    // entry in cachedRegionLocations that map to this server; but the absence
+    // of a server in this map guarentees that there is no entry in cache that
+    // maps to the absent server.
+    private final Set<String> cachedServers =
+        new HashSet<String>();
+
     // region cache prefetch is enabled by default. this set contains all
     // tables whose region cache prefetch are disabled.
     private final Set<Integer> regionCachePrefetchDisabledTables =
@@ -1116,6 +1125,35 @@ public class HConnectionManager {
     }
 
     /*
+     * Delete all cached entries of a table that maps to a specific location.
+     *
+     * @param tablename
+     * @param server
+     */
+    private void clearCachedLocationForServer(
+        final String server) {
+      boolean deletedSomething = false;
+      synchronized (this.cachedRegionLocations) {
+        if (!cachedServers.contains(server)) {
+          return;
+        }
+        for (SoftValueSortedMap<byte[], HRegionLocation> tableLocations :
+            cachedRegionLocations.values()) {
+          for (Entry<byte[], HRegionLocation> e : tableLocations.entrySet()) {
+            if (e.getValue().getServerAddress().toString().equals(server)) {
+              tableLocations.remove(e.getKey());
+              deletedSomething = true;
+            }
+          }
+        }
+        cachedServers.remove(server);
+      }
+      if (deletedSomething && LOG.isDebugEnabled()) {
+        LOG.debug("Removed all cached region locations that map to " + server);
+      }
+    }
+
+    /*
      * @param tableName
      * @return Map of cached locations for passed <code>tableName</code>
      */
@@ -1140,6 +1178,7 @@ public class HConnectionManager {
     public void clearRegionCache() {
       synchronized(this.cachedRegionLocations) {
         this.cachedRegionLocations.clear();
+        this.cachedServers.clear();
       }
     }
 
@@ -1158,7 +1197,12 @@ public class HConnectionManager {
       byte [] startKey = location.getRegionInfo().getStartKey();
       SoftValueSortedMap<byte [], HRegionLocation> tableLocations =
         getTableLocations(tableName);
-      if (tableLocations.put(startKey, location) == null) {
+      boolean hasNewCache = false;
+      synchronized (this.cachedRegionLocations) {
+        cachedServers.add(location.getServerAddress().toString());
+        hasNewCache = (tableLocations.put(startKey, location) == null);
+      }
+      if (hasNewCache) {
         LOG.debug("Cached location for " +
             location.getRegionInfo().getRegionNameAsString() +
             " is " + location.getHostnamePort());
@@ -1281,6 +1325,17 @@ public class HConnectionManager {
         } catch (Throwable t) {
           callable.shouldRetry(t);
           t = translateException(t);
+          if (t instanceof SocketTimeoutException ||
+              t instanceof ConnectException ||
+              t instanceof RetriesExhaustedException) {
+            // if thrown these exceptions, we clear all the cache entries that
+            // map to that slow/dead server; otherwise, let cache miss and ask
+            // .META. again to find the new location
+            HRegionLocation hrl = callable.location;
+            if (hrl != null) {
+              clearCachedLocationForServer(hrl.getServerAddress().toString());
+            }
+          }
           RetriesExhaustedException.ThrowableWithExtraContext qt =
             new RetriesExhaustedException.ThrowableWithExtraContext(t,
               System.currentTimeMillis(), callable.toString());

Modified: hbase/branches/0.92/src/main/java/org/apache/hadoop/hbase/util/SoftValueSortedMap.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.92/src/main/java/org/apache/hadoop/hbase/util/SoftValueSortedMap.java?rev=1205660&r1=1205659&r2=1205660&view=diff
==============================================================================
--- hbase/branches/0.92/src/main/java/org/apache/hadoop/hbase/util/SoftValueSortedMap.java (original)
+++ hbase/branches/0.92/src/main/java/org/apache/hadoop/hbase/util/SoftValueSortedMap.java Wed Nov 23 23:31:12 2011
@@ -24,6 +24,7 @@ import java.lang.ref.SoftReference;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Comparator;
+import java.util.LinkedHashSet;
 import java.util.Map;
 import java.util.Set;
 import java.util.SortedMap;
@@ -172,7 +173,13 @@ public class SoftValueSortedMap<K,V> imp
   }
 
   public synchronized Set<Map.Entry<K,V>> entrySet() {
-    throw new RuntimeException("Not implemented");
+    checkReferences();
+    Set<Map.Entry<K, SoftValue<K, V>>> entries = this.internalMap.entrySet();
+    Set<Map.Entry<K, V>> realEntries = new LinkedHashSet<Map.Entry<K, V>>();
+    for (Map.Entry<K, SoftValue<K, V>> entry : entries) {
+      realEntries.add(entry.getValue());
+    }
+    return realEntries;
   }
 
   public synchronized Collection<V> values() {
@@ -185,12 +192,24 @@ public class SoftValueSortedMap<K,V> imp
     return hardValues;
   }
 
-  private static class SoftValue<K,V> extends SoftReference<V> {
+  private static class SoftValue<K,V> extends SoftReference<V> implements Map.Entry<K, V> {
     final K key;
 
     SoftValue(K key, V value, ReferenceQueue q) {
       super(value, q);
       this.key = key;
     }
+
+    public K getKey() {
+      return this.key;
+    }
+
+    public V getValue() {
+      return get();
+    }
+
+    public V setValue(V value) {
+      throw new RuntimeException("Not implemented");
+    }
   }
 }