-
Notifications
You must be signed in to change notification settings - Fork 28.9k
[SPARK-3167] Handle special driver configs in Windows #2129
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 all commits
83ebe60
f97daa2
35caecc
eeb34a0
803218b
72004c2
afcffea
22b1acd
92e6047
881a8f0
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 |
|---|---|---|
|
|
@@ -17,6 +17,8 @@ rem See the License for the specific language governing permissions and | |
| rem limitations under the License. | ||
| rem | ||
|
|
||
| rem Any changes to this file must be reflected in SparkSubmitDriverBootstrapper.scala! | ||
|
|
||
| setlocal enabledelayedexpansion | ||
|
|
||
| set SCALA_VERSION=2.10 | ||
|
|
@@ -38,7 +40,7 @@ if not "x%1"=="x" goto arg_given | |
|
|
||
| if not "x%SPARK_MEM%"=="x" ( | ||
| echo Warning: SPARK_MEM is deprecated, please use a more specific config option | ||
| echo e.g., spark.executor.memory or SPARK_DRIVER_MEMORY. | ||
| echo e.g., spark.executor.memory or spark.driver.memory. | ||
| ) | ||
|
|
||
| rem Use SPARK_MEM or 512m as the default memory, to be overridden by specific options | ||
|
|
@@ -67,10 +69,18 @@ rem Executors use SPARK_JAVA_OPTS + SPARK_EXECUTOR_MEMORY. | |
| set OUR_JAVA_OPTS=%SPARK_JAVA_OPTS% %SPARK_EXECUTOR_OPTS% | ||
| if not "x%SPARK_EXECUTOR_MEMORY%"=="x" set OUR_JAVA_MEM=%SPARK_EXECUTOR_MEMORY% | ||
|
|
||
| rem All drivers use SPARK_JAVA_OPTS + SPARK_DRIVER_MEMORY. The repl also uses SPARK_REPL_OPTS. | ||
| ) else if "%1"=="org.apache.spark.repl.Main" ( | ||
| set OUR_JAVA_OPTS=%SPARK_JAVA_OPTS% %SPARK_REPL_OPTS% | ||
| rem Spark submit uses SPARK_JAVA_OPTS + SPARK_SUBMIT_OPTS + | ||
| rem SPARK_DRIVER_MEMORY + SPARK_SUBMIT_DRIVER_MEMORY. | ||
| rem The repl also uses SPARK_REPL_OPTS. | ||
| ) else if "%1"=="org.apache.spark.deploy.SparkSubmit" ( | ||
| set OUR_JAVA_OPTS=%SPARK_JAVA_OPTS% %SPARK_SUBMIT_OPTS% %SPARK_REPL_OPTS% | ||
| if not "x%SPARK_SUBMIT_LIBRARY_PATH%"=="x" ( | ||
| set OUR_JAVA_OPTS=!OUR_JAVA_OPTS! -Djava.library.path=%SPARK_SUBMIT_LIBRARY_PATH% | ||
| ) else if not "x%SPARK_LIBRARY_PATH%"=="x" ( | ||
| set OUR_JAVA_OPTS=!OUR_JAVA_OPTS! -Djava.library.path=%SPARK_LIBRARY_PATH% | ||
| ) | ||
| if not "x%SPARK_DRIVER_MEMORY%"=="x" set OUR_JAVA_MEM=%SPARK_DRIVER_MEMORY% | ||
| if not "x%SPARK_SUBMIT_DRIVER_MEMORY%"=="x" set OUR_JAVA_MEM=%SPARK_SUBMIT_DRIVER_MEMORY% | ||
| ) else ( | ||
| set OUR_JAVA_OPTS=%SPARK_JAVA_OPTS% | ||
| if not "x%SPARK_DRIVER_MEMORY%"=="x" set OUR_JAVA_MEM=%SPARK_DRIVER_MEMORY% | ||
|
|
@@ -80,9 +90,9 @@ rem Set JAVA_OPTS to be able to load native libraries and to set heap size | |
| for /f "tokens=3" %%i in ('java -version 2^>^&1 ^| find "version"') do set jversion=%%i | ||
| for /f "tokens=1 delims=_" %%i in ("%jversion:~1,-1%") do set jversion=%%i | ||
| if "%jversion%" geq "1.8.0" ( | ||
| set JAVA_OPTS=%OUR_JAVA_OPTS% -Djava.library.path=%SPARK_LIBRARY_PATH% -Xms%OUR_JAVA_MEM% -Xmx%OUR_JAVA_MEM% | ||
| set JAVA_OPTS=%OUR_JAVA_OPTS% -Xms%OUR_JAVA_MEM% -Xmx%OUR_JAVA_MEM% | ||
| ) else ( | ||
| set JAVA_OPTS=-XX:MaxPermSize=128m %OUR_JAVA_OPTS% -Djava.library.path=%SPARK_LIBRARY_PATH% -Xms%OUR_JAVA_MEM% -Xmx%OUR_JAVA_MEM% | ||
| set JAVA_OPTS=-XX:MaxPermSize=128m %OUR_JAVA_OPTS% -Xms%OUR_JAVA_MEM% -Xmx%OUR_JAVA_MEM% | ||
| ) | ||
| rem Attention: when changing the way the JAVA_OPTS are assembled, the change must be reflected in CommandUtils.scala! | ||
|
|
||
|
|
@@ -115,5 +125,27 @@ rem Figure out where java is. | |
| set RUNNER=java | ||
| if not "x%JAVA_HOME%"=="x" set RUNNER=%JAVA_HOME%\bin\java | ||
|
|
||
| "%RUNNER%" -cp "%CLASSPATH%" %JAVA_OPTS% %* | ||
| rem In Spark submit client mode, the driver is launched in the same JVM as Spark submit itself. | ||
| rem Here we must parse the properties file for relevant "spark.driver.*" configs before launching | ||
| rem the driver JVM itself. Instead of handling this complexity here, we launch a separate JVM | ||
| rem to prepare the launch environment of this driver JVM. | ||
|
|
||
| rem In this case, leave out the main class (org.apache.spark.deploy.SparkSubmit) and use our own. | ||
| rem Leaving out the first argument is surprisingly difficult to do in Windows. Note that this must | ||
| rem be done here because the Windows "shift" command does not work in a conditional block. | ||
| set BOOTSTRAP_ARGS= | ||
| shift | ||
| :start_parse | ||
| if "%~1" == "" goto end_parse | ||
| set BOOTSTRAP_ARGS=%BOOTSTRAP_ARGS% %~1 | ||
| shift | ||
| goto start_parse | ||
| :end_parse | ||
|
|
||
| if not [%SPARK_SUBMIT_BOOTSTRAP_DRIVER%] == [] ( | ||
| set SPARK_CLASS=1 | ||
| "%RUNNER%" org.apache.spark.deploy.SparkSubmitDriverBootstrapper %BOOTSTRAP_ARGS% | ||
|
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. This is not working yet. See commit message andrewor14@83ebe60 for more detail.
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. This should be fixed in this commit andrewor14@f97daa2
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. JK, this was actually fixed in andrewor14@35caecc |
||
| ) else ( | ||
| "%RUNNER%" -cp "%CLASSPATH%" %JAVA_OPTS% %* | ||
| ) | ||
| :exit | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -133,17 +133,24 @@ private[spark] object SparkSubmitDriverBootstrapper { | |
| val process = builder.start() | ||
|
|
||
| // Redirect stdin, stdout, and stderr to/from the child JVM | ||
| val stdinThread = new RedirectThread(System.in, process.getOutputStream, "redirect stdin") | ||
| val stdoutThread = new RedirectThread(process.getInputStream, System.out, "redirect stdout") | ||
| val stderrThread = new RedirectThread(process.getErrorStream, System.err, "redirect stderr") | ||
| stdinThread.start() | ||
| stdoutThread.start() | ||
| stderrThread.start() | ||
|
|
||
| // Terminate on broken pipe, which signals that the parent process has exited. This is | ||
| // important for the PySpark shell, where Spark submit itself is a python subprocess. | ||
| stdinThread.join() | ||
| process.destroy() | ||
| // In Windows, the subprocess reads directly from our stdin, so we should avoid spawning | ||
|
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. Is there any public location where this behavior is specified (i.e. for a developer doc?)
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. Not that I'm aware of :/ |
||
| // a thread that contends with the subprocess in reading from System.in. | ||
| if (Utils.isWindows) { | ||
| // For the PySpark shell, the termination of this process is handled in java_gateway.py | ||
| process.waitFor() | ||
| } else { | ||
| // Terminate on broken pipe, which signals that the parent process has exited. This is | ||
| // important for the PySpark shell, where Spark submit itself is a python subprocess. | ||
| val stdinThread = new RedirectThread(System.in, process.getOutputStream, "redirect stdin") | ||
| stdinThread.start() | ||
| stdinThread.join() | ||
| process.destroy() | ||
| } | ||
| } | ||
|
|
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -15,6 +15,7 @@ | |
| # limitations under the License. | ||
| # | ||
|
|
||
| import atexit | ||
| import os | ||
| import sys | ||
| import signal | ||
|
|
@@ -69,6 +70,22 @@ def preexec_func(): | |
| error_msg += "--------------------------------------------------------------\n" | ||
| raise Exception(error_msg) | ||
|
|
||
| # In Windows, ensure the Java child processes do not linger after Python has exited. | ||
| # In UNIX-based systems, the child process can kill itself on broken pipe (i.e. when | ||
| # the parent process' stdin sends an EOF). In Windows, however, this is not possible | ||
| # because java.lang.Process reads directly from the parent process' stdin, contending | ||
| # with any opportunity to read an EOF from the parent. Note that this is only best | ||
| # effort and will not take effect if the python process is violently terminated. | ||
| if on_windows: | ||
| # In Windows, the child process here is "spark-submit.cmd", not the JVM itself | ||
| # (because the UNIX "exec" command is not available). This means we cannot simply | ||
| # call proc.kill(), which kills only the "spark-submit.cmd" process but not the | ||
| # JVMs. Instead, we use "taskkill" with the tree-kill option "/t" to terminate all | ||
| # child processes in the tree (http://technet.microsoft.com/en-us/library/bb491009.aspx) | ||
| def killChild(): | ||
| Popen(["cmd", "/c", "taskkill", "/f", "/t", "/pid", str(proc.pid)]) | ||
|
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. I would link to wherever you found this - maybe here? Also, this is a bit scary to just issue kill commands (let's hope
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. Sure. If we are to link it I'd rather provide a more official one, say http://technet.microsoft.com/en-us/library/bb491009.aspx |
||
| atexit.register(killChild) | ||
|
|
||
| # Create a thread to echo output from the GatewayServer, which is required | ||
| # for Java log output to show up: | ||
| class EchoOutputThread(Thread): | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The
!VAR_NAME!syntax is explained here: andrewor14@72004c2. If we used%VAR_NAME%, this wouldn't pick up the latest value set in L76 because we're inside a conditional.