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.Set; 030import java.util.concurrent.TimeoutException; 031 032import org.apache.hadoop.hbase.CallDroppedException; 033import org.apache.hadoop.hbase.CallQueueTooBigException; 034import org.apache.hadoop.hbase.DoNotRetryIOException; 035import org.apache.hadoop.hbase.MultiActionResultTooLarge; 036import org.apache.hadoop.hbase.NotServingRegionException; 037import org.apache.hadoop.hbase.RegionTooBusyException; 038import org.apache.hadoop.hbase.RetryImmediatelyException; 039import org.apache.yetus.audience.InterfaceAudience; 040import org.apache.yetus.audience.InterfaceStability; 041 042import org.apache.hbase.thirdparty.com.google.common.annotations.VisibleForTesting; 043import org.apache.hbase.thirdparty.com.google.common.collect.ImmutableSet; 044 045import org.apache.hadoop.hbase.ipc.CallTimeoutException; 046import org.apache.hadoop.hbase.ipc.FailedServerException; 047import org.apache.hadoop.hbase.quotas.RpcThrottlingException; 048import org.apache.hadoop.ipc.RemoteException; 049 050@InterfaceAudience.Private 051@InterfaceStability.Evolving 052public final class ClientExceptionsUtil { 053 054 private ClientExceptionsUtil() {} 055 056 public static boolean isMetaClearingException(Throwable cur) { 057 cur = findException(cur); 058 059 if (cur == null) { 060 return true; 061 } 062 return !isSpecialException(cur) || (cur instanceof RegionMovedException) 063 || cur instanceof NotServingRegionException; 064 } 065 066 public static boolean isSpecialException(Throwable cur) { 067 return (cur instanceof RegionMovedException || cur instanceof RegionOpeningException 068 || cur instanceof RegionTooBusyException || cur instanceof RpcThrottlingException 069 || cur instanceof MultiActionResultTooLarge || cur instanceof RetryImmediatelyException 070 || cur instanceof CallQueueTooBigException || cur instanceof CallDroppedException 071 || cur instanceof NotServingRegionException || cur instanceof RequestTooBigException); 072 } 073 074 075 /** 076 * Look for an exception we know in the remote exception: 077 * - hadoop.ipc wrapped exceptions 078 * - nested exceptions 079 * 080 * Looks for: RegionMovedException / RegionOpeningException / RegionTooBusyException / 081 * RpcThrottlingException 082 * @return null if we didn't find the exception, the exception otherwise. 083 */ 084 public static Throwable findException(Object exception) { 085 if (exception == null || !(exception instanceof Throwable)) { 086 return null; 087 } 088 Throwable cur = (Throwable) exception; 089 while (cur != null) { 090 if (isSpecialException(cur)) { 091 return cur; 092 } 093 if (cur instanceof RemoteException) { 094 RemoteException re = (RemoteException) cur; 095 cur = re.unwrapRemoteException(); 096 097 // unwrapRemoteException can return the exception given as a parameter when it cannot 098 // unwrap it. In this case, there is no need to look further 099 // noinspection ObjectEquality 100 if (cur == re) { 101 return cur; 102 } 103 104 // When we receive RemoteException which wraps IOException which has a cause as 105 // RemoteException we can get into infinite loop here; so if the cause of the exception 106 // is RemoteException, we shouldn't look further. 107 } else if (cur.getCause() != null && !(cur.getCause() instanceof RemoteException)) { 108 cur = cur.getCause(); 109 } else { 110 return cur; 111 } 112 } 113 114 return null; 115 } 116 117 /** 118 * Checks if the exception is CallQueueTooBig exception (maybe wrapped 119 * into some RemoteException). 120 * @param t exception to check 121 * @return true if it's a CQTBE, false otherwise 122 */ 123 public static boolean isCallQueueTooBigException(Throwable t) { 124 t = findException(t); 125 return (t instanceof CallQueueTooBigException); 126 } 127 128 /** 129 * Checks if the exception is CallDroppedException (maybe wrapped 130 * into some RemoteException). 131 * @param t exception to check 132 * @return true if it's a CQTBE, false otherwise 133 */ 134 public static boolean isCallDroppedException(Throwable t) { 135 t = findException(t); 136 return (t instanceof CallDroppedException); 137 } 138 139 // This list covers most connectivity exceptions but not all. 140 // For example, in SocketOutputStream a plain IOException is thrown at times when the channel is 141 // closed. 142 private static final ImmutableSet<Class<? extends Throwable>> CONNECTION_EXCEPTION_TYPES = 143 ImmutableSet.of(SocketTimeoutException.class, ConnectException.class, 144 ClosedChannelException.class, SyncFailedException.class, EOFException.class, 145 TimeoutException.class, TimeoutIOException.class, CallTimeoutException.class, 146 ConnectionClosingException.class, FailedServerException.class, 147 ConnectionClosedException.class); 148 149 /** 150 * For test only. Usually you should use the {@link #isConnectionException(Throwable)} method 151 * below. 152 */ 153 @VisibleForTesting 154 public static Set<Class<? extends Throwable>> getConnectionExceptionTypes() { 155 return CONNECTION_EXCEPTION_TYPES; 156 } 157 158 /** 159 * Check if the exception is something that indicates that we cannot contact/communicate with the 160 * server. 161 * @param e exception to check 162 * @return true when exception indicates that the client wasn't able to make contact with server 163 */ 164 public static boolean isConnectionException(Throwable e) { 165 if (e == null) { 166 return false; 167 } 168 for (Class<? extends Throwable> clazz : CONNECTION_EXCEPTION_TYPES) { 169 if (clazz.isAssignableFrom(e.getClass())) { 170 return true; 171 } 172 } 173 return false; 174 } 175 176 /** 177 * Translates exception for preemptive fast fail checks. 178 * @param t exception to check 179 * @return translated exception 180 * @throws IOException 181 */ 182 public static Throwable translatePFFE(Throwable t) throws IOException { 183 if (t instanceof NoSuchMethodError) { 184 // We probably can't recover from this exception by retrying. 185 throw (NoSuchMethodError) t; 186 } 187 188 if (t instanceof NullPointerException) { 189 // The same here. This is probably a bug. 190 throw (NullPointerException) t; 191 } 192 193 if (t instanceof UndeclaredThrowableException) { 194 t = t.getCause(); 195 } 196 if (t instanceof RemoteException) { 197 t = ((RemoteException) t).unwrapRemoteException(); 198 } 199 if (t instanceof DoNotRetryIOException) { 200 throw (DoNotRetryIOException) t; 201 } 202 if (t instanceof Error) { 203 throw (Error) t; 204 } 205 return t; 206 } 207}