001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.apache.hadoop.hbase.exceptions;
019
020import java.io.EOFException;
021import java.io.IOException;
022import java.io.SyncFailedException;
023import java.lang.reflect.UndeclaredThrowableException;
024import java.net.ConnectException;
025import java.net.SocketTimeoutException;
026import java.nio.channels.ClosedChannelException;
027import java.util.Set;
028import java.util.concurrent.TimeoutException;
029import org.apache.hadoop.hbase.CallDroppedException;
030import org.apache.hadoop.hbase.CallQueueTooBigException;
031import org.apache.hadoop.hbase.DoNotRetryIOException;
032import org.apache.hadoop.hbase.MultiActionResultTooLarge;
033import org.apache.hadoop.hbase.NotServingRegionException;
034import org.apache.hadoop.hbase.RegionTooBusyException;
035import org.apache.hadoop.hbase.RetryImmediatelyException;
036import org.apache.hadoop.hbase.ipc.CallTimeoutException;
037import org.apache.hadoop.hbase.ipc.FailedServerException;
038import org.apache.hadoop.hbase.quotas.RpcThrottlingException;
039import org.apache.hadoop.ipc.RemoteException;
040import org.apache.yetus.audience.InterfaceAudience;
041import org.apache.yetus.audience.InterfaceStability;
042
043import org.apache.hbase.thirdparty.com.google.common.collect.ImmutableSet;
044
045@InterfaceAudience.Private
046@InterfaceStability.Evolving
047public final class ClientExceptionsUtil {
048
049  private ClientExceptionsUtil() {
050  }
051
052  public static boolean isMetaClearingException(Throwable cur) {
053    cur = findException(cur);
054
055    if (cur == null) {
056      return true;
057    }
058    return !isSpecialException(cur) || (cur instanceof RegionMovedException)
059      || cur instanceof NotServingRegionException;
060  }
061
062  public static boolean isSpecialException(Throwable cur) {
063    return (cur instanceof RegionMovedException || cur instanceof RegionOpeningException
064      || cur instanceof RegionTooBusyException || cur instanceof RpcThrottlingException
065      || cur instanceof MultiActionResultTooLarge || cur instanceof RetryImmediatelyException
066      || cur instanceof CallQueueTooBigException || cur instanceof CallDroppedException
067      || cur instanceof NotServingRegionException || cur instanceof RequestTooBigException);
068  }
069
070  /**
071   * Look for an exception we know in the remote exception: - hadoop.ipc wrapped exceptions - nested
072   * exceptions Looks for: RegionMovedException / RegionOpeningException / RegionTooBusyException /
073   * RpcThrottlingException
074   * @return null if we didn't find the exception, the exception otherwise.
075   */
076  public static Throwable findException(Object exception) {
077    if (exception == null || !(exception instanceof Throwable)) {
078      return null;
079    }
080    Throwable cur = (Throwable) exception;
081    while (cur != null) {
082      if (isSpecialException(cur)) {
083        return cur;
084      }
085      if (cur instanceof RemoteException) {
086        RemoteException re = (RemoteException) cur;
087        cur = re.unwrapRemoteException();
088
089        // unwrapRemoteException can return the exception given as a parameter when it cannot
090        // unwrap it. In this case, there is no need to look further
091        // noinspection ObjectEquality
092        if (cur == re) {
093          return cur;
094        }
095
096        // When we receive RemoteException which wraps IOException which has a cause as
097        // RemoteException we can get into infinite loop here; so if the cause of the exception
098        // is RemoteException, we shouldn't look further.
099      } else if (cur.getCause() != null && !(cur.getCause() instanceof RemoteException)) {
100        cur = cur.getCause();
101      } else {
102        return cur;
103      }
104    }
105
106    return null;
107  }
108
109  // This list covers most connectivity exceptions but not all.
110  // For example, in SocketOutputStream a plain IOException is thrown at times when the channel is
111  // closed.
112  private static final ImmutableSet<Class<? extends Throwable>> CONNECTION_EXCEPTION_TYPES =
113    ImmutableSet.of(SocketTimeoutException.class, ConnectException.class,
114      ClosedChannelException.class, SyncFailedException.class, EOFException.class,
115      TimeoutException.class, TimeoutIOException.class, CallTimeoutException.class,
116      ConnectionClosingException.class, FailedServerException.class,
117      ConnectionClosedException.class);
118
119  /**
120   * For test only. Usually you should use the {@link #isConnectionException(Throwable)} method
121   * below.
122   */
123  public static Set<Class<? extends Throwable>> getConnectionExceptionTypes() {
124    return CONNECTION_EXCEPTION_TYPES;
125  }
126
127  /**
128   * Check if the exception is something that indicates that we cannot contact/communicate with the
129   * server.
130   * @param e exception to check
131   * @return true when exception indicates that the client wasn't able to make contact with server
132   */
133  public static boolean isConnectionException(Throwable e) {
134    if (e == null) {
135      return false;
136    }
137    for (Class<? extends Throwable> clazz : CONNECTION_EXCEPTION_TYPES) {
138      if (clazz.isAssignableFrom(e.getClass())) {
139        return true;
140      }
141    }
142    return false;
143  }
144
145  /**
146   * Translates exception for preemptive fast fail checks.
147   * @param t exception to check
148   * @return translated exception n
149   */
150  public static Throwable translatePFFE(Throwable t) throws IOException {
151    if (t instanceof NoSuchMethodError) {
152      // We probably can't recover from this exception by retrying.
153      throw (NoSuchMethodError) t;
154    }
155
156    if (t instanceof NullPointerException) {
157      // The same here. This is probably a bug.
158      throw (NullPointerException) t;
159    }
160
161    if (t instanceof UndeclaredThrowableException) {
162      t = t.getCause();
163    }
164    if (t instanceof RemoteException) {
165      t = ((RemoteException) t).unwrapRemoteException();
166    }
167    if (t instanceof DoNotRetryIOException) {
168      throw (DoNotRetryIOException) t;
169    }
170    if (t instanceof Error) {
171      throw (Error) t;
172    }
173    return t;
174  }
175}