Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -133,9 +133,12 @@ public final class S3AUtils {
S3AEncryptionMethods.SSE_S3.getMethod()
+ " is enabled but an encryption key was set in "
+ SERVER_SIDE_ENCRYPTION_KEY;
private static final String EOF_MESSAGE_IN_XML_PARSER
public static final String EOF_MESSAGE_IN_XML_PARSER
= "Failed to sanitize XML document destined for handler class";

public static final String EOF_READ_DIFFERENT_LENGTH
= "Data read has a different length than the expected";

private static final String BUCKET_PATTERN = FS_S3A_BUCKET_PREFIX + "%s.%s";

/**
Expand Down Expand Up @@ -195,7 +198,7 @@ public static IOException translateException(@Nullable String operation,
// interrupted IO, or a socket exception underneath that class
return translateInterruptedException(exception, innerCause, message);
}
if (signifiesConnectionBroken(exception)) {
if (isMessageTranslatableToEOF(exception)) {
// call considered an sign of connectivity failure
return (EOFException)new EOFException(message).initCause(exception);
}
Expand Down Expand Up @@ -415,13 +418,14 @@ public static boolean isThrottleException(Exception ex) {

/**
* Cue that an AWS exception is likely to be an EOF Exception based
* on the message coming back from an XML/JSON parser. This is likely
* to be brittle, so only a hint.
* on the message coming back from the client. This is likely to be
* brittle, so only a hint.
* @param ex exception
* @return true if this is believed to be a sign the connection was broken.
*/
public static boolean signifiesConnectionBroken(SdkBaseException ex) {
return ex.toString().contains(EOF_MESSAGE_IN_XML_PARSER);
public static boolean isMessageTranslatableToEOF(SdkBaseException ex) {
return ex.toString().contains(EOF_MESSAGE_IN_XML_PARSER) ||
ex.toString().contains(EOF_READ_DIFFERENT_LENGTH);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

package org.apache.hadoop.fs.s3a;

import java.io.EOFException;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.net.SocketTimeoutException;
Expand All @@ -28,6 +29,7 @@
import com.amazonaws.AmazonClientException;
import com.amazonaws.AmazonServiceException;
import com.amazonaws.SdkBaseException;
import com.amazonaws.SdkClientException;
import com.amazonaws.services.dynamodbv2.model.ProvisionedThroughputExceededException;
import com.amazonaws.services.s3.model.AmazonS3Exception;
import org.junit.Assert;
Expand Down Expand Up @@ -163,6 +165,40 @@ public void test500isStatus500Exception() throws Exception {
ex);
}

@Test
public void testExceptionsWithTranslatableMessage() throws Exception {
SdkBaseException xmlParsing = new SdkBaseException(EOF_MESSAGE_IN_XML_PARSER);
SdkBaseException differentLength = new SdkBaseException(EOF_READ_DIFFERENT_LENGTH);

verifyTranslated(EOFException.class, xmlParsing);
verifyTranslated(EOFException.class, differentLength);
}


@Test
public void testSdkDifferentLengthExceptionIsTranslatable() throws Throwable {
final AtomicInteger counter = new AtomicInteger(0);
invoker.retry("test", null, false, () -> {
if (counter.incrementAndGet() < ACTIVE_RETRY_LIMIT) {
throw new SdkClientException(EOF_READ_DIFFERENT_LENGTH);
}
});

assertEquals(ACTIVE_RETRY_LIMIT, counter.get());
}

@Test
public void testSdkXmlParsingExceptionIsTranslatable() throws Throwable {
final AtomicInteger counter = new AtomicInteger(0);
invoker.retry("test", null, false, () -> {
if (counter.incrementAndGet() < ACTIVE_RETRY_LIMIT) {
throw new SdkClientException(EOF_MESSAGE_IN_XML_PARSER);
}
});

assertEquals(ACTIVE_RETRY_LIMIT, counter.get());
}

@Test(expected = org.apache.hadoop.net.ConnectTimeoutException.class)
public void testExtractConnectTimeoutException() throws Throwable {
throw extractException("", "",
Expand Down