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