diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/client/ServerCallable.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/client/ServerCallable.java index 47f699a..bdf31f8 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/client/ServerCallable.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/client/ServerCallable.java @@ -27,6 +27,8 @@ import java.util.ArrayList; import java.util.List; import java.util.concurrent.Callable; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import org.apache.hadoop.classification.InterfaceAudience; import org.apache.hadoop.classification.InterfaceStability; import org.apache.hadoop.conf.Configuration; @@ -54,6 +56,8 @@ import com.google.protobuf.ServiceException; @InterfaceAudience.Public @InterfaceStability.Stable public abstract class ServerCallable implements Callable { + private static final Log LOG = LogFactory.getLog(ServerCallable.class); + protected final HConnection connection; protected final byte [] tableName; protected final byte [] row; @@ -167,25 +171,14 @@ public abstract class ServerCallable implements Callable { connect(tries != 0); return call(); } catch (Throwable t) { - shouldRetry(t); - t = translateException(t); - if (t instanceof SocketTimeoutException || - t instanceof ConnectException || - t instanceof RetriesExhaustedException) { - // if thrown these exceptions, we clear all the cache entries that - // map to that slow/dead server; otherwise, let cache miss and ask - // .META. again to find the new location - HRegionLocation hrl = location; - if (hrl != null) { - getConnection().clearCaches(hrl.getHostnamePort()); - } - } - RetriesExhaustedException.ThrowableWithExtraContext qt = - new RetriesExhaustedException.ThrowableWithExtraContext(t, - System.currentTimeMillis(), toString()); - exceptions.add(qt); - if (tries == numRetries - 1) { - throw new RetriesExhaustedException(tries, exceptions); + try { + handleFailedAttempt(t, numRetries, tries, exceptions); + } catch (RetriesExhaustedException e) { + throw e; + } catch (RuntimeException e){ + logAndGiveUp(e, tries, exceptions); + } catch (IOException e) { + logAndGiveUp(e, tries, exceptions); } } finally { afterCall(); @@ -194,13 +187,46 @@ public abstract class ServerCallable implements Callable { Thread.sleep(ConnectionUtils.getPauseTime(pause, tries)); } catch (InterruptedException e) { Thread.currentThread().interrupt(); - throw new IOException("Giving up after tries=" + tries, e); + logAndGiveUp(new IOException("Giving up after tries=" + tries, e), tries, exceptions); } } return null; } /** + * Handles unsuccessful attempt to reach a server. + * @param t the reason for the current attempt to fail + * @param numRetries maximal number of retries allowed + * @param tries current try + * @param exceptions exceptions caught in previous attempts + * @throws IOException if a remote or network exception occurs + */ + private void handleFailedAttempt(Throwable t, int numRetries, int tries, + List exceptions) + throws IOException { + shouldRetry(t); + t = translateException(t); + if (t instanceof SocketTimeoutException || + t instanceof ConnectException || + t instanceof RetriesExhaustedException) { + // if thrown these exceptions, we clear all the cache entries that + // map to that slow/dead server; otherwise, let cache miss and ask + // .META. again to find the new location + HRegionLocation hrl = location; + if (hrl != null) { + getConnection().clearCaches(hrl.getHostnamePort()); + } + } + RetriesExhaustedException.ThrowableWithExtraContext qt = + new RetriesExhaustedException.ThrowableWithExtraContext(t, + System.currentTimeMillis(), toString()); + exceptions.add(qt); + if (tries == numRetries - 1) { + throw new RetriesExhaustedException(tries, exceptions); + } + } + + /** * Run this instance against the server once. * @param the type of the return value * @return an object of type T @@ -243,4 +269,19 @@ public abstract class ServerCallable implements Callable { } return t; } + + /** + * Logs previous exceptions caught, and throws the last one. + * @param last last exception caught + * @param tries the current try + * @param exceptions exceptions caught in previous attempts + * @param the type of the last exception + * @throws T throws the last exception caught + */ + private static void logAndGiveUp(T last, int tries, + List exceptions) + throws T { + LOG.info("Giving up.", new RetriesExhaustedException(tries, exceptions)); + throw last; + } }