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