You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hbase.apache.org by en...@apache.org on 2014/06/28 02:30:51 UTC
[05/49] HBASE-10347 HRegionInfo changes for adding replicaId and
MetaEditor/MetaReader changes for region replicas
http://git-wip-us.apache.org/repos/asf/hbase/blob/d4b82224/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ConnectionManager.java
----------------------------------------------------------------------
diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ConnectionManager.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ConnectionManager.java
index ce055ca..15f78c5 100644
--- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ConnectionManager.java
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ConnectionManager.java
@@ -34,8 +34,6 @@ import java.util.NavigableMap;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.ConcurrentSkipListMap;
-import java.util.concurrent.ConcurrentSkipListSet;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
@@ -54,6 +52,7 @@ import org.apache.hadoop.hbase.HRegionInfo;
import org.apache.hadoop.hbase.HRegionLocation;
import org.apache.hadoop.hbase.HTableDescriptor;
import org.apache.hadoop.hbase.MasterNotRunningException;
+import org.apache.hadoop.hbase.RegionLocations;
import org.apache.hadoop.hbase.RegionTooBusyException;
import org.apache.hadoop.hbase.ServerName;
import org.apache.hadoop.hbase.Stoppable;
@@ -61,6 +60,7 @@ import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.TableNotEnabledException;
import org.apache.hadoop.hbase.TableNotFoundException;
import org.apache.hadoop.hbase.ZooKeeperConnectionException;
+import org.apache.hadoop.hbase.catalog.MetaReader;
import org.apache.hadoop.hbase.client.AsyncProcess.AsyncRequestFuture;
import org.apache.hadoop.hbase.client.MetaScanner.MetaScannerVisitor;
import org.apache.hadoop.hbase.client.MetaScanner.MetaScannerVisitorBase;
@@ -350,6 +350,7 @@ class ConnectionManager {
* @param conf configuration whose identity is used to find {@link HConnection} instance.
* @deprecated
*/
+ @Deprecated
public static void deleteConnection(Configuration conf) {
deleteConnection(new HConnectionKey(conf), false);
}
@@ -361,6 +362,7 @@ class ConnectionManager {
* @param connection
* @deprecated
*/
+ @Deprecated
public static void deleteStaleConnection(HConnection connection) {
deleteConnection(connection, true);
}
@@ -371,6 +373,7 @@ class ConnectionManager {
* staleConnection to true.
* @deprecated
*/
+ @Deprecated
public static void deleteAllConnections(boolean staleConnection) {
synchronized (CONNECTION_INSTANCES) {
Set<HConnectionKey> connectionKeys = new HashSet<HConnectionKey>();
@@ -496,19 +499,7 @@ class ConnectionManager {
// Client rpc instance.
private RpcClient rpcClient;
- /**
- * Map of table to table {@link HRegionLocation}s.
- */
- private final ConcurrentMap<TableName, ConcurrentSkipListMap<byte[], HRegionLocation>>
- cachedRegionLocations =
- new ConcurrentHashMap<TableName, ConcurrentSkipListMap<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.
- // The access to this attribute must be protected by a lock on cachedRegionLocations
- private final Set<ServerName> cachedServers = new ConcurrentSkipListSet<ServerName>();
+ private MetaCache metaCache = new MetaCache();
private int refCount;
@@ -731,6 +722,7 @@ class ConnectionManager {
* An identifier that will remain the same for a given connection.
* @return
*/
+ @Override
public String toString(){
return "hconnection-0x" + Integer.toHexString(hashCode());
}
@@ -902,8 +894,9 @@ class ConnectionManager {
@Override
public HRegionLocation locateRegion(final byte[] regionName) throws IOException {
- return locateRegion(HRegionInfo.getTable(regionName),
- HRegionInfo.getStartKey(regionName), false, true);
+ RegionLocations locations = locateRegion(HRegionInfo.getTable(regionName),
+ HRegionInfo.getStartKey(regionName), false, true);
+ return locations == null ? null : locations.getRegionLocation();
}
@Override
@@ -934,7 +927,14 @@ class ConnectionManager {
tableName, offlined);
final List<HRegionLocation> locations = new ArrayList<HRegionLocation>();
for (HRegionInfo regionInfo : regions.keySet()) {
- locations.add(locateRegion(tableName, regionInfo.getStartKey(), useCache, true));
+ RegionLocations list = locateRegion(tableName, regionInfo.getStartKey(), useCache, true);
+ if (list != null) {
+ for (HRegionLocation loc : list.getRegionLocations()) {
+ if (loc != null) {
+ locations.add(loc);
+ }
+ }
+ }
}
return locations;
}
@@ -949,7 +949,8 @@ class ConnectionManager {
public HRegionLocation locateRegion(final TableName tableName,
final byte [] row)
throws IOException{
- return locateRegion(tableName, row, true, true);
+ RegionLocations locations = locateRegion(tableName, row, true, true);
+ return locations == null ? null : locations.getRegionLocation();
}
@Override
@@ -969,7 +970,8 @@ class ConnectionManager {
throw new TableNotEnabledException(tableName.getNameAsString() + " is disabled.");
}
- return locateRegion(tableName, row, false, true);
+ RegionLocations locations = locateRegion(tableName, row, false, true);
+ return locations == null ? null : locations.getRegionLocation();
}
@Override
@@ -979,7 +981,7 @@ class ConnectionManager {
}
- private HRegionLocation locateRegion(final TableName tableName,
+ private RegionLocations locateRegion(final TableName tableName,
final byte [] row, boolean useCache, boolean retry)
throws IOException {
if (this.closed) throw new IOException(toString() + " closed");
@@ -1000,15 +1002,15 @@ class ConnectionManager {
* Search the hbase:meta table for the HRegionLocation
* info that contains the table and row we're seeking.
*/
- private HRegionLocation locateRegionInMeta(TableName tableName, byte[] row,
+ private RegionLocations locateRegionInMeta(TableName tableName, byte[] row,
boolean useCache, boolean retry) throws IOException {
// If we are supposed to be using the cache, look in the cache to see if
// we already have the region.
if (useCache) {
- HRegionLocation location = getCachedLocation(tableName, row);
- if (location != null) {
- return location;
+ RegionLocations locations = getCachedLocation(tableName, row);
+ if (locations != null) {
+ return locations;
}
}
@@ -1033,9 +1035,9 @@ class ConnectionManager {
" after " + localNumRetries + " tries.");
}
if (useCache) {
- HRegionLocation location = getCachedLocation(tableName, row);
- if (location != null) {
- return location;
+ RegionLocations locations = getCachedLocation(tableName, row);
+ if (locations != null) {
+ return locations;
}
}
@@ -1057,7 +1059,8 @@ class ConnectionManager {
}
// convert the row result into the HRegionLocation we need!
- HRegionInfo regionInfo = MetaScanner.getHRegionInfo(regionInfoRow);
+ RegionLocations locations = MetaReader.getRegionLocations(regionInfoRow);
+ HRegionInfo regionInfo = locations.getRegionLocation().getRegionInfo();
if (regionInfo == null) {
throw new IOException("HRegionInfo was null or empty in " +
TableName.META_TABLE_NAME + ", row=" + regionInfoRow);
@@ -1081,7 +1084,7 @@ class ConnectionManager {
regionInfo.getRegionNameAsString());
}
- ServerName serverName = HRegionInfo.getServerName(regionInfoRow);
+ ServerName serverName = locations.getRegionLocation().getServerName();
if (serverName == null) {
throw new NoServerForRegionException("No server address listed " +
"in " + TableName.META_TABLE_NAME + " for region " +
@@ -1096,10 +1099,8 @@ class ConnectionManager {
}
// Instantiate the location
- HRegionLocation location = new HRegionLocation(regionInfo, serverName,
- HRegionInfo.getSeqNumDuringOpen(regionInfoRow));
- cacheLocation(tableName, null, location);
- return location;
+ cacheLocation(tableName, locations);
+ return locations;
} catch (TableNotFoundException e) {
// if we got this error, probably means the table just plain doesn't
@@ -1138,7 +1139,16 @@ class ConnectionManager {
}
}
- /*
+ /**
+ * Put a newly discovered HRegionLocation into the cache.
+ * @param tableName The table name.
+ * @param location the new location
+ */
+ private void cacheLocation(final TableName tableName, final RegionLocations location) {
+ metaCache.cacheLocation(tableName, location);
+ }
+
+ /**
* Search the cache for a location that fits our table and row key.
* Return null if no suitable region is located.
*
@@ -1146,52 +1156,13 @@ class ConnectionManager {
* @param row
* @return Null or region location found in cache.
*/
- HRegionLocation getCachedLocation(final TableName tableName,
+ RegionLocations getCachedLocation(final TableName tableName,
final byte [] row) {
- ConcurrentSkipListMap<byte[], HRegionLocation> tableLocations =
- getTableLocations(tableName);
-
- Entry<byte[], HRegionLocation> e = tableLocations.floorEntry(row);
- if (e == null) {
- return null;
- }
- HRegionLocation possibleRegion = e.getValue();
-
- // 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_END_ROW, signifying that the region we're
- // checking is actually the last region in the table.
- byte[] endKey = possibleRegion.getRegionInfo().getEndKey();
- if (Bytes.equals(endKey, HConstants.EMPTY_END_ROW) ||
- tableName.getRowComparator().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.getCachedLocation(tableName, row);
}
- /**
- * Delete a cached location, no matter what it is. Called when we were told to not use cache.
- * @param tableName tableName
- * @param row
- */
- void forceDeleteCachedLocation(final TableName tableName, final byte [] row) {
- HRegionLocation rl = null;
- 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.
- rl = getCachedLocation(tableName, row);
- if (rl != null) {
- tableLocations.remove(rl.getRegionInfo().getStartKey());
- }
- if ((rl != null) && LOG.isDebugEnabled()) {
- LOG.debug("Removed " + rl.getHostname() + ":" + rl.getPort()
- + " as a location of " + rl.getRegionInfo().getRegionNameAsString() +
- " for tableName=" + tableName + " from cache");
- }
+ public void clearRegionCache(final TableName tableName, byte[] row) {
+ metaCache.clearCache(tableName, row);
}
/*
@@ -1199,66 +1170,17 @@ class ConnectionManager {
*/
@Override
public void clearCaches(final ServerName serverName) {
- if (!this.cachedServers.contains(serverName)) {
- return;
- }
-
- boolean deletedSomething = false;
- synchronized (this.cachedServers) {
- // We block here, because if there is an error on a server, it's likely that multiple
- // threads will get the error simultaneously. If there are hundreds of thousand of
- // region location to check, it's better to do this only once. A better pattern would
- // be to check if the server is dead when we get the region location.
- if (!this.cachedServers.contains(serverName)) {
- return;
- }
- for (Map<byte[], HRegionLocation> tableLocations : cachedRegionLocations.values()) {
- for (Entry<byte[], HRegionLocation> e : tableLocations.entrySet()) {
- HRegionLocation value = e.getValue();
- if (value != null
- && serverName.equals(value.getServerName())) {
- tableLocations.remove(e.getKey());
- deletedSomething = true;
- }
- }
- }
- this.cachedServers.remove(serverName);
- }
- if (deletedSomething && LOG.isDebugEnabled()) {
- LOG.debug("Removed all cached region locations that map to " + serverName);
- }
- }
-
- /*
- * @param tableName
- * @return Map of cached locations for passed <code>tableName</code>
- */
- private ConcurrentSkipListMap<byte[], HRegionLocation> getTableLocations(
- final TableName tableName) {
- // find the map of cached locations for this table
- ConcurrentSkipListMap<byte[], HRegionLocation> result;
- result = this.cachedRegionLocations.get(tableName);
- // if tableLocations for this table isn't built yet, make one
- if (result == null) {
- result = new ConcurrentSkipListMap<byte[], HRegionLocation>(Bytes.BYTES_COMPARATOR);
- ConcurrentSkipListMap<byte[], HRegionLocation> old =
- this.cachedRegionLocations.putIfAbsent(tableName, result);
- if (old != null) {
- return old;
- }
- }
- return result;
+ metaCache.clearCache(serverName);
}
@Override
public void clearRegionCache() {
- this.cachedRegionLocations.clear();
- this.cachedServers.clear();
+ metaCache.clearCache();
}
@Override
public void clearRegionCache(final TableName tableName) {
- this.cachedRegionLocations.remove(tableName);
+ metaCache.clearCache(tableName);
}
@Override
@@ -1274,37 +1196,7 @@ class ConnectionManager {
*/
private void cacheLocation(final TableName tableName, final ServerName source,
final HRegionLocation location) {
- boolean isFromMeta = (source == null);
- byte [] startKey = location.getRegionInfo().getStartKey();
- ConcurrentMap<byte[], HRegionLocation> tableLocations = getTableLocations(tableName);
- HRegionLocation oldLocation = tableLocations.putIfAbsent(startKey, location);
- boolean isNewCacheEntry = (oldLocation == null);
- if (isNewCacheEntry) {
- cachedServers.add(location.getServerName());
- return;
- }
- boolean updateCache;
- // If the server in cache sends us a redirect, assume it's always valid.
- if (oldLocation.getServerName().equals(source)) {
- updateCache = true;
- } else {
- long newLocationSeqNum = location.getSeqNum();
- // Meta record is stale - some (probably the same) server has closed the region
- // with later seqNum and told us about the new location.
- boolean isStaleMetaRecord = isFromMeta && (oldLocation.getSeqNum() > newLocationSeqNum);
- // Same as above for redirect. However, in this case, if the number is equal to previous
- // record, the most common case is that first the region was closed with seqNum, and then
- // opened with the same seqNum; hence we will ignore the redirect.
- // There are so many corner cases with various combinations of opens and closes that
- // an additional counter on top of seqNum would be necessary to handle them all.
- boolean isStaleRedirect = !isFromMeta && (oldLocation.getSeqNum() >= newLocationSeqNum);
- boolean isStaleUpdate = (isStaleMetaRecord || isStaleRedirect);
- updateCache = (!isStaleUpdate);
- }
- if (updateCache) {
- tableLocations.replace(startKey, oldLocation, location);
- cachedServers.add(location.getServerName());
- }
+ metaCache.cacheLocation(tableName, source, location);
}
// Map keyed by service name + regionserver to service stub implementation
@@ -1987,7 +1879,7 @@ class ConnectionManager {
}
};
}
-
+
private static void release(MasterServiceState mss) {
if (mss != null && mss.connection != null) {
@@ -2046,37 +1938,17 @@ class ConnectionManager {
cacheLocation(hri.getTable(), source, newHrl);
}
- /**
- * Deletes the cached location of the region if necessary, based on some error from source.
- * @param hri The region in question.
- * @param source The source of the error that prompts us to invalidate cache.
- */
- void deleteCachedLocation(HRegionInfo hri, ServerName source) {
- getTableLocations(hri.getTable()).remove(hri.getStartKey());
- }
-
@Override
public void deleteCachedRegionLocation(final HRegionLocation location) {
- if (location == null || location.getRegionInfo() == null) {
- return;
- }
-
- HRegionLocation removedLocation;
- TableName tableName = location.getRegionInfo().getTable();
- Map<byte[], HRegionLocation> tableLocations = getTableLocations(tableName);
- removedLocation = tableLocations.remove(location.getRegionInfo().getStartKey());
- if (LOG.isDebugEnabled() && removedLocation != null) {
- LOG.debug("Removed " +
- location.getRegionInfo().getRegionNameAsString() +
- " for tableName=" + tableName +
- " from cache");
- }
+ metaCache.clearCache(location);
}
@Override
public void updateCachedLocations(final TableName tableName, byte[] rowkey,
- final Object exception, final HRegionLocation source) {
- updateCachedLocations(tableName, rowkey, exception, source.getServerName());
+ final Object exception, final HRegionLocation source) {
+ assert source != null;
+ updateCachedLocations(tableName, source.getRegionInfo().getRegionName()
+ , rowkey, exception, source.getServerName());
}
/**
@@ -2088,7 +1960,7 @@ class ConnectionManager {
* @param source server that is the source of the location update.
*/
@Override
- public void updateCachedLocations(final TableName tableName, byte[] rowkey,
+ public void updateCachedLocations(final TableName tableName, byte[] regionName, byte[] rowkey,
final Object exception, final ServerName source) {
if (rowkey == null || tableName == null) {
LOG.warn("Coding error, see method javadoc. row=" + (rowkey == null ? "null" : rowkey) +
@@ -2101,8 +1973,18 @@ class ConnectionManager {
return;
}
+ if (regionName == null) {
+ // we do not know which region, so just remove the cache entry for the row and server
+ metaCache.clearCache(tableName, rowkey, source);
+ return;
+ }
+
// Is it something we have already updated?
- final HRegionLocation oldLocation = getCachedLocation(tableName, rowkey);
+ final RegionLocations oldLocations = getCachedLocation(tableName, rowkey);
+ HRegionLocation oldLocation = null;
+ if (oldLocations != null) {
+ oldLocation = oldLocations.getRegionLocationByRegionName(regionName);
+ }
if (oldLocation == null || !source.equals(oldLocation.getServerName())) {
// There is no such location in the cache (it's been removed already) or
// the cache has already been refreshed with a different location. => nothing to do
@@ -2133,8 +2015,8 @@ class ConnectionManager {
}
// If we're here, it means that can cannot be sure about the location, so we remove it from
- // the cache.
- deleteCachedLocation(regionInfo, source);
+ // the cache. Do not send the source because source can be a new server in the same host:port
+ metaCache.clearCache(regionInfo);
}
@Override
@@ -2221,24 +2103,9 @@ class ConnectionManager {
* Return the number of cached region for a table. It will only be called
* from a unit test.
*/
+ @VisibleForTesting
int getNumberOfCachedRegionLocations(final TableName tableName) {
- Map<byte[], HRegionLocation> tableLocs = this.cachedRegionLocations.get(tableName);
- 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(TableName tableName, final byte[] row) {
- HRegionLocation location = getCachedLocation(tableName, row);
- return location != null;
+ return metaCache.getNumberOfCachedRegionLocations(tableName);
}
@Override
@@ -2567,7 +2434,7 @@ class ConnectionManager {
* Look for an exception we know in the remote exception:
* - hadoop.ipc wrapped exceptions
* - nested exceptions
- *
+ *
* Looks for: RegionMovedException / RegionOpeningException / RegionTooBusyException
* @return null if we didn't find the exception, the exception otherwise.
*/
http://git-wip-us.apache.org/repos/asf/hbase/blob/d4b82224/hbase-client/src/main/java/org/apache/hadoop/hbase/client/HConnection.java
----------------------------------------------------------------------
diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/HConnection.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/HConnection.java
index 0305821..8e27dfd 100644
--- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/HConnection.java
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/HConnection.java
@@ -27,11 +27,11 @@ import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.classification.InterfaceStability;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.Abortable;
-import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.HRegionLocation;
import org.apache.hadoop.hbase.HTableDescriptor;
import org.apache.hadoop.hbase.MasterNotRunningException;
import org.apache.hadoop.hbase.ServerName;
+import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.ZooKeeperConnectionException;
import org.apache.hadoop.hbase.catalog.CatalogTracker;
import org.apache.hadoop.hbase.client.coprocessor.Batch;
@@ -44,7 +44,7 @@ import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.MasterService;
* keeps a cache of locations and then knows how to re-calibrate after they move. You need one
* of these to talk to your HBase cluster. {@link HConnectionManager} manages instances of this
* class. See it for how to get one of these.
- *
+ *
* <p>This is NOT a connection to a particular server but to ALL servers in the cluster. Individual
* connections are managed at a lower level.
*
@@ -264,7 +264,8 @@ public interface HConnection extends Abortable, Closeable {
* @return HRegionLocation that describes where to find the region in
* question
* @throws IOException if a remote or network exception occurs
- * @deprecated internal method, do not use thru HConnection */
+ * @deprecated internal method, do not use thru HConnection
+ */
@Deprecated
public HRegionLocation locateRegion(final TableName tableName,
final byte [] row) throws IOException;
@@ -323,12 +324,14 @@ public interface HConnection extends Abortable, Closeable {
* Update the location cache. This is used internally by HBase, in most cases it should not be
* used by the client application.
* @param tableName the table name
+ * @param regionName the regionName
* @param rowkey the row
* @param exception the exception if any. Can be null.
* @param source the previous location
- * @deprecated internal method, do not use thru HConnection */
+ * @deprecated internal method, do not use thru HConnection
+ */
@Deprecated
- void updateCachedLocations(TableName tableName, byte[] rowkey,
+ void updateCachedLocations(TableName tableName, byte[] regionName, byte[] rowkey,
Object exception, ServerName source);
@Deprecated
@@ -366,7 +369,8 @@ public interface HConnection extends Abortable, Closeable {
* regions from returned list.
* @return list of region locations for all regions of table
* @throws IOException
- * @deprecated internal method, do not use thru HConnection */
+ * @deprecated internal method, do not use thru HConnection
+ */
@Deprecated
public List<HRegionLocation> locateRegions(final TableName tableName,
final boolean useCache,
@@ -412,6 +416,7 @@ public interface HConnection extends Abortable, Closeable {
* @throws IOException if a remote or network exception occurs
* @deprecated You can pass master flag but nothing special is done.
*/
+ @Deprecated
AdminService.BlockingInterface getAdmin(final ServerName serverName, boolean getMaster)
throws IOException;
@@ -506,6 +511,7 @@ public interface HConnection extends Abortable, Closeable {
* @throws IOException if a remote or network exception occurs
* @deprecated This method will be changed from public to package protected.
*/
+ @Deprecated
int getCurrentNrHRS() throws IOException;
/**
http://git-wip-us.apache.org/repos/asf/hbase/blob/d4b82224/hbase-client/src/main/java/org/apache/hadoop/hbase/client/HConnectionManager.java
----------------------------------------------------------------------
diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/HConnectionManager.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/HConnectionManager.java
index f54d053..0d4f793 100644
--- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/HConnectionManager.java
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/HConnectionManager.java
@@ -243,6 +243,7 @@ public class HConnectionManager {
* @param conf configuration whose identity is used to find {@link HConnection} instance.
* @deprecated
*/
+ @Deprecated
public static void deleteConnection(Configuration conf) {
ConnectionManager.deleteConnection(conf);
}
@@ -254,6 +255,7 @@ public class HConnectionManager {
* @param connection
* @deprecated
*/
+ @Deprecated
public static void deleteStaleConnection(HConnection connection) {
ConnectionManager.deleteStaleConnection(connection);
}
@@ -264,6 +266,7 @@ public class HConnectionManager {
* staleConnection to true.
* @deprecated
*/
+ @Deprecated
public static void deleteAllConnections(boolean staleConnection) {
ConnectionManager.deleteAllConnections(staleConnection);
}
http://git-wip-us.apache.org/repos/asf/hbase/blob/d4b82224/hbase-client/src/main/java/org/apache/hadoop/hbase/client/HTable.java
----------------------------------------------------------------------
diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/HTable.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/HTable.java
index 13025b2..5cd0102 100644
--- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/HTable.java
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/HTable.java
@@ -43,7 +43,6 @@ import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.classification.InterfaceStability;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.Cell;
-import org.apache.hadoop.hbase.DoNotRetryIOException;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.HConstants;
import org.apache.hadoop.hbase.HRegionInfo;
@@ -51,6 +50,7 @@ import org.apache.hadoop.hbase.HRegionLocation;
import org.apache.hadoop.hbase.HTableDescriptor;
import org.apache.hadoop.hbase.KeyValue;
import org.apache.hadoop.hbase.KeyValueUtil;
+import org.apache.hadoop.hbase.RegionLocations;
import org.apache.hadoop.hbase.ServerName;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.client.AsyncProcess.AsyncRequestFuture;
@@ -76,11 +76,10 @@ import org.apache.hadoop.hbase.util.Threads;
import com.google.protobuf.Descriptors;
import com.google.protobuf.Message;
+import com.google.common.annotations.VisibleForTesting;
import com.google.protobuf.Service;
import com.google.protobuf.ServiceException;
-import com.google.common.annotations.VisibleForTesting;
-
/**
* <p>Used to communicate with a single HBase table. An implementation of
* {@link HTableInterface}. Instances of this class can be constructed directly but it is
@@ -608,12 +607,15 @@ public class HTable implements HTableInterface {
* @return Pair of arrays of region starting and ending row keys
* @throws IOException if a remote or network exception occurs
*/
+ // TODO: these are not in HTableInterface. Should we add them there or move these to HBaseAdmin?
public Pair<byte[][],byte[][]> getStartEndKeys() throws IOException {
- NavigableMap<HRegionInfo, ServerName> regions = getRegionLocations();
+
+ List<RegionLocations> regions = listRegionLocations();
final List<byte[]> startKeyList = new ArrayList<byte[]>(regions.size());
final List<byte[]> endKeyList = new ArrayList<byte[]>(regions.size());
- for (HRegionInfo region : regions.keySet()) {
+ for (RegionLocations locations : regions) {
+ HRegionInfo region = locations.getRegionLocation().getRegionInfo();
startKeyList.add(region.getStartKey());
endKeyList.add(region.getEndKey());
}
@@ -623,13 +625,20 @@ public class HTable implements HTableInterface {
endKeyList.toArray(new byte[endKeyList.size()][]));
}
+ @VisibleForTesting
+ List<RegionLocations> listRegionLocations() throws IOException {
+ return MetaScanner.listTableRegionLocations(getConfiguration(), this.connection, getName());
+ }
+
/**
* Gets all the regions and their address for this table.
* <p>
* This is mainly useful for the MapReduce integration.
* @return A map of HRegionInfo with it's server address
* @throws IOException if a remote or network exception occurs
+ * @deprecated This is no longer a public API
*/
+ @Deprecated
public NavigableMap<HRegionInfo, ServerName> getRegionLocations() throws IOException {
// TODO: Odd that this returns a Map of HRI to SN whereas getRegionLocation, singular, returns an HRegionLocation.
return MetaScanner.allTableRegions(getConfiguration(), this.connection, getName(), false);
@@ -643,7 +652,9 @@ public class HTable implements HTableInterface {
* @return A list of HRegionLocations corresponding to the regions that
* contain the specified range
* @throws IOException if a remote or network exception occurs
+ * @deprecated This is no longer a public API
*/
+ @Deprecated
public List<HRegionLocation> getRegionsInRange(final byte [] startKey,
final byte [] endKey) throws IOException {
return getRegionsInRange(startKey, endKey, false);
@@ -658,7 +669,9 @@ public class HTable implements HTableInterface {
* @return A list of HRegionLocations corresponding to the regions that
* contain the specified range
* @throws IOException if a remote or network exception occurs
+ * @deprecated This is no longer a public API
*/
+ @Deprecated
public List<HRegionLocation> getRegionsInRange(final byte [] startKey,
final byte [] endKey, final boolean reload) throws IOException {
return getKeysAndRegionsInRange(startKey, endKey, false, reload).getSecond();
@@ -674,7 +687,9 @@ public class HTable implements HTableInterface {
* @return A pair of list of start keys and list of HRegionLocations that
* contain the specified range
* @throws IOException if a remote or network exception occurs
+ * @deprecated This is no longer a public API
*/
+ @Deprecated
private Pair<List<byte[]>, List<HRegionLocation>> getKeysAndRegionsInRange(
final byte[] startKey, final byte[] endKey, final boolean includeEndKey)
throws IOException {
@@ -692,7 +707,9 @@ public class HTable implements HTableInterface {
* @return A pair of list of start keys and list of HRegionLocations that
* contain the specified range
* @throws IOException if a remote or network exception occurs
+ * @deprecated This is no longer a public API
*/
+ @Deprecated
private Pair<List<byte[]>, List<HRegionLocation>> getKeysAndRegionsInRange(
final byte[] startKey, final byte[] endKey, final boolean includeEndKey,
final boolean reload) throws IOException {
@@ -727,7 +744,8 @@ public class HTable implements HTableInterface {
throws IOException {
RegionServerCallable<Result> callable = new RegionServerCallable<Result>(this.connection,
tableName, row) {
- public Result call(int callTimeout) throws IOException {
+ @Override
+ public Result call(int callTimeout) throws IOException {
PayloadCarryingRpcController controller = rpcControllerFactory.newController();
controller.setPriority(tableName);
controller.setCallTimeout(callTimeout);
@@ -801,6 +819,7 @@ public class HTable implements HTableInterface {
public Result get(final Get get) throws IOException {
RegionServerCallable<Result> callable = new RegionServerCallable<Result>(this.connection,
getName(), get.getRow()) {
+ @Override
public Result call(int callTimeout) throws IOException {
ClientProtos.GetRequest request =
RequestConverter.buildGetRequest(getLocation().getRegionInfo().getRegionName(), get);
@@ -862,6 +881,7 @@ public class HTable implements HTableInterface {
* @deprecated If any exception is thrown by one of the actions, there is no way to
* retrieve the partially executed results. Use {@link #batch(List, Object[])} instead.
*/
+ @Deprecated
@Override
public Object[] batch(final List<? extends Row> actions)
throws InterruptedException, IOException {
@@ -887,6 +907,7 @@ public class HTable implements HTableInterface {
* {@link #batchCallback(List, Object[], org.apache.hadoop.hbase.client.coprocessor.Batch.Callback)}
* instead.
*/
+ @Deprecated
@Override
public <R> Object[] batchCallback(
final List<? extends Row> actions, final Batch.Callback<R> callback) throws IOException,
@@ -904,6 +925,7 @@ public class HTable implements HTableInterface {
throws IOException {
RegionServerCallable<Boolean> callable = new RegionServerCallable<Boolean>(connection,
tableName, delete.getRow()) {
+ @Override
public Boolean call(int callTimeout) throws IOException {
PayloadCarryingRpcController controller = rpcControllerFactory.newController();
controller.setPriority(tableName);
@@ -1044,6 +1066,7 @@ public class HTable implements HTableInterface {
public void mutateRow(final RowMutations rm) throws IOException {
RegionServerCallable<Void> callable =
new RegionServerCallable<Void>(connection, getName(), rm.getRow()) {
+ @Override
public Void call(int callTimeout) throws IOException {
PayloadCarryingRpcController controller = rpcControllerFactory.newController();
controller.setPriority(tableName);
@@ -1078,6 +1101,7 @@ public class HTable implements HTableInterface {
final long nonceGroup = ng.getNonceGroup(), nonce = ng.newNonce();
RegionServerCallable<Result> callable =
new RegionServerCallable<Result>(this.connection, getName(), append.getRow()) {
+ @Override
public Result call(int callTimeout) throws IOException {
PayloadCarryingRpcController controller = rpcControllerFactory.newController();
controller.setPriority(getTableName());
@@ -1109,6 +1133,7 @@ public class HTable implements HTableInterface {
final long nonceGroup = ng.getNonceGroup(), nonce = ng.newNonce();
RegionServerCallable<Result> callable = new RegionServerCallable<Result>(this.connection,
getName(), increment.getRow()) {
+ @Override
public Result call(int callTimeout) throws IOException {
PayloadCarryingRpcController controller = rpcControllerFactory.newController();
controller.setPriority(getTableName());
@@ -1172,6 +1197,7 @@ public class HTable implements HTableInterface {
final long nonceGroup = ng.getNonceGroup(), nonce = ng.newNonce();
RegionServerCallable<Long> callable =
new RegionServerCallable<Long>(connection, getName(), row) {
+ @Override
public Long call(int callTimeout) throws IOException {
PayloadCarryingRpcController controller = rpcControllerFactory.newController();
controller.setPriority(getTableName());
@@ -1202,6 +1228,7 @@ public class HTable implements HTableInterface {
throws IOException {
RegionServerCallable<Boolean> callable =
new RegionServerCallable<Boolean>(connection, getName(), row) {
+ @Override
public Boolean call(int callTimeout) throws IOException {
PayloadCarryingRpcController controller = rpcControllerFactory.newController();
controller.setPriority(tableName);
@@ -1230,6 +1257,7 @@ public class HTable implements HTableInterface {
throws IOException {
RegionServerCallable<Boolean> callable =
new RegionServerCallable<Boolean>(connection, getName(), row) {
+ @Override
public Boolean call(int callTimeout) throws IOException {
PayloadCarryingRpcController controller = new PayloadCarryingRpcController();
controller.setPriority(tableName);
@@ -1259,6 +1287,7 @@ public class HTable implements HTableInterface {
throws IOException {
RegionServerCallable<Boolean> callable =
new RegionServerCallable<Boolean>(connection, getName(), row) {
+ @Override
public Boolean call(int callTimeout) throws IOException {
PayloadCarryingRpcController controller = rpcControllerFactory.newController();
controller.setPriority(tableName);
@@ -1287,6 +1316,7 @@ public class HTable implements HTableInterface {
throws IOException {
RegionServerCallable<Boolean> callable =
new RegionServerCallable<Boolean>(connection, getName(), row) {
+ @Override
public Boolean call(int callTimeout) throws IOException {
PayloadCarryingRpcController controller = rpcControllerFactory.newController();
controller.setPriority(tableName);
@@ -1474,6 +1504,7 @@ public class HTable implements HTableInterface {
* @param writeBufferSize The new write buffer size, in bytes.
* @throws IOException if a remote or network exception occurs.
*/
+ @Override
public void setWriteBufferSize(long writeBufferSize) throws IOException {
this.writeBufferSize = writeBufferSize;
if(currentWriteBufferSize > writeBufferSize) {
@@ -1595,6 +1626,7 @@ public class HTable implements HTableInterface {
/**
* {@inheritDoc}
*/
+ @Override
public CoprocessorRpcChannel coprocessorService(byte[] row) {
return new RegionCoprocessorRpcChannel(connection, tableName, row);
}
@@ -1609,6 +1641,7 @@ public class HTable implements HTableInterface {
final Map<byte[],R> results = Collections.synchronizedMap(
new TreeMap<byte[], R>(Bytes.BYTES_COMPARATOR));
coprocessorService(service, startKey, endKey, callable, new Batch.Callback<R>() {
+ @Override
public void update(byte[] region, byte[] row, R value) {
if (region != null) {
results.put(region, value);
@@ -1636,6 +1669,7 @@ public class HTable implements HTableInterface {
new RegionCoprocessorRpcChannel(connection, tableName, r);
Future<R> future = pool.submit(
new Callable<R>() {
+ @Override
public R call() throws Exception {
T instance = ProtobufUtil.newServiceStub(service, channel);
R result = callable.call(instance);
http://git-wip-us.apache.org/repos/asf/hbase/blob/d4b82224/hbase-client/src/main/java/org/apache/hadoop/hbase/client/MetaCache.java
----------------------------------------------------------------------
diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/MetaCache.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/MetaCache.java
new file mode 100644
index 0000000..b8cd429
--- /dev/null
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/MetaCache.java
@@ -0,0 +1,343 @@
+/**
+ * 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.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ConcurrentSkipListMap;
+import java.util.concurrent.ConcurrentSkipListSet;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.hadoop.classification.InterfaceAudience;
+import org.apache.hadoop.hbase.HConstants;
+import org.apache.hadoop.hbase.HRegionInfo;
+import org.apache.hadoop.hbase.HRegionLocation;
+import org.apache.hadoop.hbase.RegionLocations;
+import org.apache.hadoop.hbase.ServerName;
+import org.apache.hadoop.hbase.TableName;
+import org.apache.hadoop.hbase.util.Bytes;
+
+/**
+ * A cache implementation for region locations from meta.
+ */
+@InterfaceAudience.Private
+public class MetaCache {
+
+ private static final Log LOG = LogFactory.getLog(MetaCache.class);
+
+ /**
+ * Map of table to table {@link HRegionLocation}s.
+ */
+ private final ConcurrentMap<TableName, ConcurrentSkipListMap<byte[], RegionLocations>>
+ cachedRegionLocations =
+ new ConcurrentHashMap<TableName, ConcurrentSkipListMap<byte[], RegionLocations>>();
+
+ // 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.
+ // The access to this attribute must be protected by a lock on cachedRegionLocations
+ private final Set<ServerName> cachedServers = new ConcurrentSkipListSet<ServerName>();
+
+ /**
+ * Search the cache for a location that fits our table and row key.
+ * Return null if no suitable region is located.
+ *
+ * @param tableName
+ * @param row
+ * @return Null or region location found in cache.
+ */
+ public RegionLocations getCachedLocation(final TableName tableName, final byte [] row) {
+ ConcurrentSkipListMap<byte[], RegionLocations> tableLocations =
+ getTableLocations(tableName);
+
+ Entry<byte[], RegionLocations> e = tableLocations.floorEntry(row);
+ if (e == null) {
+ return null;
+ }
+ RegionLocations possibleRegion = e.getValue();
+
+ // 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_END_ROW, signifying that the region we're
+ // checking is actually the last region in the table.
+ byte[] endKey = possibleRegion.getRegionLocation().getRegionInfo().getEndKey();
+ if (Bytes.equals(endKey, HConstants.EMPTY_END_ROW) ||
+ tableName.getRowComparator().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;
+ }
+
+ /**
+ * Put a newly discovered HRegionLocation into the cache.
+ * @param tableName The table name.
+ * @param source the source of the new location
+ * @param location the new location
+ */
+ public void cacheLocation(final TableName tableName, final ServerName source,
+ final HRegionLocation location) {
+ assert source != null;
+ byte [] startKey = location.getRegionInfo().getStartKey();
+ ConcurrentMap<byte[], RegionLocations> tableLocations = getTableLocations(tableName);
+ RegionLocations locations = new RegionLocations(new HRegionLocation[] {location}) ;
+ RegionLocations oldLocations = tableLocations.putIfAbsent(startKey, locations);
+ boolean isNewCacheEntry = (oldLocations == null);
+ if (isNewCacheEntry) {
+ addToCachedServers(locations);
+ return;
+ }
+
+ // If the server in cache sends us a redirect, assume it's always valid.
+ HRegionLocation oldLocation = oldLocations.getRegionLocation(
+ location.getRegionInfo().getReplicaId());
+ boolean force = oldLocation != null && oldLocation.getServerName() != null
+ && oldLocation.getServerName().equals(source);
+
+ // For redirect if the number is equal to previous
+ // record, the most common case is that first the region was closed with seqNum, and then
+ // opened with the same seqNum; hence we will ignore the redirect.
+ // There are so many corner cases with various combinations of opens and closes that
+ // an additional counter on top of seqNum would be necessary to handle them all.
+ RegionLocations updatedLocations = oldLocations.updateLocation(location, false, force);
+ if (oldLocations != updatedLocations) {
+ tableLocations.replace(startKey, oldLocations, updatedLocations);
+ addToCachedServers(updatedLocations);
+ }
+ }
+
+ /**
+ * Put a newly discovered HRegionLocation into the cache.
+ * @param tableName The table name.
+ * @param location the new location
+ */
+ public void cacheLocation(final TableName tableName, final RegionLocations location) {
+ byte [] startKey = location.getRegionLocation().getRegionInfo().getStartKey();
+ ConcurrentMap<byte[], RegionLocations> tableLocations = getTableLocations(tableName);
+ RegionLocations oldLocation = tableLocations.putIfAbsent(startKey, location);
+ boolean isNewCacheEntry = (oldLocation == null);
+ if (isNewCacheEntry) {
+ addToCachedServers(location);
+ return;
+ }
+
+ // merge old and new locations and add it to the cache
+ // Meta record might be stale - some (probably the same) server has closed the region
+ // with later seqNum and told us about the new location.
+ RegionLocations mergedLocation = oldLocation.mergeLocations(location);
+ tableLocations.replace(startKey, oldLocation, mergedLocation);
+ addToCachedServers(location);
+ }
+
+ private void addToCachedServers(RegionLocations locations) {
+ for (HRegionLocation loc : locations.getRegionLocations()) {
+ if (loc != null) {
+ cachedServers.add(loc.getServerName());
+ }
+ }
+ }
+
+ /**
+ * @param tableName
+ * @return Map of cached locations for passed <code>tableName</code>
+ */
+ private ConcurrentSkipListMap<byte[], RegionLocations>
+ getTableLocations(final TableName tableName) {
+ // find the map of cached locations for this table
+ ConcurrentSkipListMap<byte[], RegionLocations> result;
+ result = this.cachedRegionLocations.get(tableName);
+ // if tableLocations for this table isn't built yet, make one
+ if (result == null) {
+ result = new ConcurrentSkipListMap<byte[], RegionLocations>(Bytes.BYTES_COMPARATOR);
+ ConcurrentSkipListMap<byte[], RegionLocations> old =
+ this.cachedRegionLocations.putIfAbsent(tableName, result);
+ if (old != null) {
+ return old;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Check the region cache to see whether a region is cached yet or not.
+ * @param tableName tableName
+ * @param row row
+ * @return Region cached or not.
+ */
+ public boolean isRegionCached(TableName tableName, final byte[] row) {
+ RegionLocations location = getCachedLocation(tableName, row);
+ return location != null;
+ }
+
+ /**
+ * Return the number of cached region for a table. It will only be called
+ * from a unit test.
+ */
+ public int getNumberOfCachedRegionLocations(final TableName tableName) {
+ Map<byte[], RegionLocations> tableLocs = this.cachedRegionLocations.get(tableName);
+ if (tableLocs == null) {
+ return 0;
+ }
+ int numRegions = 0;
+ for (RegionLocations tableLoc : tableLocs.values()) {
+ numRegions += tableLoc.numNonNullElements();
+ }
+ return numRegions;
+ }
+
+ /**
+ * Delete all cached entries.
+ */
+ public void clearCache() {
+ this.cachedRegionLocations.clear();
+ this.cachedServers.clear();
+ }
+
+ /**
+ * Delete all cached entries of a server.
+ */
+ public void clearCache(final ServerName serverName) {
+ if (!this.cachedServers.contains(serverName)) {
+ return;
+ }
+
+ boolean deletedSomething = false;
+ synchronized (this.cachedServers) {
+ // We block here, because if there is an error on a server, it's likely that multiple
+ // threads will get the error simultaneously. If there are hundreds of thousand of
+ // region location to check, it's better to do this only once. A better pattern would
+ // be to check if the server is dead when we get the region location.
+ if (!this.cachedServers.contains(serverName)) {
+ return;
+ }
+ for (ConcurrentMap<byte[], RegionLocations> tableLocations : cachedRegionLocations.values()){
+ for (Entry<byte[], RegionLocations> e : tableLocations.entrySet()) {
+ RegionLocations regionLocations = e.getValue();
+ if (regionLocations != null) {
+ RegionLocations updatedLocations = regionLocations.removeByServer(serverName);
+ deletedSomething |= regionLocations == updatedLocations;
+ if (updatedLocations != regionLocations) {
+ if (updatedLocations.isEmpty()) {
+ tableLocations.remove(e.getKey(), regionLocations);
+ } else {
+ tableLocations.replace(e.getKey(), regionLocations, updatedLocations);
+ }
+ }
+ }
+ }
+ }
+ this.cachedServers.remove(serverName);
+ }
+ if (deletedSomething && LOG.isDebugEnabled()) {
+ LOG.debug("Removed all cached region locations that map to " + serverName);
+ }
+ }
+
+ /**
+ * Delete all cached entries of a table.
+ */
+ public void clearCache(final TableName tableName) {
+ this.cachedRegionLocations.remove(tableName);
+ }
+
+ /**
+ * Delete a cached location, no matter what it is. Called when we were told to not use cache.
+ * @param tableName tableName
+ * @param row
+ */
+ public void clearCache(final TableName tableName, final byte [] row) {
+ ConcurrentMap<byte[], RegionLocations> tableLocations = getTableLocations(tableName);
+
+ RegionLocations regionLocations = getCachedLocation(tableName, row);
+ if (regionLocations != null) {
+ byte[] startKey = regionLocations.getRegionLocation().getRegionInfo().getStartKey();
+ boolean removed = tableLocations.remove(startKey, regionLocations);
+ if (removed && LOG.isDebugEnabled()) {
+ LOG.debug("Removed " + regionLocations + " from cache");
+ }
+ }
+ }
+
+ /**
+ * Delete a cached location for a table, row and server
+ */
+ public void clearCache(final TableName tableName, final byte [] row, ServerName serverName) {
+ ConcurrentMap<byte[], RegionLocations> tableLocations = getTableLocations(tableName);
+
+ RegionLocations regionLocations = getCachedLocation(tableName, row);
+ if (regionLocations != null) {
+ RegionLocations updatedLocations = regionLocations.removeByServer(serverName);
+ if (updatedLocations != regionLocations) {
+ byte[] startKey = regionLocations.getRegionLocation().getRegionInfo().getStartKey();
+ if (updatedLocations.isEmpty()) {
+ tableLocations.remove(startKey, regionLocations);
+ } else {
+ tableLocations.replace(startKey, regionLocations, updatedLocations);
+ }
+ }
+ }
+ }
+
+ /**
+ * Deletes the cached location of the region if necessary, based on some error from source.
+ * @param hri The region in question.
+ */
+ public void clearCache(HRegionInfo hri) {
+ ConcurrentMap<byte[], RegionLocations> tableLocations = getTableLocations(hri.getTable());
+ RegionLocations regionLocations = tableLocations.get(hri.getStartKey());
+ if (regionLocations != null) {
+ HRegionLocation oldLocation = regionLocations.getRegionLocation(hri.getReplicaId());
+ RegionLocations updatedLocations = regionLocations.remove(oldLocation);
+ if (updatedLocations != regionLocations) {
+ if (updatedLocations.isEmpty()) {
+ tableLocations.remove(hri.getStartKey(), regionLocations);
+ } else {
+ tableLocations.replace(hri.getStartKey(), regionLocations, updatedLocations);
+ }
+ }
+ }
+ }
+
+ public void clearCache(final HRegionLocation location) {
+ if (location == null) {
+ return;
+ }
+
+ TableName tableName = location.getRegionInfo().getTable();
+ ConcurrentMap<byte[], RegionLocations> tableLocations = getTableLocations(tableName);
+ RegionLocations rll = tableLocations.get(location.getRegionInfo().getStartKey());
+ RegionLocations updatedLocations = rll.remove(location);
+ if (updatedLocations.isEmpty()) {
+ tableLocations.remove(location.getRegionInfo().getStartKey(), rll);
+ }
+ if (LOG.isDebugEnabled() && (rll == updatedLocations)) {
+ LOG.debug("Removed " +
+ location.getRegionInfo().getRegionNameAsString() +
+ " for tableName=" + tableName +
+ " from cache");
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/hbase/blob/d4b82224/hbase-client/src/main/java/org/apache/hadoop/hbase/client/MetaScanner.java
----------------------------------------------------------------------
diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/MetaScanner.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/MetaScanner.java
index b4d3268..1442cbf 100644
--- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/MetaScanner.java
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/MetaScanner.java
@@ -30,11 +30,14 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.conf.Configuration;
-import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.HConstants;
import org.apache.hadoop.hbase.HRegionInfo;
+import org.apache.hadoop.hbase.HRegionLocation;
+import org.apache.hadoop.hbase.RegionLocations;
import org.apache.hadoop.hbase.ServerName;
+import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.TableNotFoundException;
+import org.apache.hadoop.hbase.catalog.MetaReader;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.hadoop.hbase.util.ExceptionUtil;
@@ -50,6 +53,7 @@ import org.apache.hadoop.hbase.util.ExceptionUtil;
* see HBASE-5986, and {@link DefaultMetaScannerVisitor} for details. </p>
*/
@InterfaceAudience.Private
+//TODO: merge this to MetaReader, get rid of it.
public class MetaScanner {
private static final Log LOG = LogFactory.getLog(MetaScanner.class);
/**
@@ -216,14 +220,14 @@ public class MetaScanner {
* table Result.
* @param data a Result object from the catalog table scan
* @return HRegionInfo or null
+ * @deprecated Use {@link MetaReader#getRegionLocations(Result)}
*/
+ @Deprecated
public static HRegionInfo getHRegionInfo(Result data) {
return HRegionInfo.getHRegionInfo(data);
}
/**
- * Used in tests.
- *
* Lists all of the regions currently in META.
* @param conf
* @param offlined True if we are to include offlined regions, false and we'll
@@ -234,22 +238,23 @@ public class MetaScanner {
public static List<HRegionInfo> listAllRegions(Configuration conf, final boolean offlined)
throws IOException {
final List<HRegionInfo> regions = new ArrayList<HRegionInfo>();
- MetaScannerVisitor visitor = new DefaultMetaScannerVisitor() {
+ MetaScannerVisitor visitor = new MetaScannerVisitorBase() {
@Override
- public boolean processRowInternal(Result result) throws IOException {
+ public boolean processRow(Result result) throws IOException {
if (result == null || result.isEmpty()) {
return true;
}
- HRegionInfo regionInfo = getHRegionInfo(result);
- if (regionInfo == null) {
- LOG.warn("Null REGIONINFO_QUALIFIER: " + result);
- return true;
+ RegionLocations locations = MetaReader.getRegionLocations(result);
+ if (locations == null) return true;
+ for (HRegionLocation loc : locations.getRegionLocations()) {
+ if (loc != null) {
+ HRegionInfo regionInfo = loc.getRegionInfo();
+ // If region offline AND we are not to include offlined regions, return.
+ if (regionInfo.isOffline() && !offlined) continue;
+ regions.add(regionInfo);
+ }
}
-
- // If region offline AND we are not to include offlined regions, return.
- if (regionInfo.isOffline() && !offlined) return true;
- regions.add(regionInfo);
return true;
}
};
@@ -272,10 +277,34 @@ public class MetaScanner {
new TreeMap<HRegionInfo, ServerName>();
MetaScannerVisitor visitor = new TableMetaScannerVisitor(tableName) {
@Override
- public boolean processRowInternal(Result rowResult) throws IOException {
- HRegionInfo info = getHRegionInfo(rowResult);
- ServerName serverName = HRegionInfo.getServerName(rowResult);
- regions.put(new UnmodifyableHRegionInfo(info), serverName);
+ public boolean processRowInternal(Result result) throws IOException {
+ RegionLocations locations = MetaReader.getRegionLocations(result);
+ if (locations == null) return true;
+ for (HRegionLocation loc : locations.getRegionLocations()) {
+ if (loc != null) {
+ HRegionInfo regionInfo = loc.getRegionInfo();
+ regions.put(new UnmodifyableHRegionInfo(regionInfo), loc.getServerName());
+ }
+ }
+ return true;
+ }
+ };
+ metaScan(conf, connection, visitor, tableName);
+ return regions;
+ }
+
+ /**
+ * Lists table regions and locations grouped by region range from META.
+ */
+ public static List<RegionLocations> listTableRegionLocations(Configuration conf,
+ ClusterConnection connection, final TableName tableName) throws IOException {
+ final List<RegionLocations> regions = new ArrayList<RegionLocations>();
+ MetaScannerVisitor visitor = new TableMetaScannerVisitor(tableName) {
+ @Override
+ public boolean processRowInternal(Result result) throws IOException {
+ RegionLocations locations = MetaReader.getRegionLocations(result);
+ if (locations == null) return true;
+ regions.add(locations);
return true;
}
};
http://git-wip-us.apache.org/repos/asf/hbase/blob/d4b82224/hbase-client/src/main/java/org/apache/hadoop/hbase/client/RegionReplicaUtil.java
----------------------------------------------------------------------
diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/RegionReplicaUtil.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/RegionReplicaUtil.java
new file mode 100644
index 0000000..abe9bf5
--- /dev/null
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/RegionReplicaUtil.java
@@ -0,0 +1,65 @@
+/**
+ * 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 org.apache.hadoop.classification.InterfaceAudience;
+import org.apache.hadoop.hbase.HRegionInfo;
+
+/**
+ * Utility methods which contain the logic for regions and replicas.
+ */
+@InterfaceAudience.Private
+public class RegionReplicaUtil {
+
+ /**
+ * The default replicaId for the region
+ */
+ private static final int DEFAULT_REPLICA_ID = 0;
+
+ /**
+ * Returns the HRegionInfo for the given replicaId. HRegionInfo's correspond to
+ * a range of a table, but more than one "instance" of the same range can be
+ * deployed which are differentiated by the replicaId.
+ * @param replicaId the replicaId to use
+ * @return an HRegionInfo object corresponding to the same range (table, start and
+ * end key), but for the given replicaId.
+ */
+ public static HRegionInfo getRegionInfoForReplica(HRegionInfo regionInfo, int replicaId) {
+ if (regionInfo.getReplicaId() == replicaId) {
+ return regionInfo;
+ }
+ HRegionInfo replicaInfo = new HRegionInfo(regionInfo.getTable(), regionInfo.getStartKey(),
+ regionInfo.getEndKey(), regionInfo.isSplit(), regionInfo.getRegionId(), replicaId);
+
+ replicaInfo.setOffline(regionInfo.isOffline());
+ return replicaInfo;
+ }
+
+ /**
+ * Returns the HRegionInfo for the default replicaId (0). HRegionInfo's correspond to
+ * a range of a table, but more than one "instance" of the same range can be
+ * deployed which are differentiated by the replicaId.
+ * @return an HRegionInfo object corresponding to the same range (table, start and
+ * end key), but for the default replicaId.
+ */
+ public static HRegionInfo getRegionInfoForDefaultReplica(HRegionInfo regionInfo) {
+ return getRegionInfoForReplica(regionInfo, DEFAULT_REPLICA_ID);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/hbase/blob/d4b82224/hbase-client/src/main/java/org/apache/hadoop/hbase/client/RegionServerCallable.java
----------------------------------------------------------------------
diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/RegionServerCallable.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/RegionServerCallable.java
index 1740a2d..1cefb7f 100644
--- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/RegionServerCallable.java
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/RegionServerCallable.java
@@ -73,6 +73,7 @@ public abstract class RegionServerCallable<T> implements RetryingCallable<T> {
* @param reload Set this to true if connection should re-find the region
* @throws IOException e
*/
+ @Override
public void prepare(final boolean reload) throws IOException {
this.location = connection.getRegionLocation(tableName, row, reload);
if (this.location == null) {
@@ -124,7 +125,7 @@ public abstract class RegionServerCallable<T> implements RetryingCallable<T> {
// hbase:meta again to find the new location
if (this.location != null) getConnection().clearCaches(location.getServerName());
} else if (t instanceof RegionMovedException) {
- getConnection().updateCachedLocations(tableName, row, t, location.getServerName());
+ getConnection().updateCachedLocations(tableName, row, t, location);
} else if (t instanceof NotServingRegionException && !retrying) {
// Purge cache entries for this specific region from hbase:meta cache
// since we don't call connect(true) when number of retries is 1.
http://git-wip-us.apache.org/repos/asf/hbase/blob/d4b82224/hbase-client/src/main/java/org/apache/hadoop/hbase/client/Registry.java
----------------------------------------------------------------------
diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/Registry.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/Registry.java
index 2890cf4..aab547e 100644
--- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/Registry.java
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/Registry.java
@@ -19,8 +19,8 @@ package org.apache.hadoop.hbase.client;
import java.io.IOException;
+import org.apache.hadoop.hbase.RegionLocations;
import org.apache.hadoop.hbase.TableName;
-import org.apache.hadoop.hbase.HRegionLocation;
/**
* Cluster registry.
@@ -36,7 +36,7 @@ interface Registry {
* @return Meta region location
* @throws IOException
*/
- HRegionLocation getMetaRegionLocation() throws IOException;
+ RegionLocations getMetaRegionLocation() throws IOException;
/**
* @return Cluster id.
http://git-wip-us.apache.org/repos/asf/hbase/blob/d4b82224/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ZooKeeperRegistry.java
----------------------------------------------------------------------
diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ZooKeeperRegistry.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ZooKeeperRegistry.java
index 529b7f6..ca7ce68 100644
--- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ZooKeeperRegistry.java
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ZooKeeperRegistry.java
@@ -22,10 +22,11 @@ import java.io.InterruptedIOException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
-import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.HRegionInfo;
import org.apache.hadoop.hbase.HRegionLocation;
+import org.apache.hadoop.hbase.RegionLocations;
import org.apache.hadoop.hbase.ServerName;
+import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.zookeeper.MetaRegionTracker;
import org.apache.hadoop.hbase.zookeeper.ZKClusterId;
import org.apache.hadoop.hbase.zookeeper.ZKTableStateClientSideReader;
@@ -49,7 +50,7 @@ class ZooKeeperRegistry implements Registry {
}
@Override
- public HRegionLocation getMetaRegionLocation() throws IOException {
+ public RegionLocations getMetaRegionLocation() throws IOException {
ZooKeeperKeepAliveConnection zkw = hci.getKeepAliveZooKeeperWatcher();
try {
@@ -62,7 +63,8 @@ class ZooKeeperRegistry implements Registry {
"; serverName=" + ((servername == null) ? "null" : servername));
}
if (servername == null) return null;
- return new HRegionLocation(HRegionInfo.FIRST_META_REGIONINFO, servername, 0);
+ HRegionLocation loc = new HRegionLocation(HRegionInfo.FIRST_META_REGIONINFO, servername, 0);
+ return new RegionLocations(new HRegionLocation[] {loc});
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return null;
http://git-wip-us.apache.org/repos/asf/hbase/blob/d4b82224/hbase-client/src/test/java/org/apache/hadoop/hbase/TestRegionLocations.java
----------------------------------------------------------------------
diff --git a/hbase-client/src/test/java/org/apache/hadoop/hbase/TestRegionLocations.java b/hbase-client/src/test/java/org/apache/hadoop/hbase/TestRegionLocations.java
new file mode 100644
index 0000000..603f8d5
--- /dev/null
+++ b/hbase-client/src/test/java/org/apache/hadoop/hbase/TestRegionLocations.java
@@ -0,0 +1,275 @@
+/**
+ * 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;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+public class TestRegionLocations {
+
+ ServerName sn0 = ServerName.valueOf("host0", 10, 10);
+ ServerName sn1 = ServerName.valueOf("host1", 10, 10);
+ ServerName sn2 = ServerName.valueOf("host2", 10, 10);
+ ServerName sn3 = ServerName.valueOf("host3", 10, 10);
+
+ HRegionInfo info0 = hri(0);
+ HRegionInfo info1 = hri(1);
+ HRegionInfo info2 = hri(2);
+ HRegionInfo info9 = hri(9);
+
+ @Test
+ public void testSizeMethods() {
+ RegionLocations list = new RegionLocations();
+ assertTrue(list.isEmpty());
+ assertEquals(0, list.size());
+ assertEquals(0, list.numNonNullElements());
+
+ list = hrll((HRegionLocation)null);
+ assertTrue(list.isEmpty());
+ assertEquals(0, list.size());
+ assertEquals(0, list.numNonNullElements());
+
+ HRegionInfo info0 = hri(0);
+ list = hrll(hrl(info0, null));
+ assertFalse(list.isEmpty());
+ assertEquals(1, list.size());
+ assertEquals(1, list.numNonNullElements());
+
+ HRegionInfo info9 = hri(9);
+ list = hrll(hrl(info9, null));
+ assertFalse(list.isEmpty());
+ assertEquals(10, list.size());
+ assertEquals(1, list.numNonNullElements());
+
+ list = hrll(hrl(info0, null), hrl(info9, null));
+ assertFalse(list.isEmpty());
+ assertEquals(10, list.size());
+ assertEquals(2, list.numNonNullElements());
+ }
+
+ private HRegionInfo hri(int replicaId) {
+ TableName table = TableName.valueOf("table");
+ byte[] startKey = HConstants.EMPTY_START_ROW;
+ byte[] endKey = HConstants.EMPTY_END_ROW;
+ long regionId = System.currentTimeMillis();
+ HRegionInfo info = new HRegionInfo(table, startKey, endKey, false, regionId, replicaId);
+ return info;
+ }
+
+ private HRegionLocation hrl(HRegionInfo hri, ServerName sn) {
+ return new HRegionLocation(hri, sn);
+ }
+
+ private HRegionLocation hrl(HRegionInfo hri, ServerName sn, long seqNum) {
+ return new HRegionLocation(hri, sn, seqNum);
+ }
+
+ private RegionLocations hrll(HRegionLocation ... locations) {
+ return new RegionLocations(locations);
+ }
+
+ @Test
+ public void testRemoveByServer() {
+ RegionLocations list;
+
+ // test remove from empty list
+ list = new RegionLocations();
+ assertTrue(list == list.removeByServer(sn0));
+
+ // test remove from single element list
+ list = hrll(hrl(info0, sn0));
+ assertTrue(list == list.removeByServer(sn1));
+ list = list.removeByServer(sn0);
+ assertTrue(list.isEmpty());
+
+ // test remove from multi element list
+ list = hrll(hrl(info0, sn0), hrl(info1, sn1), hrl(info2, sn2), hrl(info9, sn2));
+ assertTrue(list == list.removeByServer(sn3)); // no region is mapped to sn3
+ list = list.removeByServer(sn0);
+ assertNull(list.getRegionLocation(0));
+ assertEquals(sn1, list.getRegionLocation(1).getServerName());
+ assertEquals(sn2, list.getRegionLocation(2).getServerName());
+ assertNull(list.getRegionLocation(5));
+ assertEquals(sn2, list.getRegionLocation(9).getServerName());
+
+ // test multi-element remove from multi element list
+ list = hrll(hrl(info0, sn1), hrl(info1, sn1), hrl(info2, sn0), hrl(info9, sn0));
+ list = list.removeByServer(sn0);
+ assertEquals(sn1, list.getRegionLocation(0).getServerName());
+ assertEquals(sn1, list.getRegionLocation(1).getServerName());
+ assertNull(list.getRegionLocation(2));
+ assertNull(list.getRegionLocation(5));
+ assertNull(list.getRegionLocation(9));
+ }
+
+ @Test
+ public void testRemove() {
+ RegionLocations list;
+
+ // test remove from empty list
+ list = new RegionLocations();
+ assertTrue(list == list.remove(hrl(info0, sn0)));
+
+ // test remove from single element list
+ list = hrll(hrl(info0, sn0));
+ assertTrue(list == list.remove(hrl(info0, sn1)));
+ list = list.remove(hrl(info0, sn0));
+ assertTrue(list.isEmpty());
+
+ // test remove from multi element list
+ list = hrll(hrl(info0, sn0), hrl(info1, sn1), hrl(info2, sn2), hrl(info9, sn2));
+ assertTrue(list == list.remove(hrl(info1, sn3))); // no region is mapped to sn3
+ list = list.remove(hrl(info0, sn0));
+ assertNull(list.getRegionLocation(0));
+ assertEquals(sn1, list.getRegionLocation(1).getServerName());
+ assertEquals(sn2, list.getRegionLocation(2).getServerName());
+ assertNull(list.getRegionLocation(5));
+ assertEquals(sn2, list.getRegionLocation(9).getServerName());
+
+ list = list.remove(hrl(info9, sn2));
+ assertNull(list.getRegionLocation(0));
+ assertEquals(sn1, list.getRegionLocation(1).getServerName());
+ assertEquals(sn2, list.getRegionLocation(2).getServerName());
+ assertNull(list.getRegionLocation(5));
+ assertNull(list.getRegionLocation(9));
+
+
+ // test multi-element remove from multi element list
+ list = hrll(hrl(info0, sn1), hrl(info1, sn1), hrl(info2, sn0), hrl(info9, sn0));
+ list = list.remove(hrl(info9, sn0));
+ assertEquals(sn1, list.getRegionLocation(0).getServerName());
+ assertEquals(sn1, list.getRegionLocation(1).getServerName());
+ assertEquals(sn0, list.getRegionLocation(2).getServerName());
+ assertNull(list.getRegionLocation(5));
+ assertNull(list.getRegionLocation(9));
+ }
+
+ @Test
+ public void testUpdateLocation() {
+ RegionLocations list;
+
+ // test add to empty list
+ list = new RegionLocations();
+ list = list.updateLocation(hrl(info0, sn1), false, false);
+ assertEquals(sn1, list.getRegionLocation(0).getServerName());
+
+ // test add to non-empty list
+ list = list.updateLocation(hrl(info9, sn3, 10), false, false);
+ assertEquals(sn3, list.getRegionLocation(9).getServerName());
+ assertEquals(10, list.size());
+ list = list.updateLocation(hrl(info2, sn2, 10), false, false);
+ assertEquals(sn2, list.getRegionLocation(2).getServerName());
+ assertEquals(10, list.size());
+
+ // test update greater SeqNum
+ list = list.updateLocation(hrl(info2, sn3, 11), false, false);
+ assertEquals(sn3, list.getRegionLocation(2).getServerName());
+ assertEquals(sn3, list.getRegionLocation(9).getServerName());
+
+ // test update equal SeqNum
+ list = list.updateLocation(hrl(info2, sn1, 11), false, false); // should not update
+ assertEquals(sn3, list.getRegionLocation(2).getServerName());
+ assertEquals(sn3, list.getRegionLocation(9).getServerName());
+ list = list.updateLocation(hrl(info2, sn1, 11), true, false); // should update
+ assertEquals(sn1, list.getRegionLocation(2).getServerName());
+ assertEquals(sn3, list.getRegionLocation(9).getServerName());
+
+ // test force update
+ list = list.updateLocation(hrl(info2, sn2, 9), false, true); // should update
+ assertEquals(sn2, list.getRegionLocation(2).getServerName());
+ assertEquals(sn3, list.getRegionLocation(9).getServerName());
+ }
+
+ @Test
+ public void testMergeLocations() {
+ RegionLocations list1, list2;
+
+ // test merge empty lists
+ list1 = new RegionLocations();
+ list2 = new RegionLocations();
+
+ assertTrue(list1 == list1.mergeLocations(list2));
+
+ // test merge non-empty and empty
+ list2 = hrll(hrl(info0, sn0));
+ list1 = list1.mergeLocations(list2);
+ assertEquals(sn0, list1.getRegionLocation(0).getServerName());
+
+ // test merge empty and non empty
+ list1 = hrll();
+ list1 = list2.mergeLocations(list1);
+ assertEquals(sn0, list1.getRegionLocation(0).getServerName());
+
+ // test merge non intersecting
+ list1 = hrll(hrl(info0, sn0), hrl(info1, sn1));
+ list2 = hrll(hrl(info2, sn2));
+ list1 = list2.mergeLocations(list1);
+ assertEquals(sn0, list1.getRegionLocation(0).getServerName());
+ assertEquals(sn1, list1.getRegionLocation(1).getServerName());
+ assertEquals(sn2, list1.getRegionLocation(2).getServerName());
+
+ // do the other way merge as well
+ list1 = hrll(hrl(info0, sn0), hrl(info1, sn1));
+ list2 = hrll(hrl(info2, sn2));
+ list1 = list1.mergeLocations(list2);
+ assertEquals(sn0, list1.getRegionLocation(0).getServerName());
+ assertEquals(sn1, list1.getRegionLocation(1).getServerName());
+ assertEquals(sn2, list1.getRegionLocation(2).getServerName());
+
+ // test intersecting lists same seqNum
+ list1 = hrll(hrl(info0, sn0), hrl(info1, sn1));
+ list2 = hrll(hrl(info0, sn2), hrl(info1, sn2), hrl(info9, sn3));
+ list1 = list2.mergeLocations(list1); // list1 should override
+ assertEquals(10, list1.size());
+ assertEquals(sn0, list1.getRegionLocation(0).getServerName());
+ assertEquals(sn1, list1.getRegionLocation(1).getServerName());
+ assertEquals(sn3, list1.getRegionLocation(9).getServerName());
+
+ // do the other way
+ list1 = hrll(hrl(info0, sn0), hrl(info1, sn1));
+ list2 = hrll(hrl(info0, sn2), hrl(info1, sn2), hrl(info9, sn3));
+ list1 = list1.mergeLocations(list2); // list2 should override
+ assertEquals(10, list1.size());
+ assertEquals(sn2, list1.getRegionLocation(0).getServerName());
+ assertEquals(sn2, list1.getRegionLocation(1).getServerName());
+ assertEquals(sn3, list1.getRegionLocation(9).getServerName());
+
+ // test intersecting lists different seqNum
+ list1 = hrll(hrl(info0, sn0, 10), hrl(info1, sn1, 10));
+ list2 = hrll(hrl(info0, sn2, 11), hrl(info1, sn2, 11), hrl(info9, sn3, 11));
+ list1 = list1.mergeLocations(list2); // list2 should override because of seqNum
+ assertEquals(10, list1.size());
+ assertEquals(sn2, list1.getRegionLocation(0).getServerName());
+ assertEquals(sn2, list1.getRegionLocation(1).getServerName());
+ assertEquals(sn3, list1.getRegionLocation(9).getServerName());
+
+ // do the other way
+ list1 = hrll(hrl(info0, sn0, 10), hrl(info1, sn1, 10));
+ list2 = hrll(hrl(info0, sn2, 11), hrl(info1, sn2, 11), hrl(info9, sn3, 11));
+ list1 = list1.mergeLocations(list2); // list2 should override
+ assertEquals(10, list1.size());
+ assertEquals(sn2, list1.getRegionLocation(0).getServerName());
+ assertEquals(sn2, list1.getRegionLocation(1).getServerName());
+ assertEquals(sn3, list1.getRegionLocation(9).getServerName());
+ }
+}
http://git-wip-us.apache.org/repos/asf/hbase/blob/d4b82224/hbase-client/src/test/java/org/apache/hadoop/hbase/client/TestClientNoCluster.java
----------------------------------------------------------------------
diff --git a/hbase-client/src/test/java/org/apache/hadoop/hbase/client/TestClientNoCluster.java b/hbase-client/src/test/java/org/apache/hadoop/hbase/client/TestClientNoCluster.java
index 2067e01..64301c1 100644
--- a/hbase-client/src/test/java/org/apache/hadoop/hbase/client/TestClientNoCluster.java
+++ b/hbase-client/src/test/java/org/apache/hadoop/hbase/client/TestClientNoCluster.java
@@ -43,6 +43,7 @@ import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.HConstants;
import org.apache.hadoop.hbase.HRegionInfo;
import org.apache.hadoop.hbase.HRegionLocation;
+import org.apache.hadoop.hbase.RegionLocations;
import org.apache.hadoop.hbase.KeyValue;
import org.apache.hadoop.hbase.RegionTooBusyException;
import org.apache.hadoop.hbase.ServerName;
@@ -117,8 +118,9 @@ public class TestClientNoCluster extends Configured implements Tool {
}
@Override
- public HRegionLocation getMetaRegionLocation() throws IOException {
- return new HRegionLocation(HRegionInfo.FIRST_META_REGIONINFO, META_HOST);
+ public RegionLocations getMetaRegionLocation() throws IOException {
+ return new RegionLocations(
+ new HRegionLocation(HRegionInfo.FIRST_META_REGIONINFO, META_HOST));
}
@Override
@@ -142,7 +144,7 @@ public class TestClientNoCluster extends Configured implements Tool {
* Remove the @Ignore to try out timeout and retry asettings
* @throws IOException
*/
- @Ignore
+ @Ignore
@Test
public void testTimeoutAndRetries() throws IOException {
Configuration localConfig = HBaseConfiguration.create(this.conf);
@@ -759,7 +761,7 @@ public class TestClientNoCluster extends Configured implements Tool {
// an exception is thrown -- usually RegionTooBusyException when we have more than
// hbase.test.multi.too.many requests outstanding at any time.
getConf().setInt("hbase.client.start.log.errors.counter", 0);
-
+
// Ugly but this is only way to pass in configs.into ManyServersManyRegionsConnection class.
getConf().setInt("hbase.test.regions", regions);
getConf().setLong("hbase.test.namespace.span", namespaceSpan);
http://git-wip-us.apache.org/repos/asf/hbase/blob/d4b82224/hbase-common/src/main/java/org/apache/hadoop/hbase/HConstants.java
----------------------------------------------------------------------
diff --git a/hbase-common/src/main/java/org/apache/hadoop/hbase/HConstants.java b/hbase-common/src/main/java/org/apache/hadoop/hbase/HConstants.java
index b27679c..65f2086 100644
--- a/hbase-common/src/main/java/org/apache/hadoop/hbase/HConstants.java
+++ b/hbase-common/src/main/java/org/apache/hadoop/hbase/HConstants.java
@@ -397,13 +397,19 @@ public final class HConstants {
public static final byte [] REGIONINFO_QUALIFIER = Bytes.toBytes(REGIONINFO_QUALIFIER_STR);
/** The server column qualifier */
- public static final byte [] SERVER_QUALIFIER = Bytes.toBytes("server");
+ public static final String SERVER_QUALIFIER_STR = "server";
+ /** The server column qualifier */
+ public static final byte [] SERVER_QUALIFIER = Bytes.toBytes(SERVER_QUALIFIER_STR);
/** The startcode column qualifier */
- public static final byte [] STARTCODE_QUALIFIER = Bytes.toBytes("serverstartcode");
+ public static final String STARTCODE_QUALIFIER_STR = "serverstartcode";
+ /** The startcode column qualifier */
+ public static final byte [] STARTCODE_QUALIFIER = Bytes.toBytes(STARTCODE_QUALIFIER_STR);
/** The open seqnum column qualifier */
- public static final byte [] SEQNUM_QUALIFIER = Bytes.toBytes("seqnumDuringOpen");
+ public static final String SEQNUM_QUALIFIER_STR = "seqnumDuringOpen";
+ /** The open seqnum column qualifier */
+ public static final byte [] SEQNUM_QUALIFIER = Bytes.toBytes(SEQNUM_QUALIFIER_STR);
/** The state column qualifier */
public static final byte [] STATE_QUALIFIER = Bytes.toBytes("state");