Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Netty async stability fixes #173

Merged
merged 4 commits into from
Sep 26, 2017
Merged

Netty async stability fixes #173

merged 4 commits into from
Sep 26, 2017

Conversation

dagnir
Copy link
Contributor

@dagnir dagnir commented Sep 21, 2017

  • Fix data corruption bug in streaming responses
  • Fix failure to signal the SdkResponseHandler in situations where remote end of the TCP connection is unexpectedly closed by the service

Builds on @shorea's work here: https://github.com/aws/aws-sdk-java-v2/tree/shorea-dongie-perf-share

Fixes #146

shorea and others added 2 commits September 20, 2017 16:00
- Prevent possible use-after-free bug for Streaming responses

- Account for half closed connection (closed by remote) and signal back
  to SdkResponseHandler asn an IOException

Fixes aws#146
Copy link
Contributor

@shorea shorea left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!

@@ -60,6 +60,14 @@

<!--Reactive Dependencies-->
<dependency>
<groupId>io.netty</groupId>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can probably remove this. Was testing the perf of native SSL.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed

@@ -143,7 +145,7 @@ private static int port(URI uri) {

private SslContext sslContext(String scheme) {
if (scheme.equalsIgnoreCase("https")) {
SslContextBuilder builder = SslContextBuilder.forClient().sslProvider(defaultClientProvider());
SslContextBuilder builder = SslContextBuilder.forClient().sslProvider(SslProvider.JDK);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This you can revert for now.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reverted

ctx.channel().close()
.addListener(channelFuture -> requestContext.channelPool().release(ctx.channel()));
private static void removePerRequestHandlers(ChannelHandlerContext ctx) {
removePerRequestHandlers(ctx, HttpStreamsClientHandler.class, ReadTimeoutHandler.class, WriteTimeoutHandler.class);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can get rid of this and remove them before the request starts.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 looks like we were already doing that; removed

ByteBuf fullContent = ((FullHttpResponse) msg).content();
final ByteBuffer bb = copyToByteBuffer(fullContent);
fullContent.release();
requestContext.handler().onStream(new FullResponseContentPublisher(channelContext, bb));
}

if (msg instanceof LastHttpContent) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you remove the removePerRequsetHandlers method I think you can combine this with the FullHttpResponse branch.

}
}

@Override
public void abort() {
if (channel != null) {
channel.disconnect().addListener(ignored -> context.channelPool().release(channel));
channel.close().addListener(ignored -> context.channelPool().release(channel));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a closeAndRelease method would be good here too.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refactored into closeAndRelease

Copy link
Contributor

@spfink spfink left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any helpful comments we could add to the SPI based on the changes you had to make here?

bundle/pom.xml Outdated
@@ -54,6 +54,10 @@
<configuration>
<artifactSet>
<includes>
<include>joda-time:joda-time</include>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where are we still using joda?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch! Removed

}
} catch (Exception e) {
subscriber.onError(e);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment or logging here?

}
}

private void close() {
// Completion handled by response handler
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No longer true?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like this got left it while I was resolving some merge conflicts

.statusCode(response.status().code())
.statusText(response.status().reasonPhrase())
.build();
.headers(fromNettyHeaders(response.headers()))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh man, are we fixed or aligned?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Haha, realigned this.

ByteBuf fullContent = ((FullHttpResponse) msg).content();
final ByteBuffer bb = copyToByteBuffer(fullContent);
fullContent.release();
requestContext.handler().onStream(new FullResponseContentPublisher(channelContext, bb));
Subscriber<? super ByteBuffer> subscriber = channelContext.channel().attr(ChannelAttributeKeys.SUBSCRIBER_KEY).get();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we still need to stick the subscriber in an attribute if we complete on the same message?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah since the FullResponseContentPublisher is the one that sets the subscriber in the ChannelContext

public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
RequestContext requestContext = ctx.channel().attr(REQUEST_CONTEXT_KEY).get();
log.error("Exception processing request: {}", requestContext.sdkRequest(), cause);
runAndLogError("SdkHttpResponseHandler threw an exception",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we mark complete here too?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

requestContext.handler().complete();
} finally {
finalizeRequest(requestContext, channelContext);
// Run in the event loop to avoid sync issues in finalizeRequest
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should be guaranteed to be running on the channel thread.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Double checked this and looks like HttpStreamsClientHandler does guarantee this. Thanks for pointing it out!

Copy link
Contributor

@shorea shorea left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! Nice work!


// TODO make these configurable
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you modify this TODO to only add the write here, remove it when we finished writing, add the read then, then remove read when the request if finished?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 done.

@dagnir dagnir merged commit f4d3685 into aws:master Sep 26, 2017
This was referenced Oct 17, 2017
Closed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

S3 client corrupts downloaded files
3 participants