HADOOP-16580. Disable retry of FailoverOnNetworkExceptionRetry in case of AccessControlException. Contributed by Adam Antal

(cherry picked from commit c79a5f2d99)
(cherry picked from commit 0bbd48c7a8)
This commit is contained in:
Szilard Nemeth 2019-10-16 13:29:06 +02:00
parent a70c6e9665
commit f8c06f5a87
4 changed files with 66 additions and 0 deletions

View File

@ -38,6 +38,7 @@ import org.apache.hadoop.ipc.RemoteException;
import org.apache.hadoop.ipc.RetriableException; import org.apache.hadoop.ipc.RetriableException;
import org.apache.hadoop.ipc.StandbyException; import org.apache.hadoop.ipc.StandbyException;
import org.apache.hadoop.net.ConnectTimeoutException; import org.apache.hadoop.net.ConnectTimeoutException;
import org.apache.hadoop.security.AccessControlException;
import org.apache.hadoop.security.token.SecretManager.InvalidToken; import org.apache.hadoop.security.token.SecretManager.InvalidToken;
import org.ietf.jgss.GSSException; import org.ietf.jgss.GSSException;
@ -688,6 +689,9 @@ public class RetryPolicies {
} else if (e instanceof InvalidToken) { } else if (e instanceof InvalidToken) {
return new RetryAction(RetryAction.RetryDecision.FAIL, 0, return new RetryAction(RetryAction.RetryDecision.FAIL, 0,
"Invalid or Cancelled Token"); "Invalid or Cancelled Token");
} else if (e instanceof AccessControlException) {
return new RetryAction(RetryAction.RetryDecision.FAIL, 0,
"Access denied");
} else if (e instanceof SocketException } else if (e instanceof SocketException
|| (e instanceof IOException && !(e instanceof RemoteException))) { || (e instanceof IOException && !(e instanceof RemoteException))) {
if (isIdempotentOrAtMostOnce) { if (isIdempotentOrAtMostOnce) {

View File

@ -25,6 +25,7 @@ import org.apache.hadoop.io.retry.UnreliableInterface.FatalException;
import org.apache.hadoop.io.retry.UnreliableInterface.UnreliableException; import org.apache.hadoop.io.retry.UnreliableInterface.UnreliableException;
import org.apache.hadoop.ipc.ProtocolTranslator; import org.apache.hadoop.ipc.ProtocolTranslator;
import org.apache.hadoop.ipc.RemoteException; import org.apache.hadoop.ipc.RemoteException;
import org.apache.hadoop.security.AccessControlException;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.mockito.invocation.InvocationOnMock; import org.mockito.invocation.InvocationOnMock;
@ -48,6 +49,14 @@ import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.anyInt;
import static org.mockito.Mockito.*; import static org.mockito.Mockito.*;
/**
* TestRetryProxy tests the behaviour of the {@link RetryPolicy} class using
* a certain method of {@link UnreliableInterface} implemented by
* {@link UnreliableImplementation}.
*
* Some methods may be sensitive to the {@link Idempotent} annotation
* (annotated in {@link UnreliableInterface}).
*/
public class TestRetryProxy { public class TestRetryProxy {
private UnreliableImplementation unreliableImpl; private UnreliableImplementation unreliableImpl;
@ -348,4 +357,24 @@ public class TestRetryProxy {
assertEquals(RetryDecision.FAIL, caughtRetryAction.action); assertEquals(RetryDecision.FAIL, caughtRetryAction.action);
} }
} }
@Test
public void testNoRetryOnAccessControlException() throws Exception {
RetryPolicy policy = mock(RetryPolicy.class);
RetryPolicy realPolicy = RetryPolicies.failoverOnNetworkException(5);
setupMockPolicy(policy, realPolicy);
UnreliableInterface unreliable = (UnreliableInterface) RetryProxy.create(
UnreliableInterface.class, unreliableImpl, policy);
try {
unreliable.failsWithAccessControlExceptionEightTimes();
fail("Should fail");
} catch (AccessControlException e) {
// expected
verify(policy, times(1)).shouldRetry(any(Exception.class), anyInt(),
anyInt(), anyBoolean());
assertEquals(RetryDecision.FAIL, caughtRetryAction.action);
}
}
} }

View File

@ -23,7 +23,14 @@ import javax.security.sasl.SaslException;
import org.apache.hadoop.ipc.RemoteException; import org.apache.hadoop.ipc.RemoteException;
import org.apache.hadoop.ipc.StandbyException; import org.apache.hadoop.ipc.StandbyException;
import org.apache.hadoop.security.AccessControlException;
/**
* For the usage and purpose of this class see {@link UnreliableInterface}
* which this class implements.
*
* @see UnreliableInterface
*/
class UnreliableImplementation implements UnreliableInterface { class UnreliableImplementation implements UnreliableInterface {
private int failsOnceInvocationCount, private int failsOnceInvocationCount,
@ -32,6 +39,7 @@ class UnreliableImplementation implements UnreliableInterface {
failsOnceRemoteExceptionInvocationCount, failsOnceRemoteExceptionInvocationCount,
failsTenTimesInvocationCount, failsTenTimesInvocationCount,
failsWithSASLExceptionTenTimesInvocationCount, failsWithSASLExceptionTenTimesInvocationCount,
failsWithAccessControlExceptionInvocationCount,
succeedsOnceThenFailsCount, succeedsOnceThenFailsCount,
succeedsOnceThenFailsIdempotentCount, succeedsOnceThenFailsIdempotentCount,
succeedsTenTimesThenFailsCount; succeedsTenTimesThenFailsCount;
@ -123,6 +131,14 @@ class UnreliableImplementation implements UnreliableInterface {
} }
} }
@Override
public void failsWithAccessControlExceptionEightTimes()
throws AccessControlException {
if (failsWithAccessControlExceptionInvocationCount++ < 8) {
throw new AccessControlException();
}
}
@Override @Override
public String succeedsOnceThenFailsReturningString() public String succeedsOnceThenFailsReturningString()
throws UnreliableException, IOException, StandbyException { throws UnreliableException, IOException, StandbyException {

View File

@ -24,7 +24,20 @@ import javax.security.sasl.SaslException;
import org.apache.hadoop.ipc.RemoteException; import org.apache.hadoop.ipc.RemoteException;
import org.apache.hadoop.ipc.StandbyException; import org.apache.hadoop.ipc.StandbyException;
import org.apache.hadoop.security.AccessControlException;
/**
* The methods of UnreliableInterface could throw exceptions in a
* predefined way. It is currently used for testing {@link RetryPolicy}
* and {@link FailoverProxyProvider} classes, but can be potentially used
* to test any class's behaviour where an underlying interface or class
* may throw exceptions.
*
* Some methods may be annotated with the {@link Idempotent} annotation.
* In order to test those some methods of UnreliableInterface are annotated,
* but they are not actually Idempotent functions.
*
*/
public interface UnreliableInterface { public interface UnreliableInterface {
public static class UnreliableException extends Exception { public static class UnreliableException extends Exception {
@ -66,6 +79,10 @@ public interface UnreliableInterface {
void failsWithSASLExceptionTenTimes() throws SaslException; void failsWithSASLExceptionTenTimes() throws SaslException;
@Idempotent
void failsWithAccessControlExceptionEightTimes()
throws AccessControlException;
public String succeedsOnceThenFailsReturningString() public String succeedsOnceThenFailsReturningString()
throws UnreliableException, StandbyException, IOException; throws UnreliableException, StandbyException, IOException;
@Idempotent @Idempotent