hbase-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From li...@apache.org
Subject svn commit: r1584181 - in /hbase/branches/0.89-fb/src: main/java/org/apache/hadoop/hbase/client/ test/java/org/apache/hadoop/hbase/client/
Date Wed, 02 Apr 2014 21:03:38 GMT
Author: liyin
Date: Wed Apr  2 21:03:37 2014
New Revision: 1584181

URL: http://svn.apache.org/r1584181
Log:
[HBASE-10776] Extract location cache function out as MetaCache

Author: daviddeng

Summary: Add `MetaCache` class

Test Plan: Testcase

Reviewers: manukranthk, fan, liyintang, gauravm

Reviewed By: liyintang

CC: hbase-eng@

Differential Revision: https://phabricator.fb.com/D1233412

Added:
    hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/client/MetaCache.java
    hbase/branches/0.89-fb/src/test/java/org/apache/hadoop/hbase/client/TestMetaCache.java
Modified:
    hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/client/HConnection.java
    hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/client/HConnectionManager.java
    hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/client/TableServers.java
    hbase/branches/0.89-fb/src/test/java/org/apache/hadoop/hbase/client/TestFastFail.java
    hbase/branches/0.89-fb/src/test/java/org/apache/hadoop/hbase/client/TestHCM.java

Modified: hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/client/HConnection.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/client/HConnection.java?rev=1584181&r1=1584180&r2=1584181&view=diff
==============================================================================
--- hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/client/HConnection.java (original)
+++ hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/client/HConnection.java Wed
Apr  2 21:03:37 2014
@@ -19,6 +19,14 @@
  */
 package org.apache.hadoop.hbase.client;
 
+import java.io.Closeable;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ExecutorService;
+
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.hbase.HRegionInfo;
 import org.apache.hadoop.hbase.HRegionLocation;
@@ -30,14 +38,6 @@ import org.apache.hadoop.hbase.ipc.HMast
 import org.apache.hadoop.hbase.ipc.HRegionInterface;
 import org.apache.hadoop.hbase.zookeeper.ZooKeeperWrapper;
 
-import java.io.Closeable;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ExecutorService;
-
 /**
  * Cluster connection.
  * {@link HConnectionManager} manages instances of this class.
@@ -262,7 +262,7 @@ public interface HConnection extends Clo
    * @return Count of committed Deletes. On fault, < list.size().
    * @throws IOException if a remote or network exception occurs
    */
-  public int processBatchOfDeletes(List<Delete> list, byte[] tableName, 
+  public int processBatchOfDeletes(List<Delete> list, byte[] tableName,
       final HBaseRPCOptions options)
   throws IOException;
 
@@ -311,9 +311,9 @@ public interface HConnection extends Clo
 
   /**
    * Process the MultiPut request by submitting it to the multiPutThreadPool in HTable.
-   * The request will be sent to its destination region server by one thread in 
+   * The request will be sent to its destination region server by one thread in
    * the HTable's multiPutThreadPool.
-   * 
+   *
    * Also it will return the list of failed put among the MultiPut request or return null
if all
    * puts are sent to the HRegionServer successfully.
    * @param mputs The list of MultiPut requests
@@ -326,7 +326,7 @@ public interface HConnection extends Clo
   public List<Put> processListOfMultiPut(List<MultiPut> mputs,
       final byte[] tableName, HBaseRPCOptions options,
       Map<String, HRegionFailureInfo> failureInfo) throws IOException;
-  
+
   /**
    * Delete the cached location
    * @param tableName
@@ -335,7 +335,7 @@ public interface HConnection extends Clo
    */
   public void deleteCachedLocation(final byte [] tableName, final byte [] row,
       HServerAddress oldLoc);
-  
+
   /**
    * Enable or disable region cache prefetch for the table. It will be
    * applied for the given table's all HTable instances within this
@@ -348,15 +348,16 @@ public interface HConnection extends Clo
 
   /**
    * Check whether region cache prefetch is enabled or not.
+   *
    * @param tableName name of table to check
-   * @return true if table's region cache prefecth is enabled. Otherwise
-   * it is disabled.
+   * @return true if table's region cache prefetch is enabled. Otherwise
+   *         it is disabled.
    */
   public boolean getRegionCachePrefetch(final byte[] tableName);
 
   /**
    * Load the region map and warm up the global region cache for the table.
-   * @param tableName name of the table to perform region cache prewarm.
+   * @param tableName name of the table to perform region cache warm-up.
    * @param regions a region map.
    */
   public void prewarmRegionCache(final byte[] tableName,

Modified: hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/client/HConnectionManager.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/client/HConnectionManager.java?rev=1584181&r1=1584180&r2=1584181&view=diff
==============================================================================
--- hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/client/HConnectionManager.java
(original)
+++ hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/client/HConnectionManager.java
Wed Apr  2 21:03:37 2014
@@ -19,17 +19,17 @@
  */
 package org.apache.hadoop.hbase.client;
 
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.hbase.HBaseConfiguration;
 import org.apache.hadoop.hbase.ipc.HBaseRPC;
 import org.apache.hadoop.hbase.ipc.thrift.HBaseThriftRPC;
 import org.apache.hadoop.hbase.zookeeper.ZooKeeperWrapper;
 
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.LinkedHashMap;
-import java.util.Map;
-
 /**
  * A non-instantiable class that manages connections to multiple tables in
  * multiple HBase instances.
@@ -169,7 +169,7 @@ public class HConnectionManager {
    */
   static int getCachedRegionCount(Configuration conf, byte[] tableName) {
     TableServers connection = (TableServers) getConnection(conf);
-    return connection.getNumberOfCachedRegionLocations(tableName);
+    return connection.metaCache.getNumber(tableName);
   }
 
   /**
@@ -178,8 +178,9 @@ public class HConnectionManager {
    *
    * @return true if the region where the table and row reside is cached.
    */
-  static boolean isRegionCached(Configuration conf, byte[] tableName, byte[] row) {
+  static boolean isRegionCached(Configuration conf, byte[] tableName,
+      byte[] row) {
     TableServers connection = (TableServers) getConnection(conf);
-    return connection.isRegionCached(tableName, row);
+    return connection.metaCache.getForRow(tableName, row) != null;
   }
 }

Added: hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/client/MetaCache.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/client/MetaCache.java?rev=1584181&view=auto
==============================================================================
--- hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/client/MetaCache.java (added)
+++ hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/client/MetaCache.java Wed
Apr  2 21:03:37 2014
@@ -0,0 +1,240 @@
+/**
+ * Copyright 2014 The Apache Software Foundation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.hadoop.hbase.client;
+
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.NavigableMap;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentSkipListMap;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.hadoop.hbase.HConstants;
+import org.apache.hadoop.hbase.HRegionLocation;
+import org.apache.hadoop.hbase.HServerAddress;
+import org.apache.hadoop.hbase.KeyValue;
+import org.apache.hadoop.hbase.util.Bytes;
+
+/**
+ * Cache for meta information (HRegionLocation)
+ */
+public class MetaCache {
+  static final Log LOG = LogFactory.getLog(MetaCache.class);
+
+  public final Map<Integer, ConcurrentSkipListMap<byte[], HRegionLocation>>
+    tableToCache = new ConcurrentHashMap<>();
+
+  // 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 guarantees that there is no entry in cache that
+  // maps to the absent server.
+  private final Set<String> servers = new HashSet<>();
+
+  public Set<String> getServers() {
+    return servers;
+  }
+
+  /**
+   * Gets meta cache map of a table.
+   *
+   * @return Map of cached locations for passed <code>tableName</code>. A new
+   *         map is created if not found.
+   */
+  public NavigableMap<byte[], HRegionLocation> getForTable(
+      final byte[] tableName) {
+    // find the map of cached locations for this table
+    Integer key = Bytes.mapKey(tableName);
+    ConcurrentSkipListMap<byte[], HRegionLocation> result =
+        this.tableToCache.get(key);
+    if (result == null) {
+      synchronized (this.tableToCache) {
+        result = this.tableToCache.get(key);
+        if (result == null) {
+          // if tableLocations for this table isn't built yet, make one
+          result = new ConcurrentSkipListMap<>(Bytes.BYTES_COMPARATOR);
+          this.tableToCache.put(key, result);
+        }
+      }
+    }
+    return result;
+  }
+
+  /*
+   * Searches the cache for a location that fits our table and row key.
+   * Return null if no suitable region is located. TODO: synchronization note
+   *
+   * <p>TODO: This method during writing consumes 15% of CPU doing lookup
+   * into the Soft Reference SortedMap.  Improve.
+   *
+   * @param tableName
+   * @param row
+   * @return Null or region location found in cache.
+   */
+  HRegionLocation getForRow(final byte[] tableName, final byte[] row) {
+    NavigableMap<byte[], HRegionLocation> tableMeta = getForTable(tableName);
+
+    // start to examine the cache. we can only do cache actions
+    // if there's something in the cache for this table.
+    if (tableMeta.isEmpty()) {
+      return null;
+    }
+
+    HRegionLocation rl = tableMeta.get(row);
+    if (rl != null) {
+      if (LOG.isTraceEnabled()) {
+        LOG.trace("Cache hit for row <" + Bytes.toStringBinary(row)
+            + "> in tableName " + Bytes.toStringBinary(tableName)
+            + ": location server " + rl.getServerAddress()
+            + ", location region name "
+            + rl.getRegionInfo().getRegionNameAsString());
+      }
+      return rl;
+    }
+
+    // get the matching region for the row
+    Entry<byte[], HRegionLocation> entry = tableMeta.floorEntry(row);
+    HRegionLocation possibleRegion = (entry == null) ? null : entry.getValue();
+
+    // we need to examine the cached location to verify that it is
+    // a match by end key as well.
+    if (possibleRegion != null) {
+      byte[] endKey = possibleRegion.getRegionInfo().getEndKey();
+
+      // make sure that the end key is greater than the row we're looking
+      // for, otherwise the row actually belongs in the next region, not
+      // this one. the exception case is when the end key is
+      // HConstants.EMPTY_START_ROW, signifying that the region we're
+      // checking is actually the last region in the table.
+      if (Bytes.equals(endKey, HConstants.EMPTY_END_ROW)
+          || KeyValue.getRowComparator(tableName).compareRows(endKey, 0,
+              endKey.length, row, 0, row.length) > 0) {
+        return possibleRegion;
+      }
+    }
+
+    // Passed all the way through, so we got nothing - complete cache miss
+    return null;
+  }
+
+  /**
+   * Deletes a cached meta for the specified table name and row if it is
+   * located on the (optionally) specified old location.
+   */
+  public void deleteForRow(final byte[] tableName, final byte[] row,
+      HServerAddress oldServer) {
+    synchronized (this.tableToCache) {
+      Map<byte[], HRegionLocation> tableLocations = getForTable(tableName);
+
+      // start to examine the cache. we can only do cache actions
+      // if there's something in the cache for this table.
+      if (!tableLocations.isEmpty()) {
+        HRegionLocation rl = getForRow(tableName, row);
+        if (rl != null) {
+          // If oldLocation is specified. deleteLocation only if it is the
+          // same.
+          if (oldServer != null && !oldServer.equals(rl.getServerAddress()))
+            return; // perhaps, some body else cleared and re-populated.
+
+          tableLocations.remove(rl.getRegionInfo().getStartKey());
+          if (LOG.isDebugEnabled()) {
+            LOG.debug("Removed " + rl.getRegionInfo().getRegionNameAsString()
+                + " for tableName=" + Bytes.toStringBinary(tableName)
+                + " from cache " + "because of " + Bytes.toStringBinary(row));
+          }
+        }
+      }
+    }
+  }
+
+  /**
+   * Deletes all cached entries of a table that maps to a specific location.
+   *
+   */
+  protected void clearForServer(final String server) {
+    boolean deletedSomething = false;
+    synchronized (this.tableToCache) {
+      if (!servers.contains(server)) {
+        return;
+      }
+      for (Map<byte[], HRegionLocation> tableLocations : tableToCache
+          .values()) {
+        for (Entry<byte[], HRegionLocation> e : tableLocations.entrySet()) {
+          if (e.getValue().getServerAddress().toString().equals(server)) {
+            tableLocations.remove(e.getKey());
+            deletedSomething = true;
+          }
+        }
+      }
+      servers.remove(server);
+    }
+    if (deletedSomething && LOG.isDebugEnabled()) {
+      LOG.debug("Removed all cached region locations that map to " + server);
+    }
+  }
+
+  /**
+   * Adds a newly discovered HRegionLocation into the cache.
+   *
+   * FIXME the first parameter seems not necessary.
+   */
+  public void add(final byte[] tableName, final HRegionLocation location) {
+    byte[] startKey = location.getRegionInfo().getStartKey();
+    boolean hasNewCache;
+    synchronized (this.tableToCache) {
+      servers.add(location.getServerAddress().toString());
+      hasNewCache = (getForTable(tableName).put(startKey, location) == null);
+    }
+    if (hasNewCache) {
+      LOG.debug("Cached location for "
+          + location.getRegionInfo().getRegionNameAsString() + " is "
+          + location.getServerAddress().toString());
+    }
+  }
+
+  /**
+   * Clears all meta cache
+   */
+  public void clear() {
+    synchronized (this.tableToCache) {
+      tableToCache.clear();
+      servers.clear();
+    }
+  }
+
+  /*
+   * Returns the number of cached regions for a table. It will only be called
+   * from a unit test.
+   */
+  int getNumber(final byte[] tableName) {
+    Integer key = Bytes.mapKey(tableName);
+    synchronized (this.tableToCache) {
+      Map<byte[], HRegionLocation> tableLocs = this.tableToCache.get(key);
+
+      if (tableLocs == null) {
+        return 0;
+      }
+      return tableLocs.size();
+    }
+  }
+
+}

Modified: hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/client/TableServers.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/client/TableServers.java?rev=1584181&r1=1584180&r2=1584181&view=diff
==============================================================================
--- hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/client/TableServers.java
(original)
+++ hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/client/TableServers.java
Wed Apr  2 21:03:37 2014
@@ -1,3 +1,22 @@
+/**
+ * Copyright 2014 The Apache Software Foundation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.apache.hadoop.hbase.client;
 
 import java.io.EOFException;
@@ -13,7 +32,6 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
@@ -25,7 +43,6 @@ import java.util.concurrent.Callable;
 import java.util.concurrent.CancellationException;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.ConcurrentSkipListMap;
 import java.util.concurrent.ConcurrentSkipListSet;
 import java.util.concurrent.CopyOnWriteArraySet;
 import java.util.concurrent.ExecutionException;
@@ -45,7 +62,6 @@ import org.apache.hadoop.hbase.HRegionIn
 import org.apache.hadoop.hbase.HRegionLocation;
 import org.apache.hadoop.hbase.HServerAddress;
 import org.apache.hadoop.hbase.HTableDescriptor;
-import org.apache.hadoop.hbase.KeyValue;
 import org.apache.hadoop.hbase.MasterNotRunningException;
 import org.apache.hadoop.hbase.NotServingRegionException;
 import org.apache.hadoop.hbase.RemoteExceptionHandler;
@@ -97,7 +113,7 @@ public class TableServers implements Ser
   // Used by master and region servers during safe mode only
   private volatile HRegionLocation rootRegionLocation;
 
-  private final Map<Integer, ConcurrentSkipListMap<byte[], HRegionLocation>>
cachedRegionLocations = new ConcurrentHashMap<Integer, ConcurrentSkipListMap<byte[],
HRegionLocation>>();
+  MetaCache metaCache = new MetaCache();
 
   // amount of time to wait before we consider a server to be in fast fail
   // mode
@@ -204,14 +220,6 @@ public class TableServers implements Ser
   public Map<HServerAddress, FailureInfo> getFailureMap() {
     return repeatedFailuresMap;
   }
-
-  // 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 guarantees 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 =
@@ -626,7 +634,7 @@ public class TableServers implements Ser
   }
 
   private HRegionLocation prefetchRegionCache(final byte[] tableName,
-                                   final byte[] row) {
+      final byte[] row) {
     return prefetchRegionCache(tableName, row, this.prefetchRegionLimit);
   }
 
@@ -635,7 +643,7 @@ public class TableServers implements Ser
    * row we're seeking. It will prefetch certain number of regions info and
    * save them to the global region cache.
    */
-  private HRegionLocation prefetchRegionCache(final byte[] tableName,
+  public HRegionLocation prefetchRegionCache(final byte[] tableName,
       final byte[] row, int prefetchRegionLimit) {
     // Implement a new visitor for MetaScanner, and use it to walk through
     // the .META.
@@ -677,7 +685,7 @@ public class TableServers implements Ser
             HRegionLocation loc = new HRegionLocation(regionInfo,
                 new HServerAddress(serverAddress), serverStartCode);
             // cache this meta entry
-            cacheLocation(tableName, loc);
+            metaCache.add(tableName, loc);
           }
           return true;
         } catch (RuntimeException e) {
@@ -688,7 +696,7 @@ public class TableServers implements Ser
     try {
       // pre-fetch certain number of regions info at region cache.
       MetaScanner.metaScan(conf, visitor, tableName, row, prefetchRegionLimit);
-      return getCachedLocation(tableName, row);
+      return metaCache.getForRow(tableName, row);
     } catch (IOException e) {
       LOG.warn("Encounted problems when prefetch META table: ", e);
     }
@@ -705,7 +713,7 @@ public class TableServers implements Ser
   throws IOException {
     HRegionLocation location;
     if (useCache) {
-      location = getCachedLocation(tableName, row);
+      location = metaCache.getForRow(tableName, row);
       if (location != null) {
         return location;
       }
@@ -765,7 +773,7 @@ public class TableServers implements Ser
             // be using the cache, delete any existing cached location so it won't
             // interfere.
             if (useCache) {
-              location = getCachedLocation(tableName, row);
+              location = metaCache.getForRow(tableName, row);
               if (location != null) {
                 return location;
               }
@@ -800,7 +808,7 @@ public class TableServers implements Ser
       }
       location = getLocationFromRow(regionInfoRow, tableName,
         parentTable, row);
-      cacheLocation(tableName, location);
+      metaCache.add(tableName, location);
       return location;
     } catch (TableNotFoundException e) {
       // if we got this error, probably means the table just plain doesn't
@@ -915,7 +923,7 @@ private HRegionLocation locateMetaInRoot
   final byte[] parentTable = HConstants.ROOT_TABLE_NAME;
   final byte[] tableName = HConstants.META_TABLE_NAME;
   if (useCache) {
-    location = getCachedLocation(tableName, row);
+      location = metaCache.getForRow(tableName, row);
     if (location != null) {
       return location;
     }
@@ -995,7 +1003,7 @@ private HRegionLocation locateMetaInRoot
         // the second will use the value that the first one found.
         synchronized (metaRegionLock) {
           if (useCache) {
-            location = getCachedLocation(tableName, row);
+              location = metaCache.getForRow(tableName, row);
             if (location != null) {
               return location;
             }
@@ -1012,7 +1020,7 @@ private HRegionLocation locateMetaInRoot
             HConstants.CATALOG_FAMILY);
           location = getLocationFromRow(regionInfoRow, tableName,
             parentTable, row);
-          cacheLocation(tableName, location);
+          metaCache.add(tableName, location);
         }
       } catch (Throwable t) {
         throw t;
@@ -1089,161 +1097,20 @@ private HRegionLocation locateMetaInRoot
   }
 
   @Override
-  public Collection<HRegionLocation> getCachedHRegionLocations(final byte [] tableName,
-                                                               boolean forceRefresh) {
+  public Collection<HRegionLocation> getCachedHRegionLocations(
+      final byte[] tableName, boolean forceRefresh) {
     if (forceRefresh || !initializedTableSet.contains(tableName)) {
       prefetchRegionCache(tableName, null, Integer.MAX_VALUE);
       initializedTableSet.add(tableName);
     }
 
-    ConcurrentSkipListMap<byte [], HRegionLocation> tableLocations =
-      getTableLocations(tableName);
-    return tableLocations.values();
-  }
-
-  /*
-   * Search the cache for a location that fits our table and row key.
-   * Return null if no suitable region is located. TODO: synchronization note
-   *
-   * <p>TODO: This method during writing consumes 15% of CPU doing lookup
-   * into the Soft Reference SortedMap.  Improve.
-   *
-   * @param tableName
-   * @param row
-   * @return Null or region location found in cache.
-   */
-  HRegionLocation getCachedLocation(final byte [] tableName,
-      final byte [] row) {
-    ConcurrentSkipListMap<byte [], HRegionLocation> tableLocations =
-      getTableLocations(tableName);
-
-    // start to examine the cache. we can only do cache actions
-    // if there's something in the cache for this table.
-    if (tableLocations.isEmpty()) {
-      return null;
-    }
-
-    HRegionLocation rl = tableLocations.get(row);
-    if (rl != null) {
-      if (LOG.isTraceEnabled()) {
-        LOG.trace("Cache hit for row <" + Bytes.toStringBinary(row)
-            + "> in tableName " + Bytes.toStringBinary(tableName)
-            + ": location server " + rl.getServerAddress()
-            + ", location region name "
-            + rl.getRegionInfo().getRegionNameAsString());
-      }
-      return rl;
-    }
-
-    // get the matching region for the row
-    Entry<byte[], HRegionLocation> entry = tableLocations.floorEntry(row);
-    HRegionLocation possibleRegion = (entry == null) ? null : entry
-        .getValue();
-
-    // we need to examine the cached location to verify that it is
-    // a match by end key as well.
-    if (possibleRegion != null) {
-      byte[] endKey = possibleRegion.getRegionInfo().getEndKey();
-
-      // make sure that the end key is greater than the row we're looking
-      // for, otherwise the row actually belongs in the next region, not
-      // this one. the exception case is when the endkey is
-      // HConstants.EMPTY_START_ROW, signifying that the region we're
-      // checking is actually the last region in the table.
-      if (Bytes.equals(endKey, HConstants.EMPTY_END_ROW)
-          || KeyValue.getRowComparator(tableName).compareRows(endKey, 0,
-              endKey.length, row, 0, row.length) > 0) {
-        return possibleRegion;
-      }
-    }
-
-    // Passed all the way through, so we got nothing - complete cache miss
-    return null;
+    return metaCache.getForTable(tableName).values();
   }
 
-  /*
-   * Delete a cached location for the specified table name and row if it is
-   * located on the (optionally) specified old location.
-   */
   @Override
   public void deleteCachedLocation(final byte[] tableName, final byte[] row,
       HServerAddress oldServer) {
-    synchronized (this.cachedRegionLocations) {
-      Map<byte[], HRegionLocation> tableLocations = getTableLocations(tableName);
-
-      // start to examine the cache. we can only do cache actions
-      // if there's something in the cache for this table.
-      if (!tableLocations.isEmpty()) {
-        HRegionLocation rl = getCachedLocation(tableName, row);
-        if (rl != null) {
-          // If oldLocation is specified. deleteLocation only if it is the
-          // same.
-          if (oldServer != null && !oldServer.equals(rl.getServerAddress()))
-            return; // perhaps, some body else cleared and repopulated.
-
-          tableLocations.remove(rl.getRegionInfo().getStartKey());
-          if (LOG.isDebugEnabled()) {
-            LOG.debug("Removed " + rl.getRegionInfo().getRegionNameAsString()
-                + " for tableName=" + Bytes.toStringBinary(tableName)
-                + " from cache " + "because of " + Bytes.toStringBinary(row));
-          }
-        }
-      }
-    }
-  }
-
-  /*
-   * Delete all cached entries of a table that maps to a specific location.
-   *
-   * @param tablename
-   *
-   * @param server
-   */
-  protected void clearCachedLocationForServer(final String server) {
-    boolean deletedSomething = false;
-    synchronized (this.cachedRegionLocations) {
-      if (!cachedServers.contains(server)) {
-        return;
-      }
-      for (Map<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>
-   */
-  private ConcurrentSkipListMap<byte[], HRegionLocation> getTableLocations(
-      final byte[] tableName) {
-    // find the map of cached locations for this table
-    Integer key = Bytes.mapKey(tableName);
-    ConcurrentSkipListMap<byte[], HRegionLocation> result = this.cachedRegionLocations
-        .get(key);
-    if (result == null) {
-      synchronized (this.cachedRegionLocations) {
-        result = this.cachedRegionLocations.get(key);
-        if (result == null) {
-          // if tableLocations for this table isn't built yet, make one
-          result = new ConcurrentSkipListMap<byte[], HRegionLocation>(
-              Bytes.BYTES_COMPARATOR);
-          this.cachedRegionLocations.put(key, result);
-        }
-      }
-    }
-    return result;
+    metaCache.deleteForRow(tableName, row, oldServer);
   }
 
   /**
@@ -1251,28 +1118,7 @@ private HRegionLocation locateMetaInRoot
    */
   @Override
   public void clearRegionCache() {
-    synchronized (this.cachedRegionLocations) {
-      cachedRegionLocations.clear();
-      cachedServers.clear();
-    }
-  }
-
-  /**
-   * Put a newly discovered HRegionLocation into the cache.
-   */
-  private void cacheLocation(final byte [] tableName,
-      final HRegionLocation location) {
-    byte [] startKey = location.getRegionInfo().getStartKey();
-    boolean hasNewCache;
-    synchronized (this.cachedRegionLocations) {
-      cachedServers.add(location.getServerAddress().toString());
-      hasNewCache = (getTableLocations(tableName).put(startKey, location) == null);
-    }
-    if (hasNewCache) {
-      LOG.debug("Cached location for " +
-        location.getRegionInfo().getRegionNameAsString() +
-        " is " + location.getServerAddress().toString());
-    }
+    metaCache.clear();
   }
 
   @SuppressWarnings("resource")
@@ -1710,7 +1556,7 @@ private HRegionLocation locateMetaInRoot
       if (currentTime > fInfo.timeOfLatestCacheClearMilliSec
           + cacheClearingTimeoutMilliSec) {
         fInfo.timeOfLatestCacheClearMilliSec = currentTime;
-        clearCachedLocationForServer(server.toString());
+        metaCache.clearForServer(server.toString());
       }
       LOG.error("Exception in FastFail mode : " + t.toString());
       return;
@@ -1720,7 +1566,7 @@ private HRegionLocation locateMetaInRoot
     // map to that slow/dead server; otherwise, let cache miss and ask
     // .META. again to find the new location
     fInfo.timeOfLatestCacheClearMilliSec = currentTime;
-    clearCachedLocationForServer(server.toString());
+    metaCache.clearForServer(server.toString());
   }
 
   /**
@@ -2969,38 +2815,6 @@ private HRegionLocation locateMetaInRoot
     return t;
   }
 
-  /*
-   * Return the number of cached region for a table. It will only be called
-   * from a unit test.
-   */
-  int getNumberOfCachedRegionLocations(final byte[] tableName) {
-    Integer key = Bytes.mapKey(tableName);
-    synchronized (this.cachedRegionLocations) {
-      Map<byte[], HRegionLocation> tableLocs = this.cachedRegionLocations
-          .get(key);
-
-      if (tableLocs == null) {
-        return 0;
-      }
-      return tableLocs.values().size();
-    }
-  }
-
-  /**
-   * Check the region cache to see whether a region is cached yet or not.
-   * Called by unit tests.
-   *
-   * @param tableName
-   *          tableName
-   * @param row
-   *          row
-   * @return Region cached or not.
-   */
-  boolean isRegionCached(final byte[] tableName, final byte[] row) {
-    HRegionLocation location = getCachedLocation(tableName, row);
-    return location != null;
-  }
-
   @Override
   public void setRegionCachePrefetch(final byte[] tableName,
       final boolean enable) {
@@ -3021,7 +2835,7 @@ private HRegionLocation locateMetaInRoot
   public void prewarmRegionCache(final byte[] tableName,
       final Map<HRegionInfo, HServerAddress> regions) {
     for (Map.Entry<HRegionInfo, HServerAddress> e : regions.entrySet()) {
-      cacheLocation(tableName, new HRegionLocation(e.getKey(), e.getValue()));
+      metaCache.add(tableName, new HRegionLocation(e.getKey(), e.getValue()));
     }
   }
 
@@ -3161,7 +2975,7 @@ private HRegionLocation locateMetaInRoot
   private HServerAddress getRandomServerAddress() throws IOException {
     final ArrayList<String> addrs = new ArrayList<String>();
 
-    if (cachedServers.isEmpty()){
+    if (metaCache.getServers().isEmpty()) {
       getMaster();
       // If we have no cached servers
       // Use a visitor to collect a list of all the region server addresses
@@ -3188,10 +3002,9 @@ private HRegionLocation locateMetaInRoot
         }
       };
       MetaScanner.metaScan(conf, visitor);
-    }
-    else{
+    } else {
       // If we have any cached servers use them
-      addrs.addAll(cachedServers);
+      addrs.addAll(metaCache.getServers());
     }
     // return a random region server address
     int numServers = addrs.size();
@@ -3202,7 +3015,6 @@ private HRegionLocation locateMetaInRoot
     return new HServerAddress(serverAddrStr);
   }
 
-
   @Override
   public String getServerConfProperty(String prop) throws IOException{
     HServerAddress addr = getRandomServerAddress();

Modified: hbase/branches/0.89-fb/src/test/java/org/apache/hadoop/hbase/client/TestFastFail.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.89-fb/src/test/java/org/apache/hadoop/hbase/client/TestFastFail.java?rev=1584181&r1=1584180&r2=1584181&view=diff
==============================================================================
--- hbase/branches/0.89-fb/src/test/java/org/apache/hadoop/hbase/client/TestFastFail.java
(original)
+++ hbase/branches/0.89-fb/src/test/java/org/apache/hadoop/hbase/client/TestFastFail.java
Wed Apr  2 21:03:37 2014
@@ -264,7 +264,7 @@ public class TestFastFail {
         repeatedFailuresMap.put(serverAddr, fInfo);
 
         // clear out the cache
-        hcm.clearCachedLocationForServer(serverAddr.toString());
+        hcm.metaCache.clearForServer(serverAddr.toString());
       }
     }
 

Modified: hbase/branches/0.89-fb/src/test/java/org/apache/hadoop/hbase/client/TestHCM.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.89-fb/src/test/java/org/apache/hadoop/hbase/client/TestHCM.java?rev=1584181&r1=1584180&r2=1584181&view=diff
==============================================================================
--- hbase/branches/0.89-fb/src/test/java/org/apache/hadoop/hbase/client/TestHCM.java (original)
+++ hbase/branches/0.89-fb/src/test/java/org/apache/hadoop/hbase/client/TestHCM.java Wed Apr
 2 21:03:37 2014
@@ -19,10 +19,12 @@
  */
 package org.apache.hadoop.hbase.client;
 
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
 import java.io.IOException;
-import java.util.Collection;
 import java.util.List;
-import java.util.Set;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
@@ -31,28 +33,20 @@ import org.apache.hadoop.fs.FileSystem;
 import org.apache.hadoop.fs.Path;
 import org.apache.hadoop.hbase.HBaseTestingUtility;
 import org.apache.hadoop.hbase.HConstants;
+import org.apache.hadoop.hbase.HConstants.OperationStatusCode;
 import org.apache.hadoop.hbase.HRegionInfo;
 import org.apache.hadoop.hbase.HRegionLocation;
-import org.apache.hadoop.hbase.HServerAddress;
-import org.apache.hadoop.hbase.HConstants.OperationStatusCode;
 import org.apache.hadoop.hbase.ipc.HRegionInterface;
-import org.apache.hadoop.hbase.master.AssignmentPlan;
 import org.apache.hadoop.hbase.master.ServerManager;
-
 import org.apache.hadoop.hbase.regionserver.FlushRequester;
 import org.apache.hadoop.hbase.regionserver.HRegion;
-import org.apache.hadoop.hbase.regionserver.HRegionServer;
 import org.apache.hadoop.hbase.regionserver.wal.HLog;
 import org.apache.hadoop.hbase.util.Bytes;
-import org.apache.hadoop.hbase.util.Pair;
 import org.apache.hadoop.hbase.util.JVMClusterUtil.RegionServerThread;
+import org.apache.hadoop.hbase.util.Pair;
 import org.junit.BeforeClass;
 import org.junit.Test;
 
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
 /**
  * This class is for testing HCM features
  */
@@ -134,9 +128,9 @@ public class TestHCM {
     table.put(put);
     TableServers conn =
         (TableServers) table.getConnectionAndResetOperationContext();
-    assertNotNull(conn.getCachedLocation(TABLE_NAME, ROW));
+    assertNotNull(conn.metaCache.getForRow(TABLE_NAME, ROW));
     conn.deleteCachedLocation(TABLE_NAME, ROW, null);
-    HRegionLocation rl = conn.getCachedLocation(TABLE_NAME, ROW);
+    HRegionLocation rl = conn.metaCache.getForRow(TABLE_NAME, ROW);
     assertNull("What is this location?? " + rl, rl);
   }
 

Added: hbase/branches/0.89-fb/src/test/java/org/apache/hadoop/hbase/client/TestMetaCache.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.89-fb/src/test/java/org/apache/hadoop/hbase/client/TestMetaCache.java?rev=1584181&view=auto
==============================================================================
--- hbase/branches/0.89-fb/src/test/java/org/apache/hadoop/hbase/client/TestMetaCache.java
(added)
+++ hbase/branches/0.89-fb/src/test/java/org/apache/hadoop/hbase/client/TestMetaCache.java
Wed Apr  2 21:03:37 2014
@@ -0,0 +1,142 @@
+/**
+ * Copyright 2014 The Apache Software Foundation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.hadoop.hbase.client;
+
+import junit.framework.Assert;
+
+import org.apache.hadoop.hbase.HConstants;
+import org.apache.hadoop.hbase.HRegionInfo;
+import org.apache.hadoop.hbase.HRegionLocation;
+import org.apache.hadoop.hbase.HServerAddress;
+import org.apache.hadoop.hbase.HTableDescriptor;
+import org.apache.hadoop.hbase.util.Bytes;
+import org.junit.Test;
+
+/**
+ * Testcase for MetaCache class.
+ */
+public class TestMetaCache {
+
+  @Test
+  public void testBasic() {
+    final byte[] TABLE = Bytes.toBytes(this.getClass().getSimpleName());
+    final byte[] TABLE2 = Bytes.toBytes(this.getClass().getSimpleName() + "2");
+    final byte[] START_KEY = Bytes.toBytes("aaa");
+    final byte[] END_KEY = Bytes.toBytes("ggg");
+    final byte[] SMALL_ROW = Bytes.toBytes("a");
+    final byte[] ROW = Bytes.toBytes("ddd");
+
+    final HRegionLocation LOCATION = new HRegionLocation(new HRegionInfo(
+        new HTableDescriptor(TABLE), START_KEY, END_KEY),
+        new HServerAddress("10.0.0.11:1234"));
+
+    MetaCache metaCache = new MetaCache();
+
+    // Assert initial states
+    Assert.assertEquals("getNumber", 0, metaCache.getNumber(TABLE));
+    Assert.assertEquals("get(table).size", 0, metaCache.getForTable(TABLE).size());
+    Assert.assertEquals("getServers().size()",
+        0, metaCache.getServers().size());
+    Assert.assertNull("get(table, row)", metaCache.getForRow(TABLE, ROW));
+
+    metaCache.add(TABLE, LOCATION);
+
+    Assert.assertEquals("getNumber", 1, metaCache.getNumber(TABLE));
+    Assert.assertEquals("get(table).size", 1, metaCache.getForTable(TABLE).size());
+    Assert.assertEquals("getServers().size()",
+        1, metaCache.getServers().size());
+
+    Assert.assertEquals("should found", LOCATION, metaCache.getForRow(TABLE, ROW));
+    Assert.assertNull("should not found",
+        metaCache.getForRow(TABLE, HConstants.EMPTY_BYTE_ARRAY));
+    Assert.assertNull("should not found", metaCache.getForRow(TABLE, SMALL_ROW));
+    Assert.assertNull("should not found", metaCache.getForRow(TABLE, END_KEY));
+
+    // Add another location of the same table at the same server
+    metaCache.add(TABLE, new HRegionLocation(new HRegionInfo(
+        new HTableDescriptor(TABLE), HConstants.EMPTY_START_ROW, START_KEY),
+        new HServerAddress("10.0.0.11:1234")));
+
+    Assert.assertEquals("should found", LOCATION, metaCache.getForRow(TABLE, ROW));
+    Assert.assertNotNull("should found", metaCache.getForRow(TABLE, SMALL_ROW));
+
+    Assert.assertEquals("getNumber", 2, metaCache.getNumber(TABLE));
+    Assert.assertEquals("get(table).size", 2, metaCache.getForTable(TABLE).size());
+    Assert.assertEquals("getServers().size()",
+        1, metaCache.getServers().size());
+
+    // Add another location of the different table at the different server
+    metaCache.add(TABLE2, new HRegionLocation(new HRegionInfo(
+        new HTableDescriptor(TABLE2), END_KEY, HConstants.EMPTY_START_ROW),
+        new HServerAddress("10.0.0.12:1234")));
+
+    Assert.assertEquals("getNumber", 2, metaCache.getNumber(TABLE));
+    Assert.assertEquals("get(table).size", 2, metaCache.getForTable(TABLE).size());
+    Assert.assertEquals("getServers().size()",
+        2, metaCache.getServers().size());
+
+    Assert.assertEquals("getNumber", 1, metaCache.getNumber(TABLE2));
+    Assert.assertEquals("get(table).size", 1, metaCache.getForTable(TABLE2).size());
+
+    // Delete the first location with wrong server info
+    metaCache.deleteForRow(TABLE, ROW, new HServerAddress("10.0.0.13:1234"));
+
+    Assert.assertEquals("should found", LOCATION, metaCache.getForRow(TABLE, ROW));
+    Assert.assertNotNull("should found", metaCache.getForRow(TABLE, SMALL_ROW));
+
+    // Delete the first location with correct server info
+    metaCache.deleteForRow(TABLE, ROW, new HServerAddress("10.0.0.11:1234"));
+
+    Assert.assertNull("should not found", metaCache.getForRow(TABLE, ROW));
+    Assert.assertNotNull("should found", metaCache.getForRow(TABLE, SMALL_ROW));
+
+    // Delete the second location with null server info
+    metaCache.deleteForRow(TABLE, SMALL_ROW, null);
+
+    Assert.assertNull("should not found", metaCache.getForRow(TABLE, ROW));
+    Assert.assertNull("should not found", metaCache.getForRow(TABLE, SMALL_ROW));
+
+    Assert.assertEquals("getNumber", 0, metaCache.getNumber(TABLE));
+    Assert.assertEquals("get(table).size", 0, metaCache.getForTable(TABLE).size());
+    Assert.assertTrue("getServers().size() should <= 2",
+        metaCache.getServers().size() <= 2);
+
+    // clear not existing server
+    metaCache.clearForServer("10.0.0.13:1234");
+
+    Assert.assertTrue("getServers().size() should <= 2",
+        metaCache.getServers().size() <= 2);
+
+    // clear existing server
+    metaCache.clearForServer("10.0.0.11:1234");
+
+    Assert.assertTrue("getServers().size() should <= 1",
+        metaCache.getServers().size() <= 1);
+
+    // clear all
+    metaCache.clear();
+    Assert.assertEquals("getServers().size()",
+        0, metaCache.getServers().size());
+
+    // Assert not null for get(table) even if not existing
+    Assert.assertNotNull("get(table)", metaCache.getForTable(TABLE));
+  }
+
+}



Mime
View raw message