Skip to content

[SPARK-6578] [core] Fix thread-safety issue in outbound path of network library. #5234

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

Closed
wants to merge 9 commits into from

Conversation

vanzin
Copy link
Contributor

@vanzin vanzin commented Mar 27, 2015

While the inbound path of a netty pipeline is thread-safe, the outbound
path is not. That means that multiple threads can compete to write messages
to the next stage of the pipeline.

The network library sometimes breaks a single RPC message into multiple
buffers internally to avoid copying data (see MessageEncoder). This can
result in the following scenario (where "FxBy" means "frame x, buffer y"):

           T1         F1B1            F1B2
                        \               \
                         \               \
           socket        F1B1   F2B1    F1B2  F2B2
                                 /             /
                                /             /
           T2                  F2B1         F2B2

And the frames now cannot be rebuilt on the receiving side because the
different messages have been mixed up on the wire.

The fix wraps these multi-buffer messages into a FileRegion object
so that these messages are written "atomically" to the next pipeline handler.

While the inbound path of a netty pipeline is thread-safe, the outbound
path is not. That means that multiple threads can compete to write messages
to the next stage of the pipeline.

The network library sometimes breaks a single RPC message into multiple
buffers internally to avoid copying data (see MessageEncoder). This can
result in the following scenario (where "FxBy" means "frame x, buffer y"):

               T1         F1B1            F1B2
                            \               \
                             \               \
               socket        F1B1   F2B1    F1B2  F2B2
                                     /             /
                                    /             /
               T2                  F2B1         F2B2

And the frames now cannot be rebuilt on the receiving side because the
different messages have been mixed up on the wire.

The fix introduces a new stage in the pipeline that acts as a "demultiplexer":
multi-buffer frames are expected to navigate the pipeline as a List, and the
new handler will write all buffers in the List to the next stage in a
thread-safe manner.
@vanzin vanzin changed the title Fix thread-safety issue in outbound path of network library. [SPARK-6578] [core] Fix thread-safety issue in outbound path of network library. Mar 27, 2015
@SparkQA
Copy link

SparkQA commented Mar 27, 2015

Test build #29321 has started for PR 5234 at commit 8d70e60.

  • This patch merges cleanly.

@vanzin
Copy link
Contributor Author

vanzin commented Mar 27, 2015

/cc @rxin @aarondav

@SparkQA
Copy link

SparkQA commented Mar 27, 2015

Test build #29323 has started for PR 5234 at commit 432f3bd.

  • This patch merges cleanly.

It's been too long since the electronics class in college, I guess.
@SparkQA
Copy link

SparkQA commented Mar 27, 2015

Test build #29324 has started for PR 5234 at commit 84aa7ce.

  • This patch merges cleanly.

@SparkQA
Copy link

SparkQA commented Mar 27, 2015

Test build #29321 has finished for PR 5234 at commit 8d70e60.

  • This patch passes all tests.
  • This patch merges cleanly.
  • This patch adds the following public classes (experimental):
    • public final class MessageDemux extends ChannelOutboundHandlerAdapter

@AmplabJenkins
Copy link

Test PASSed.
Refer to this link for build results (access rights to CI server needed):
https://amplab.cs.berkeley.edu/jenkins//job/SparkPullRequestBuilder/29321/
Test PASSed.

@SparkQA
Copy link

SparkQA commented Mar 27, 2015

Test build #29323 has finished for PR 5234 at commit 432f3bd.

  • This patch passes all tests.
  • This patch merges cleanly.
  • This patch adds the following public classes (experimental):
    • public final class MessageDemux extends ChannelOutboundHandlerAdapter

@AmplabJenkins
Copy link

Test PASSed.
Refer to this link for build results (access rights to CI server needed):
https://amplab.cs.berkeley.edu/jenkins//job/SparkPullRequestBuilder/29323/
Test PASSed.

@SparkQA
Copy link

SparkQA commented Mar 27, 2015

Test build #29324 has finished for PR 5234 at commit 84aa7ce.

  • This patch passes all tests.
  • This patch merges cleanly.
  • This patch adds the following public classes (experimental):
    • public final class MessageMuxer extends ChannelOutboundHandlerAdapter

@AmplabJenkins
Copy link

Test PASSed.
Refer to this link for build results (access rights to CI server needed):
https://amplab.cs.berkeley.edu/jenkins//job/SparkPullRequestBuilder/29324/
Test PASSed.

@vanzin
Copy link
Contributor Author

vanzin commented Mar 28, 2015

BTW, if anyone cares to look at it, I wrote some code that shows the race exists; you can see it here. I didn't post it as part of the PR because it's a contrived test that doesn't really test the network library, but is just meant to show what happened when the bug was actually triggered before.

@rxin
Copy link
Contributor

rxin commented Mar 28, 2015

This seems to me a pretty serious problem with our current implementation and a limitation from Netty w.r.t. the use of zero-copy.

If I am understanding this correctly, the problem is that Netty Channel cannot accept a composite buffer that includes a ByteBuf and a FileRegion at the same time. As a result, we separated a data transfer message into two messages: one for header, and one for data itself using transferTo.

Netty already went most of the way to make sure users don't have to worry about linearizability and concurrency, but in this case we'd have to resort to locking in order to guarantee atomicity of a message that gets divided into two.

If Netty can have some support structure for this, it'd greatly simplify our programming model and eliminate the locking required at our level. Looks like an extra if statement that checks whether the "msg" is a special object that contain a ByteBuf and a FileRegion: https://github.com/netty/netty/blob/33f75d374091946058fc334c3cdbcd0f0a59d9b3/transport/src/main/java/io/netty/channel/nio/AbstractNioByteChannel.java#L189

cc @normanmaurer and @trustin any comment on this?

@rxin
Copy link
Contributor

rxin commented Mar 28, 2015

@varzin any idea on the performance impact of this patch?

@vanzin
Copy link
Contributor Author

vanzin commented Mar 28, 2015

Adding a lock is always a little bit scary, but I wouldn't expect a lot of overhead from this code, given that netty itself has to do context switching to actually write the data to the socket. An easy optimization would be to avoid the lock when the input list has a single element, since in that case we don't care about the ordering.

One question I have is: does netty have some interface/method that I can implement to make any object directly writable to a socket? e.g. the transferTo method you mention; can I just implement that and netty will handle it? I couldn't find anything in the javadocs.

If there is something like that, then we can avoid the lock by wrapping the two messages created by ChunkFetchSuccess in an object that implements that interface. Still zero copy, and just requires allocating one extra small object.

@normanmaurer
Copy link
Contributor

You can implement FileRegion

Am 28.03.2015 um 04:42 schrieb Marcelo Vanzin [email protected]:

Adding a lock is always a little bit scary, but I wouldn't expect a lot of overhead from this code, given that netty itself has to do context switching to actually write the data to the socket. An easy optimization would be to avoid the lock when the input list has a single element, since in that case we don't care about the ordering.

One question I have is: does netty have some interface/method that I can implement to make any object directly writable to a socket? e.g. the transferTo method you mention; can I just implement that and netty will handle it? I couldn't find anything in the javadocs.

If there is something like that, then we can avoid the lock by wrapping the two messages created by ChunkFetchSuccess in an object that implements that interface. Still zero copy, and just requires allocating one extra small object.


Reply to this email directly or view it on GitHub.

@rxin
Copy link
Contributor

rxin commented Mar 28, 2015

Ah that makes sense. We can just add the header to our own LazyFileRegion. It won't work with the native epoll transport, but should be fine for nio since it is the default anyway.

@rxin
Copy link
Contributor

rxin commented Mar 30, 2015

@vanzin do you have time to do the fix suggested by @normanmaurer? If you do, I can review it tonight and merge it. If you don't, Aaron or I will probably find time to fix it tomorrow.

The idea is to add a header ByteBuf to LazyFileRegion, and in transferTo transfer both the header and the body. Then MessageEncoder can return either a single ByteBuf or a single LazyFileRegion.

@vanzin
Copy link
Contributor Author

vanzin commented Mar 30, 2015

Yeah, I hope to take a look at this after lunch.

Netty treats FileRegion by calling its "transferTo" method to
copy data to the destination. We can use this to wrap the whole
outgoing message into a single one, to avoid the problems that
trying to send two different messages would cause. This also
avoids having a lock in the user-level threads.

Also add a log4j config (and update pom) so that we get logs
from unit test runs.
@vanzin
Copy link
Contributor Author

vanzin commented Mar 30, 2015

Ok, I implemented the FileRegion approach. I chose to keep the code internal to MessageEncoder instead of trying to add a header to LazyFileRegion or other approaches that involved changing code outside of the pipeline handlers.

@vanzin
Copy link
Contributor Author

vanzin commented Mar 30, 2015

BTW if you're ok with this approach I'll need to update the change description since it still references the lock-based approach.

@SparkQA
Copy link

SparkQA commented Mar 30, 2015

Test build #29424 has started for PR 5234 at commit c503f6c.

@AmplabJenkins
Copy link

Test FAILed.
Refer to this link for build results (access rights to CI server needed):
https://amplab.cs.berkeley.edu/jenkins//job/SparkPullRequestBuilder/29424/
Test FAILed.

@SparkQA
Copy link

SparkQA commented Mar 31, 2015

Test build #29437 has started for PR 5234 at commit e26509f.

@vanzin
Copy link
Contributor Author

vanzin commented Mar 31, 2015

I'm trying to run unit tests locally but it seems something is busted somewhere else. e.g. I get this:

sparkDriver-akka.actor.default-dispatcher-16 ERROR AkkaRpcEnv: Ignore error: AkkaRpcEndpointRef(Actor[akka://sparkDriver/user/OutputCommitCoordinator#1646821675]) does not implement 'receive'

SparkListenerSuite also doesn't seem to finish, but right now I'm not sure whether that's the source of the issue or just a side-effect. Also, lots of this in the log output:

15/03/30 17:48:47.658 spark-dynamic-executor-allocation WARN SparkContext: Requesting executors is only supported in coarse-grained mode

I'll try to dig more into this later, but so far I don't see a connection between my code and the current test issues I'm running into.

@SparkQA
Copy link

SparkQA commented Mar 31, 2015

Test build #29480 has started for PR 5234 at commit e26509f.

@AmplabJenkins
Copy link

Test FAILed.
Refer to this link for build results (access rights to CI server needed):
https://amplab.cs.berkeley.edu/jenkins//job/SparkPullRequestBuilder/29480/
Test FAILed.

@SparkQA
Copy link

SparkQA commented Mar 31, 2015

Test build #29497 has started for PR 5234 at commit 8474bab.

@SparkQA
Copy link

SparkQA commented Mar 31, 2015

Test build #29497 has finished for PR 5234 at commit 8474bab.

  • This patch passes all tests.
  • This patch merges cleanly.
  • This patch adds the following public classes (experimental):
    • class MessageWithHeader extends AbstractReferenceCounted implements FileRegion
  • This patch does not change any dependencies.

@AmplabJenkins
Copy link

Test PASSed.
Refer to this link for build results (access rights to CI server needed):
https://amplab.cs.berkeley.edu/jenkins//job/SparkPullRequestBuilder/29497/
Test PASSed.

@SparkQA
Copy link

SparkQA commented Mar 31, 2015

Test build #29505 has started for PR 5234 at commit 9c888ac.

private final int headerLength;
private final Object body;
private final long bodyLength;
private int totalBytesTransferred;
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 this should be a long

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah, yes.

@rxin
Copy link
Contributor

rxin commented Mar 31, 2015

@normanmaurer do you want me to create a ticket for netty for tracking?

@SparkQA
Copy link

SparkQA commented Apr 1, 2015

Test build #29505 has finished for PR 5234 at commit 9c888ac.

  • This patch passes all tests.
  • This patch merges cleanly.
  • This patch adds the following public classes (experimental):
    • class MessageWithHeader extends AbstractReferenceCounted implements FileRegion
  • This patch does not change any dependencies.

@AmplabJenkins
Copy link

Test PASSed.
Refer to this link for build results (access rights to CI server needed):
https://amplab.cs.berkeley.edu/jenkins//job/SparkPullRequestBuilder/29505/
Test PASSed.

@SparkQA
Copy link

SparkQA commented Apr 1, 2015

Test build #29513 has started for PR 5234 at commit 16b2d70.

@SparkQA
Copy link

SparkQA commented Apr 1, 2015

Test build #29513 has finished for PR 5234 at commit 16b2d70.

  • This patch passes all tests.
  • This patch merges cleanly.
  • This patch adds the following public classes (experimental):
    • class MessageWithHeader extends AbstractReferenceCounted implements FileRegion
  • This patch adds the following new dependencies:
    • RoaringBitmap-0.4.5.jar
    • activation-1.1.jar
    • akka-actor_2.10-2.3.4-spark.jar
    • akka-remote_2.10-2.3.4-spark.jar
    • akka-slf4j_2.10-2.3.4-spark.jar
    • aopalliance-1.0.jar
    • arpack_combined_all-0.1.jar
    • avro-1.7.7.jar
    • breeze-macros_2.10-0.11.2.jar
    • breeze_2.10-0.11.2.jar
    • chill-java-0.5.0.jar
    • chill_2.10-0.5.0.jar
    • commons-beanutils-1.7.0.jar
    • commons-beanutils-core-1.8.0.jar
    • commons-cli-1.2.jar
    • commons-codec-1.10.jar
    • commons-collections-3.2.1.jar
    • commons-compress-1.4.1.jar
    • commons-configuration-1.6.jar
    • commons-digester-1.8.jar
    • commons-httpclient-3.1.jar
    • commons-io-2.1.jar
    • commons-lang-2.5.jar
    • commons-lang3-3.3.2.jar
    • commons-math-2.1.jar
    • commons-math3-3.1.1.jar
    • commons-net-2.2.jar
    • compress-lzf-1.0.0.jar
    • config-1.2.1.jar
    • core-1.1.2.jar
    • curator-client-2.4.0.jar
    • curator-framework-2.4.0.jar
    • curator-recipes-2.4.0.jar
    • gmbal-api-only-3.0.0-b023.jar
    • grizzly-framework-2.1.2.jar
    • grizzly-http-2.1.2.jar
    • grizzly-http-server-2.1.2.jar
    • grizzly-http-servlet-2.1.2.jar
    • grizzly-rcm-2.1.2.jar
    • groovy-all-2.3.7.jar
    • guava-14.0.1.jar
    • guice-3.0.jar
    • hadoop-annotations-2.2.0.jar
    • hadoop-auth-2.2.0.jar
    • hadoop-client-2.2.0.jar
    • hadoop-common-2.2.0.jar
    • hadoop-hdfs-2.2.0.jar
    • hadoop-mapreduce-client-app-2.2.0.jar
    • hadoop-mapreduce-client-common-2.2.0.jar
    • hadoop-mapreduce-client-core-2.2.0.jar
    • hadoop-mapreduce-client-jobclient-2.2.0.jar
    • hadoop-mapreduce-client-shuffle-2.2.0.jar
    • hadoop-yarn-api-2.2.0.jar
    • hadoop-yarn-client-2.2.0.jar
    • hadoop-yarn-common-2.2.0.jar
    • hadoop-yarn-server-common-2.2.0.jar
    • ivy-2.4.0.jar
    • jackson-annotations-2.4.0.jar
    • jackson-core-2.4.4.jar
    • jackson-core-asl-1.8.8.jar
    • jackson-databind-2.4.4.jar
    • jackson-jaxrs-1.8.8.jar
    • jackson-mapper-asl-1.8.8.jar
    • jackson-module-scala_2.10-2.4.4.jar
    • jackson-xc-1.8.8.jar
    • jansi-1.4.jar
    • javax.inject-1.jar
    • javax.servlet-3.0.0.v201112011016.jar
    • javax.servlet-3.1.jar
    • javax.servlet-api-3.0.1.jar
    • jaxb-api-2.2.2.jar
    • jaxb-impl-2.2.3-1.jar
    • jcl-over-slf4j-1.7.10.jar
    • jersey-client-1.9.jar
    • jersey-core-1.9.jar
    • jersey-grizzly2-1.9.jar
    • jersey-guice-1.9.jar
    • jersey-json-1.9.jar
    • jersey-server-1.9.jar
    • jersey-test-framework-core-1.9.jar
    • jersey-test-framework-grizzly2-1.9.jar
    • jets3t-0.7.1.jar
    • jettison-1.1.jar
    • jetty-util-6.1.26.jar
    • jline-0.9.94.jar
    • jline-2.10.4.jar
    • jodd-core-3.6.3.jar
    • json4s-ast_2.10-3.2.10.jar
    • json4s-core_2.10-3.2.10.jar
    • json4s-jackson_2.10-3.2.10.jar
    • jsr305-1.3.9.jar
    • jtransforms-2.4.0.jar
    • jul-to-slf4j-1.7.10.jar
    • kryo-2.21.jar
    • log4j-1.2.17.jar
    • lz4-1.2.0.jar
    • management-api-3.0.0-b012.jar
    • mesos-0.21.0-shaded-protobuf.jar
    • metrics-core-3.1.0.jar
    • metrics-graphite-3.1.0.jar
    • metrics-json-3.1.0.jar
    • metrics-jvm-3.1.0.jar
    • minlog-1.2.jar
    • netty-3.8.0.Final.jar
    • netty-all-4.0.23.Final.jar
    • objenesis-1.2.jar
    • opencsv-2.3.jar
    • oro-2.0.8.jar
    • paranamer-2.6.jar
    • parquet-column-1.6.0rc3.jar
    • parquet-common-1.6.0rc3.jar
    • parquet-encoding-1.6.0rc3.jar
    • parquet-format-2.2.0-rc1.jar
    • parquet-generator-1.6.0rc3.jar
    • parquet-hadoop-1.6.0rc3.jar
    • parquet-jackson-1.6.0rc3.jar
    • protobuf-java-2.4.1.jar
    • protobuf-java-2.5.0-spark.jar
    • py4j-0.8.2.1.jar
    • pyrolite-2.0.1.jar
    • quasiquotes_2.10-2.0.1.jar
    • reflectasm-1.07-shaded.jar
    • scala-compiler-2.10.4.jar
    • scala-library-2.10.4.jar
    • scala-reflect-2.10.4.jar
    • scalap-2.10.4.jar
    • scalatest_2.10-2.2.1.jar
    • slf4j-api-1.7.10.jar
    • slf4j-log4j12-1.7.10.jar
    • snappy-java-1.1.1.6.jar
    • spark-bagel_2.10-1.4.0-SNAPSHOT.jar
    • spark-catalyst_2.10-1.4.0-SNAPSHOT.jar
    • spark-core_2.10-1.4.0-SNAPSHOT.jar
    • spark-graphx_2.10-1.4.0-SNAPSHOT.jar
    • spark-launcher_2.10-1.4.0-SNAPSHOT.jar
    • spark-mllib_2.10-1.4.0-SNAPSHOT.jar
    • spark-network-common_2.10-1.4.0-SNAPSHOT.jar
    • spark-network-shuffle_2.10-1.4.0-SNAPSHOT.jar
    • spark-repl_2.10-1.4.0-SNAPSHOT.jar
    • spark-sql_2.10-1.4.0-SNAPSHOT.jar
    • spark-streaming_2.10-1.4.0-SNAPSHOT.jar
    • spire-macros_2.10-0.7.4.jar
    • spire_2.10-0.7.4.jar
    • stax-api-1.0.1.jar
    • stream-2.7.0.jar
    • tachyon-0.5.0.jar
    • tachyon-client-0.5.0.jar
    • uncommons-maths-1.2.2a.jar
    • unused-1.0.0.jar
    • xmlenc-0.52.jar
    • xz-1.0.jar
    • zookeeper-3.4.5.jar

@AmplabJenkins
Copy link

Test PASSed.
Refer to this link for build results (access rights to CI server needed):
https://amplab.cs.berkeley.edu/jenkins//job/SparkPullRequestBuilder/29513/
Test PASSed.

}

private int copyByteBuf(ByteBuf buf, WritableByteChannel target) throws IOException {
int written = target.write(buf.nioBuffer());
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this actually safe? nioBuffer can create a duplicate each time, and thus resetting the offset?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

What do you mean by "resetting the offset"? The buffer returned by nioBuffer() does not change the state of the ByteBuf, which is why you have the skipBytes call in the next line.

Copy link
Contributor

Choose a reason for hiding this comment

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

ah nvm i thougth this was a ManagedBuffer

@rxin
Copy link
Contributor

rxin commented Apr 1, 2015

Thanks. Merging in master & branch-1.3.

I think there is a minor change we can do to make the code more clear, but I will just submit a small PR for that myself.

@asfgit asfgit closed this in f084c5d Apr 1, 2015
asfgit pushed a commit that referenced this pull request Apr 1, 2015
…rk library.

While the inbound path of a netty pipeline is thread-safe, the outbound
path is not. That means that multiple threads can compete to write messages
to the next stage of the pipeline.

The network library sometimes breaks a single RPC message into multiple
buffers internally to avoid copying data (see MessageEncoder). This can
result in the following scenario (where "FxBy" means "frame x, buffer y"):

               T1         F1B1            F1B2
                            \               \
                             \               \
               socket        F1B1   F2B1    F1B2  F2B2
                                     /             /
                                    /             /
               T2                  F2B1         F2B2

And the frames now cannot be rebuilt on the receiving side because the
different messages have been mixed up on the wire.

The fix wraps these multi-buffer messages into a `FileRegion` object
so that these messages are written "atomically" to the next pipeline handler.

Author: Marcelo Vanzin <[email protected]>

Closes #5234 from vanzin/SPARK-6578 and squashes the following commits:

16b2d70 [Marcelo Vanzin] Forgot to update a type.
c9c2e4e [Marcelo Vanzin] Review comments: simplify some code.
9c888ac [Marcelo Vanzin] Small style nits.
8474bab [Marcelo Vanzin] Fix multiple calls to MessageWithHeader.transferTo().
e26509f [Marcelo Vanzin] Merge branch 'master' into SPARK-6578
c503f6c [Marcelo Vanzin] Implement a custom FileRegion instead of using locks.
84aa7ce [Marcelo Vanzin] Rename handler to the correct name.
432f3bd [Marcelo Vanzin] Remove unneeded method.
8d70e60 [Marcelo Vanzin] Fix thread-safety issue in outbound path of network library.

(cherry picked from commit f084c5d)
Signed-off-by: Reynold Xin <[email protected]>
@vanzin vanzin deleted the SPARK-6578 branch April 2, 2015 19:55
vanzin pushed a commit to vanzin/spark that referenced this pull request Apr 2, 2015
…rk library.

While the inbound path of a netty pipeline is thread-safe, the outbound
path is not. That means that multiple threads can compete to write messages
to the next stage of the pipeline.

The network library sometimes breaks a single RPC message into multiple
buffers internally to avoid copying data (see MessageEncoder). This can
result in the following scenario (where "FxBy" means "frame x, buffer y"):

               T1         F1B1            F1B2
                            \               \
                             \               \
               socket        F1B1   F2B1    F1B2  F2B2
                                     /             /
                                    /             /
               T2                  F2B1         F2B2

And the frames now cannot be rebuilt on the receiving side because the
different messages have been mixed up on the wire.

The fix wraps these multi-buffer messages into a `FileRegion` object
so that these messages are written "atomically" to the next pipeline handler.

Author: Marcelo Vanzin <[email protected]>

Closes apache#5234 from vanzin/SPARK-6578 and squashes the following commits:

16b2d70 [Marcelo Vanzin] Forgot to update a type.
c9c2e4e [Marcelo Vanzin] Review comments: simplify some code.
9c888ac [Marcelo Vanzin] Small style nits.
8474bab [Marcelo Vanzin] Fix multiple calls to MessageWithHeader.transferTo().
e26509f [Marcelo Vanzin] Merge branch 'master' into SPARK-6578
c503f6c [Marcelo Vanzin] Implement a custom FileRegion instead of using locks.
84aa7ce [Marcelo Vanzin] Rename handler to the correct name.
432f3bd [Marcelo Vanzin] Remove unneeded method.
8d70e60 [Marcelo Vanzin] Fix thread-safety issue in outbound path of network library.

(cherry picked from commit f084c5d)

Conflicts:
	network/common/pom.xml
vanzin pushed a commit to vanzin/spark that referenced this pull request Apr 20, 2015
…rk library.

While the inbound path of a netty pipeline is thread-safe, the outbound
path is not. That means that multiple threads can compete to write messages
to the next stage of the pipeline.

The network library sometimes breaks a single RPC message into multiple
buffers internally to avoid copying data (see MessageEncoder). This can
result in the following scenario (where "FxBy" means "frame x, buffer y"):

               T1         F1B1            F1B2
                            \               \
                             \               \
               socket        F1B1   F2B1    F1B2  F2B2
                                     /             /
                                    /             /
               T2                  F2B1         F2B2

And the frames now cannot be rebuilt on the receiving side because the
different messages have been mixed up on the wire.

The fix wraps these multi-buffer messages into a `FileRegion` object
so that these messages are written "atomically" to the next pipeline handler.

Author: Marcelo Vanzin <[email protected]>

Closes apache#5234 from vanzin/SPARK-6578 and squashes the following commits:

16b2d70 [Marcelo Vanzin] Forgot to update a type.
c9c2e4e [Marcelo Vanzin] Review comments: simplify some code.
9c888ac [Marcelo Vanzin] Small style nits.
8474bab [Marcelo Vanzin] Fix multiple calls to MessageWithHeader.transferTo().
e26509f [Marcelo Vanzin] Merge branch 'master' into SPARK-6578
c503f6c [Marcelo Vanzin] Implement a custom FileRegion instead of using locks.
84aa7ce [Marcelo Vanzin] Rename handler to the correct name.
432f3bd [Marcelo Vanzin] Remove unneeded method.
8d70e60 [Marcelo Vanzin] Fix thread-safety issue in outbound path of network library.

(cherry picked from commit f084c5d)
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.

7 participants