-
Notifications
You must be signed in to change notification settings - Fork 29.3k
[SPARK-22590][SQL] Copy sparkContext.localproperties to child thread in BroadcastExchangeExec.executionContext #27266
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
Changes from 12 commits
6803bb0
ae519ca
59b42d4
dd42e11
354dc61
0b62b52
b208a7a
65c49de
0f39043
742d322
11fffca
763d1bc
2ed76c3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -34,7 +34,7 @@ import org.apache.spark.sql.execution.{SparkPlan, SQLExecution} | |
| import org.apache.spark.sql.execution.joins.HashedRelation | ||
| import org.apache.spark.sql.execution.metric.SQLMetrics | ||
| import org.apache.spark.sql.internal.{SQLConf, StaticSQLConf} | ||
| import org.apache.spark.util.{SparkFatalException, ThreadUtils} | ||
| import org.apache.spark.util.{SparkFatalException, ThreadUtils, Utils} | ||
|
|
||
| /** | ||
| * A [[BroadcastExchangeExec]] collects, transforms and finally broadcasts the result of | ||
|
|
@@ -73,83 +73,79 @@ case class BroadcastExchangeExec( | |
|
|
||
| @transient | ||
| private[sql] lazy val relationFuture: Future[broadcast.Broadcast[Any]] = { | ||
| // relationFuture is used in "doExecute". Therefore we can get the execution id correctly here. | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I usually don't like such changes. Wonder if we can keep the indentation same and make it easier to track the history of commits.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @HyukjinKwon I have tried to adjust the indent so that diff seems to show only lines i have modified. Does it seem ok now.?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The indentation is wrong now although the diff is smaller. how about
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @cloud-fan updated as per your suggestion, but still it changes indent than original. Is it ok.?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ah sorry I misread the code. Seems we can't avoid changing the indentation as it was so nested before. I'm OK with your original code.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. reverted |
||
| val executionId = sparkContext.getLocalProperty(SQLExecution.EXECUTION_ID_KEY) | ||
| val task = new Callable[broadcast.Broadcast[Any]]() { | ||
| override def call(): broadcast.Broadcast[Any] = { | ||
| // This will run in another thread. Set the execution id so that we can connect these jobs | ||
| // with the correct execution. | ||
| SQLExecution.withExecutionId(sqlContext.sparkSession, executionId) { | ||
| try { | ||
| // Setup a job group here so later it may get cancelled by groupId if necessary. | ||
| sparkContext.setJobGroup(runId.toString, s"broadcast exchange (runId $runId)", | ||
| interruptOnCancel = true) | ||
| val beforeCollect = System.nanoTime() | ||
| // Use executeCollect/executeCollectIterator to avoid conversion to Scala types | ||
| val (numRows, input) = child.executeCollectIterator() | ||
| if (numRows >= 512000000) { | ||
| throw new SparkException( | ||
| s"Cannot broadcast the table with 512 million or more rows: $numRows rows") | ||
| } | ||
|
|
||
| val beforeBuild = System.nanoTime() | ||
| longMetric("collectTime") += NANOSECONDS.toMillis(beforeBuild - beforeCollect) | ||
|
|
||
| // Construct the relation. | ||
| val relation = mode.transform(input, Some(numRows)) | ||
|
|
||
| val dataSize = relation match { | ||
| case map: HashedRelation => | ||
| map.estimatedSize | ||
| case arr: Array[InternalRow] => | ||
| arr.map(_.asInstanceOf[UnsafeRow].getSizeInBytes.toLong).sum | ||
| case _ => | ||
| throw new SparkException("[BUG] BroadcastMode.transform returned unexpected " + | ||
| s"type: ${relation.getClass.getName}") | ||
| } | ||
|
|
||
| longMetric("dataSize") += dataSize | ||
| if (dataSize >= (8L << 30)) { | ||
| throw new SparkException( | ||
| s"Cannot broadcast the table that is larger than 8GB: ${dataSize >> 30} GB") | ||
| } | ||
|
|
||
| val beforeBroadcast = System.nanoTime() | ||
| longMetric("buildTime") += NANOSECONDS.toMillis(beforeBroadcast - beforeBuild) | ||
|
|
||
| // Broadcast the relation | ||
| val broadcasted = sparkContext.broadcast(relation) | ||
| longMetric("broadcastTime") += NANOSECONDS.toMillis( | ||
| System.nanoTime() - beforeBroadcast) | ||
|
|
||
| SQLMetrics.postDriverMetricUpdates(sparkContext, executionId, metrics.values.toSeq) | ||
| promise.success(broadcasted) | ||
| broadcasted | ||
| } catch { | ||
| // SPARK-24294: To bypass scala bug: https://github.com/scala/bug/issues/9554, we throw | ||
| // SparkFatalException, which is a subclass of Exception. ThreadUtils.awaitResult | ||
| // will catch this exception and re-throw the wrapped fatal throwable. | ||
| case oe: OutOfMemoryError => | ||
| val ex = new SparkFatalException( | ||
| new OutOfMemoryError("Not enough memory to build and broadcast the table to all " + | ||
| "worker nodes. As a workaround, you can either disable broadcast by setting " + | ||
| s"${SQLConf.AUTO_BROADCASTJOIN_THRESHOLD.key} to -1 or increase the spark " + | ||
| s"driver memory by setting ${SparkLauncher.DRIVER_MEMORY} to a higher value.") | ||
| .initCause(oe.getCause)) | ||
| promise.failure(ex) | ||
| throw ex | ||
| case e if !NonFatal(e) => | ||
| val ex = new SparkFatalException(e) | ||
| promise.failure(ex) | ||
| throw ex | ||
| case e: Throwable => | ||
| promise.failure(e) | ||
| throw e | ||
| } | ||
| } | ||
| SQLExecution.withThreadLocalCaptured[broadcast.Broadcast[Any]]( | ||
| sqlContext.sparkSession, BroadcastExchangeExec.executionContext) { | ||
| doBroadcast | ||
| } | ||
| } | ||
|
|
||
| private def doBroadcast = { | ||
| try { | ||
| // Setup a job group here so later it may get cancelled by groupId if necessary. | ||
| sparkContext.setJobGroup(runId.toString, s"broadcast exchange (runId $runId)", | ||
| interruptOnCancel = true) | ||
| val beforeCollect = System.nanoTime() | ||
| // Use executeCollect/executeCollectIterator to avoid conversion to Scala types | ||
| val (numRows, input) = child.executeCollectIterator() | ||
| if (numRows >= 512000000) { | ||
| throw new SparkException( | ||
| s"Cannot broadcast the table with 512 million or more rows: $numRows rows") | ||
| } | ||
|
|
||
| val beforeBuild = System.nanoTime() | ||
| longMetric("collectTime") += NANOSECONDS.toMillis(beforeBuild - beforeCollect) | ||
|
|
||
| // Construct the relation. | ||
| val relation = mode.transform(input, Some(numRows)) | ||
|
|
||
| val dataSize = relation match { | ||
| case map: HashedRelation => | ||
| map.estimatedSize | ||
| case arr: Array[InternalRow] => | ||
| arr.map(_.asInstanceOf[UnsafeRow].getSizeInBytes.toLong).sum | ||
| case _ => | ||
| throw new SparkException("[BUG] BroadcastMode.transform returned unexpected " + | ||
| s"type: ${relation.getClass.getName}") | ||
| } | ||
|
|
||
| longMetric("dataSize") += dataSize | ||
| if (dataSize >= (8L << 30)) { | ||
| throw new SparkException( | ||
| s"Cannot broadcast the table that is larger than 8GB: ${dataSize >> 30} GB") | ||
| } | ||
|
|
||
| val beforeBroadcast = System.nanoTime() | ||
| longMetric("buildTime") += NANOSECONDS.toMillis(beforeBroadcast - beforeBuild) | ||
|
|
||
| // Broadcast the relation | ||
| val broadcasted = sparkContext.broadcast(relation) | ||
| longMetric("broadcastTime") += NANOSECONDS.toMillis( | ||
| System.nanoTime() - beforeBroadcast) | ||
| val executionId = sparkContext.getLocalProperty(SQLExecution.EXECUTION_ID_KEY) | ||
| SQLMetrics.postDriverMetricUpdates(sparkContext, executionId, metrics.values.toSeq) | ||
| promise.success(broadcasted) | ||
| broadcasted | ||
| } catch { | ||
| // SPARK-24294: To bypass scala bug: https://github.com/scala/bug/issues/9554, we throw | ||
| // SparkFatalException, which is a subclass of Exception. ThreadUtils.awaitResult | ||
| // will catch this exception and re-throw the wrapped fatal throwable. | ||
| case oe: OutOfMemoryError => | ||
| val ex = new SparkFatalException( | ||
| new OutOfMemoryError("Not enough memory to build and broadcast the table to all " + | ||
| "worker nodes. As a workaround, you can either disable broadcast by setting " + | ||
| s"${SQLConf.AUTO_BROADCASTJOIN_THRESHOLD.key} to -1 or increase the spark " + | ||
| s"driver memory by setting ${SparkLauncher.DRIVER_MEMORY} to a higher value.") | ||
| .initCause(oe.getCause)) | ||
| promise.failure(ex) | ||
| throw ex | ||
| case e if !NonFatal(e) => | ||
| val ex = new SparkFatalException(e) | ||
| promise.failure(ex) | ||
| throw ex | ||
| case e: Throwable => | ||
| promise.failure(e) | ||
| throw e | ||
| } | ||
| BroadcastExchangeExec.executionContext.submit[broadcast.Broadcast[Any]](task) | ||
| } | ||
|
|
||
| override protected def doPrepare(): Unit = { | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.