HADOOP-7928. HA: Client failover policy is incorrectly trying to fail over all IOExceptions. Contributed by Aaron T. Myers.

git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/branches/HDFS-1623@1215019 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Aaron Myers 2011-12-16 01:54:44 +00:00
parent 353bc3799d
commit 116bf57bd6
4 changed files with 52 additions and 41 deletions

View File

@ -15,3 +15,6 @@ HADOOP-7922. Improve some logging for client IPC failovers and
StandbyExceptions (todd) StandbyExceptions (todd)
HADOOP-7921. StandbyException should extend IOException (todd) HADOOP-7921. StandbyException should extend IOException (todd)
HADOOP-7928. HA: Client failover policy is incorrectly trying to fail over all
IOExceptions (atm)

View File

@ -341,7 +341,7 @@ public RetryAction shouldRetry(Exception e, int retries,
failovers == 0 ? 0 : failovers == 0 ? 0 :
calculateExponentialTime(delayMillis, failovers, maxDelayBase)); calculateExponentialTime(delayMillis, failovers, maxDelayBase));
} else if (e instanceof SocketException || } else if (e instanceof SocketException ||
e instanceof IOException) { (e instanceof IOException && !(e instanceof RemoteException))) {
if (isMethodIdempotent) { if (isMethodIdempotent) {
return RetryAction.FAILOVER_AND_RETRY; return RetryAction.FAILOVER_AND_RETRY;
} else { } else {

View File

@ -181,7 +181,7 @@ public void testFailoverOnNetworkExceptionIdempotentOperation()
assertEquals("impl1", unreliable.succeedsOnceThenFailsReturningString()); assertEquals("impl1", unreliable.succeedsOnceThenFailsReturningString());
try { try {
assertEquals("impl2", unreliable.succeedsOnceThenFailsReturningString()); unreliable.succeedsOnceThenFailsReturningString();
fail("should not have succeeded twice"); fail("should not have succeeded twice");
} catch (IOException e) { } catch (IOException e) {
// Make sure we *don't* fail over since the first implementation threw an // Make sure we *don't* fail over since the first implementation threw an
@ -304,4 +304,26 @@ public void run() {
String result = unreliable.failsIfIdentifierDoesntMatch("renamed-impl1"); String result = unreliable.failsIfIdentifierDoesntMatch("renamed-impl1");
assertEquals("renamed-impl1", result); assertEquals("renamed-impl1", result);
} }
/**
* Ensure that normal IO exceptions don't result in a failover.
*/
@Test
public void testExpectedIOException() {
UnreliableInterface unreliable = (UnreliableInterface)RetryProxy
.create(UnreliableInterface.class,
new FlipFlopProxyProvider(UnreliableInterface.class,
new UnreliableImplementation("impl1", TypeOfExceptionToFailWith.REMOTE_EXCEPTION),
new UnreliableImplementation("impl2", TypeOfExceptionToFailWith.UNRELIABLE_EXCEPTION)),
RetryPolicies.failoverOnNetworkException(
RetryPolicies.TRY_ONCE_THEN_FAIL, 10, 1000, 10000));
try {
unreliable.failsIfIdentifierDoesntMatch("no-such-identifier");
fail("Should have thrown *some* exception");
} catch (Exception e) {
assertTrue("Expected IOE but got " + e.getClass(),
e instanceof IOException);
}
}
} }

View File

@ -19,6 +19,7 @@
import java.io.IOException; import java.io.IOException;
import org.apache.hadoop.io.retry.UnreliableInterface.UnreliableException;
import org.apache.hadoop.ipc.RemoteException; import org.apache.hadoop.ipc.RemoteException;
import org.apache.hadoop.ipc.StandbyException; import org.apache.hadoop.ipc.StandbyException;
@ -37,7 +38,8 @@ public class UnreliableImplementation implements UnreliableInterface {
public static enum TypeOfExceptionToFailWith { public static enum TypeOfExceptionToFailWith {
UNRELIABLE_EXCEPTION, UNRELIABLE_EXCEPTION,
STANDBY_EXCEPTION, STANDBY_EXCEPTION,
IO_EXCEPTION IO_EXCEPTION,
REMOTE_EXCEPTION
} }
public UnreliableImplementation() { public UnreliableImplementation() {
@ -95,14 +97,7 @@ public String succeedsOnceThenFailsReturningString()
if (succeedsOnceThenFailsCount++ < 1) { if (succeedsOnceThenFailsCount++ < 1) {
return identifier; return identifier;
} else { } else {
switch (exceptionToFailWith) { throwAppropriateException(exceptionToFailWith, identifier);
case STANDBY_EXCEPTION:
throw new StandbyException(identifier);
case UNRELIABLE_EXCEPTION:
throw new UnreliableException(identifier);
case IO_EXCEPTION:
throw new IOException(identifier);
}
return null; return null;
} }
} }
@ -113,16 +108,8 @@ public String succeedsTenTimesThenFailsReturningString()
if (succeedsTenTimesThenFailsCount++ < 10) { if (succeedsTenTimesThenFailsCount++ < 10) {
return identifier; return identifier;
} else { } else {
switch (exceptionToFailWith) { throwAppropriateException(exceptionToFailWith, identifier);
case STANDBY_EXCEPTION: return null;
throw new StandbyException(identifier);
case UNRELIABLE_EXCEPTION:
throw new UnreliableException(identifier);
case IO_EXCEPTION:
throw new IOException(identifier);
default:
throw new RuntimeException(identifier);
}
} }
} }
@ -132,16 +119,8 @@ public String succeedsOnceThenFailsReturningStringIdempotent()
if (succeedsOnceThenFailsIdempotentCount++ < 1) { if (succeedsOnceThenFailsIdempotentCount++ < 1) {
return identifier; return identifier;
} else { } else {
switch (exceptionToFailWith) { throwAppropriateException(exceptionToFailWith, identifier);
case STANDBY_EXCEPTION: return null;
throw new StandbyException(identifier);
case UNRELIABLE_EXCEPTION:
throw new UnreliableException(identifier);
case IO_EXCEPTION:
throw new IOException(identifier);
default:
throw new RuntimeException(identifier);
}
} }
} }
@ -153,17 +132,24 @@ public String failsIfIdentifierDoesntMatch(String identifier)
} else { } else {
String message = "expected '" + this.identifier + "' but received '" + String message = "expected '" + this.identifier + "' but received '" +
identifier + "'"; identifier + "'";
switch (exceptionToFailWith) { throwAppropriateException(exceptionToFailWith, message);
case STANDBY_EXCEPTION: return null;
throw new StandbyException(message);
case UNRELIABLE_EXCEPTION:
throw new UnreliableException(message);
case IO_EXCEPTION:
throw new IOException(message);
default:
throw new RuntimeException(message);
}
} }
} }
private static void throwAppropriateException(TypeOfExceptionToFailWith eType,
String message) throws UnreliableException, StandbyException, IOException {
switch (eType) {
case STANDBY_EXCEPTION:
throw new StandbyException(message);
case UNRELIABLE_EXCEPTION:
throw new UnreliableException(message);
case IO_EXCEPTION:
throw new IOException(message);
case REMOTE_EXCEPTION:
throw new RemoteException(IOException.class.getName(), message);
default:
throw new RuntimeException(message);
}
}
} }