HBASE-9861 Location does not have to be refreshed on regionTooBusy
git-svn-id: https://svn.apache.org/repos/asf/hbase/trunk@1537425 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
68db456397
commit
e828b5eb69
|
@ -56,6 +56,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.RegionTooBusyException;
|
||||
import org.apache.hadoop.hbase.ServerName;
|
||||
import org.apache.hadoop.hbase.Stoppable;
|
||||
import org.apache.hadoop.hbase.TableName;
|
||||
|
@ -2208,7 +2209,8 @@ public class HConnectionManager {
|
|||
|
||||
/**
|
||||
* Update the location with the new value (if the exception is a RegionMovedException)
|
||||
* or delete it from the cache.
|
||||
* or delete it from the cache. Does nothing if we can be sure from the exception that
|
||||
* the location is still accurate, or if the cache has already been updated.
|
||||
* @param exception an object (to simplify user code) on which we will try to find a nested
|
||||
* or wrapped or both RegionMovedException
|
||||
* @param source server that is the source of the location update.
|
||||
|
@ -2222,30 +2224,45 @@ public class HConnectionManager {
|
|||
return;
|
||||
}
|
||||
|
||||
if (source == null || source.getServerName() == null){
|
||||
// This should not happen, but let's secure ourselves.
|
||||
return;
|
||||
}
|
||||
|
||||
// Is it something we have already updated?
|
||||
final HRegionLocation oldLocation = getCachedLocation(tableName, rowkey);
|
||||
if (oldLocation == null) {
|
||||
// There is no such location in the cache => it's been removed already => nothing to do
|
||||
if (oldLocation == null || !source.getServerName().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
|
||||
return;
|
||||
}
|
||||
|
||||
HRegionInfo regionInfo = oldLocation.getRegionInfo();
|
||||
final RegionMovedException rme = RegionMovedException.find(exception);
|
||||
if (rme != null) {
|
||||
if (LOG.isTraceEnabled()){
|
||||
LOG.trace("Region " + regionInfo.getRegionNameAsString() + " moved to " +
|
||||
rme.getHostname() + ":" + rme.getPort() + " according to " + source.getHostnamePort());
|
||||
Throwable cause = findException(exception);
|
||||
if (cause != null) {
|
||||
if (cause instanceof RegionTooBusyException || cause instanceof RegionOpeningException) {
|
||||
// We know that the region is still on this region server
|
||||
return;
|
||||
}
|
||||
updateCachedLocation(
|
||||
regionInfo, source, rme.getServerName(), rme.getLocationSeqNum());
|
||||
} else if (RegionOpeningException.find(exception) != null) {
|
||||
if (LOG.isTraceEnabled()) {
|
||||
LOG.trace("Region " + regionInfo.getRegionNameAsString() + " is being opened on "
|
||||
+ source.getHostnamePort() + "; not deleting the cache entry");
|
||||
|
||||
if (cause instanceof RegionMovedException) {
|
||||
RegionMovedException rme = (RegionMovedException) cause;
|
||||
if (LOG.isTraceEnabled()) {
|
||||
LOG.trace("Region " + regionInfo.getRegionNameAsString() + " moved to " +
|
||||
rme.getHostname() + ":" + rme.getPort() +
|
||||
" according to " + source.getHostnamePort());
|
||||
}
|
||||
// We know that the region is not anymore on this region server, but we know
|
||||
// the new location.
|
||||
updateCachedLocation(
|
||||
regionInfo, source, rme.getServerName(), rme.getLocationSeqNum());
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
deleteCachedLocation(regionInfo, source);
|
||||
}
|
||||
|
||||
// If we're here, it means that can cannot be sure about the location, so we remove it from
|
||||
// the cache.
|
||||
deleteCachedLocation(regionInfo, source);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -2713,6 +2730,46 @@ public class HConnectionManager {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Look for an exception we know in the remote exception:
|
||||
* - hadoop.ipc wrapped exceptions
|
||||
* - nested exceptions
|
||||
*
|
||||
* Looks for: RegionMovedException / RegionOpeningException / RegionTooBusyException
|
||||
* @returns null if we didn't find the exception, the exception otherwise.
|
||||
*/
|
||||
public static Throwable findException(Object exception) {
|
||||
if (exception == null || !(exception instanceof Throwable)) {
|
||||
return null;
|
||||
}
|
||||
Throwable cur = (Throwable) exception;
|
||||
while (cur != null) {
|
||||
if (cur instanceof RegionMovedException || cur instanceof RegionOpeningException
|
||||
|| cur instanceof RegionTooBusyException) {
|
||||
return cur;
|
||||
}
|
||||
if (cur instanceof RemoteException) {
|
||||
RemoteException re = (RemoteException) cur;
|
||||
cur = re.unwrapRemoteException(
|
||||
RegionOpeningException.class, RegionMovedException.class,
|
||||
RegionTooBusyException.class);
|
||||
if (cur == null) {
|
||||
cur = re.unwrapRemoteException();
|
||||
}
|
||||
// unwrapRemoteException can return the exception given as a parameter when it cannot
|
||||
// unwrap it. In this case, there is no need to look further
|
||||
// noinspection ObjectEquality
|
||||
if (cur == re) {
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
cur = cur.getCause();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the number of retries to use serverside when trying to communicate
|
||||
* with another server over {@link HConnection}. Used updating catalog
|
||||
|
|
|
@ -109,47 +109,4 @@ public class RegionMovedException extends NotServingRegionException {
|
|||
return "Region moved to: " + HOST_FIELD + hostname + " " + PORT_FIELD + port + " " +
|
||||
STARTCODE_FIELD + startCode + ". As of " + LOCATIONSEQNUM_FIELD + locationSeqNum + ".";
|
||||
}
|
||||
|
||||
/**
|
||||
* Look for a RegionMovedException in the exception:
|
||||
* - hadoop.ipc wrapped exceptions
|
||||
* - nested exceptions
|
||||
* Returns null if we didn't find the exception or if it was not readable.
|
||||
*/
|
||||
public static RegionMovedException find(Object exception) {
|
||||
if (exception == null || !(exception instanceof Throwable)){
|
||||
return null;
|
||||
}
|
||||
|
||||
Throwable cur = (Throwable)exception;
|
||||
RegionMovedException res = null;
|
||||
|
||||
while (res == null && cur != null) {
|
||||
if (cur instanceof RegionMovedException) {
|
||||
res = (RegionMovedException) cur;
|
||||
} else {
|
||||
if (cur instanceof RemoteException) {
|
||||
RemoteException re = (RemoteException) cur;
|
||||
Exception e = re.unwrapRemoteException(RegionMovedException.class);
|
||||
if (e == null){
|
||||
e = re.unwrapRemoteException();
|
||||
}
|
||||
// unwrapRemoteException can return the exception given as a parameter when it cannot
|
||||
// unwrap it. In this case, there is no need to look further
|
||||
// noinspection ObjectEquality
|
||||
if (e != re){
|
||||
res = find(e);
|
||||
}
|
||||
}
|
||||
cur = cur.getCause();
|
||||
}
|
||||
}
|
||||
|
||||
if (res != null && (res.getPort() < 0 || res.getHostname() == null)){
|
||||
// We failed to parse the exception. Let's act as we don't find the exception.
|
||||
return null;
|
||||
} else {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,42 +38,4 @@ public class RegionOpeningException extends NotServingRegionException {
|
|||
public RegionOpeningException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Look for a RegionOpeningException in the exception:
|
||||
* - hadoop.ipc wrapped exceptions
|
||||
* - nested exceptions
|
||||
* Returns null if we didn't find the exception.
|
||||
* TODO: this code is mostly C/Ped from RegionMovedExecption. Due to the limitations of
|
||||
* generics it's not amenable to generalizing without adding parameters/isAssignableFrom.
|
||||
* Might make general if used in more places.
|
||||
*/
|
||||
public static RegionOpeningException find(Object exception) {
|
||||
if (exception == null || !(exception instanceof Throwable)) {
|
||||
return null;
|
||||
}
|
||||
RegionOpeningException res = null;
|
||||
Throwable cur = (Throwable)exception;
|
||||
while (res == null && cur != null) {
|
||||
if (cur instanceof RegionOpeningException) {
|
||||
res = (RegionOpeningException) cur;
|
||||
} else {
|
||||
if (cur instanceof RemoteException) {
|
||||
RemoteException re = (RemoteException) cur;
|
||||
Exception e = re.unwrapRemoteException(RegionOpeningException.class);
|
||||
if (e == null) {
|
||||
e = re.unwrapRemoteException();
|
||||
}
|
||||
// unwrapRemoteException can return the exception given as a parameter when it cannot
|
||||
// unwrap it. In this case, there is no need to look further
|
||||
// noinspection ObjectEquality
|
||||
if (e != re) {
|
||||
res = find(e);
|
||||
}
|
||||
}
|
||||
cur = cur.getCause();
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
|
@ -54,6 +54,7 @@ import org.apache.hadoop.hbase.TableName;
|
|||
import org.apache.hadoop.hbase.Waiter;
|
||||
import org.apache.hadoop.hbase.client.HConnectionManager.HConnectionImplementation;
|
||||
import org.apache.hadoop.hbase.exceptions.DeserializationException;
|
||||
import org.apache.hadoop.hbase.exceptions.RegionMovedException;
|
||||
import org.apache.hadoop.hbase.filter.Filter;
|
||||
import org.apache.hadoop.hbase.filter.FilterBase;
|
||||
import org.apache.hadoop.hbase.master.HMaster;
|
||||
|
@ -449,12 +450,18 @@ public class TestHCM {
|
|||
} catch (RetriesExhaustedWithDetailsException e){
|
||||
LOG.info("Put done, exception caught: " + e.getClass());
|
||||
Assert.assertEquals(1, e.getNumExceptions());
|
||||
Assert.assertEquals(1, e.getCauses().size());
|
||||
Assert.assertArrayEquals(e.getRow(0).getRow(), ROW);
|
||||
|
||||
// Check that we unserialized the exception as expected
|
||||
Throwable cause = HConnectionManager.findException(e.getCause(0));
|
||||
Assert.assertNotNull(cause);
|
||||
Assert.assertTrue(cause instanceof RegionMovedException);
|
||||
}
|
||||
Assert.assertNotNull("Cached connection is null", conn.getCachedLocation(TABLE_NAME, ROW));
|
||||
Assert.assertEquals(
|
||||
"Previous server was "+curServer.getServerName().getHostAndPort(),
|
||||
destServerName.getPort(), conn.getCachedLocation(TABLE_NAME, ROW).getPort());
|
||||
"Previous server was " + curServer.getServerName().getHostAndPort(),
|
||||
destServerName.getPort(), conn.getCachedLocation(TABLE_NAME, ROW).getPort());
|
||||
|
||||
Assert.assertFalse(destServer.getRegionsInTransitionInRS().containsKey(encodedRegionNameBytes));
|
||||
Assert.assertFalse(curServer.getRegionsInTransitionInRS().containsKey(encodedRegionNameBytes));
|
||||
|
|
Loading…
Reference in New Issue