{"action":"created","issue":{"url":"https://api.github.com/repos/apache/spark/issues/22079","repository_url":"https://api.github.com/repos/apache/spark","labels_url":"https://api.github.com/repos/apache/spark/issues/22079/labels{/name}","comments_url":"https://api.github.com/repos/apache/spark/issues/22079/comments","events_url":"https://api.github.com/repos/apache/spark/issues/22079/events","html_url":"https://github.com/apache/spark/pull/22079","id":349745616,"node_id":"MDExOlB1bGxSZXF1ZXN0MjA3NzgxNjE0","number":22079,"title":"[SPARK-23207][SQL][BACKPORT-2.2] Shuffle+Repartition on a DataFrame could lead to incorrect answers","user":{"login":"bersprockets","id":21131848,"node_id":"MDQ6VXNlcjIxMTMxODQ4","avatar_url":"https://avatars2.githubusercontent.com/u/21131848?v=4","gravatar_id":"","url":"https://api.github.com/users/bersprockets","html_url":"https://github.com/bersprockets","followers_url":"https://api.github.com/users/bersprockets/followers","following_url":"https://api.github.com/users/bersprockets/following{/other_user}","gists_url":"https://api.github.com/users/bersprockets/gists{/gist_id}","starred_url":"https://api.github.com/users/bersprockets/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/bersprockets/subscriptions","organizations_url":"https://api.github.com/users/bersprockets/orgs","repos_url":"https://api.github.com/users/bersprockets/repos","events_url":"https://api.github.com/users/bersprockets/events{/privacy}","received_events_url":"https://api.github.com/users/bersprockets/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":3,"created_at":"2018-08-11T16:19:25Z","updated_at":"2018-08-11T18:40:16Z","closed_at":null,"author_association":"CONTRIBUTOR","pull_request":{"url":"https://api.github.com/repos/apache/spark/pulls/22079","html_url":"https://github.com/apache/spark/pull/22079","diff_url":"https://github.com/apache/spark/pull/22079.diff","patch_url":"https://github.com/apache/spark/pull/22079.patch"},"body":"## What changes were proposed in this pull request?\r\n\r\nCurrently shuffle repartition uses RoundRobinPartitioning, the generated result is nondeterministic since the sequence of input rows are not determined.\r\n\r\nThe bug can be triggered when there is a repartition call following a shuffle (which would lead to non-deterministic row ordering), as the pattern shows below:\r\nupstream stage -> repartition stage -> result stage\r\n(-> indicate a shuffle)\r\nWhen one of the executors process goes down, some tasks on the repartition stage will be retried and generate inconsistent ordering, and some tasks of the result stage will be retried generating different data.\r\n\r\nThe following code returns 931532, instead of 1000000:\r\n```\r\nimport scala.sys.process._\r\n\r\nimport org.apache.spark.TaskContext\r\nval res = spark.range(0, 1000 * 1000, 1).repartition(200).map { x =>\r\n  x\r\n}.repartition(200).map { x =>\r\n  if (TaskContext.get.attemptNumber == 0 && TaskContext.get.partitionId < 2) {\r\n    throw new Exception(\"pkill -f java\".!!)\r\n  }\r\n  x\r\n}\r\nres.distinct().count()\r\n```\r\n\r\nIn this PR, we propose a most straight-forward way to fix this problem by performing a local sort before partitioning, after we make the input row ordering deterministic, the function from rows to partitions is fully deterministic too.\r\n\r\nThe downside of the approach is that with extra local sort inserted, the performance of repartition() will go down, so we add a new config named `spark.sql.execution.sortBeforeRepartition` to control whether this patch is applied. The patch is default enabled to be safe-by-default, but user may choose to manually turn it off to avoid performance regression.\r\n\r\nThis patch also changes the output rows ordering of repartition(), that leads to a bunch of test cases failure because they are comparing the results directly.\r\n\r\nAdd unit test in ExchangeSuite.\r\n\r\nWith this patch(and `spark.sql.execution.sortBeforeRepartition` set to true), the following query returns 1000000:\r\n```\r\nimport scala.sys.process._\r\n\r\nimport org.apache.spark.TaskContext\r\n\r\nspark.conf.set(\"spark.sql.execution.sortBeforeRepartition\", \"true\")\r\n\r\nval res = spark.range(0, 1000 * 1000, 1).repartition(200).map { x =>\r\n  x\r\n}.repartition(200).map { x =>\r\n  if (TaskContext.get.attemptNumber == 0 && TaskContext.get.partitionId < 2) {\r\n    throw new Exception(\"pkill -f java\".!!)\r\n  }\r\n  x\r\n}\r\nres.distinct().count()\r\n\r\nres7: Long = 1000000\r\n```\r\n\r\nAuthor: Xingbo Jiang <xingbo.jiang@databricks.com>\r\n\r\n## How was this patch tested?\r\n\r\nRan all SBT unit tests for org.apache.spark.sql.*.\r\n\r\nRan pyspark tests for module pyspark-sql.\r\n\r\n"},"comment":{"url":"https://api.github.com/repos/apache/spark/issues/comments/412294039","html_url":"https://github.com/apache/spark/pull/22079#issuecomment-412294039","issue_url":"https://api.github.com/repos/apache/spark/issues/22079","id":412294039,"node_id":"MDEyOklzc3VlQ29tbWVudDQxMjI5NDAzOQ==","user":{"login":"AmplabJenkins","id":4031291,"node_id":"MDQ6VXNlcjQwMzEyOTE=","avatar_url":"https://avatars3.githubusercontent.com/u/4031291?v=4","gravatar_id":"","url":"https://api.github.com/users/AmplabJenkins","html_url":"https://github.com/AmplabJenkins","followers_url":"https://api.github.com/users/AmplabJenkins/followers","following_url":"https://api.github.com/users/AmplabJenkins/following{/other_user}","gists_url":"https://api.github.com/users/AmplabJenkins/gists{/gist_id}","starred_url":"https://api.github.com/users/AmplabJenkins/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/AmplabJenkins/subscriptions","organizations_url":"https://api.github.com/users/AmplabJenkins/orgs","repos_url":"https://api.github.com/users/AmplabJenkins/repos","events_url":"https://api.github.com/users/AmplabJenkins/events{/privacy}","received_events_url":"https://api.github.com/users/AmplabJenkins/received_events","type":"User","site_admin":false},"created_at":"2018-08-11T18:40:16Z","updated_at":"2018-08-11T18:40:16Z","author_association":"NONE","body":"Merged build finished. Test FAILed."}}
{"actor":{"display_login":"AmplabJenkins"}}