aboutsummaryrefslogtreecommitdiff
path: root/yarn
diff options
context:
space:
mode:
authorCarsten Blank <blank@cncengine.com>2015-08-19 10:19:24 -0700
committerMarcelo Vanzin <vanzin@cloudera.com>2015-08-19 10:19:24 -0700
commitf3e177917dd093873dca286d2419704a561ba44b (patch)
tree84515bde37406f92535bcefd2ee8fbccfa482530 /yarn
parent802b5b8791fc2c892810981b2479a04175aa3dcd (diff)
downloadspark-f3e177917dd093873dca286d2419704a561ba44b.tar.gz
spark-f3e177917dd093873dca286d2419704a561ba44b.tar.bz2
spark-f3e177917dd093873dca286d2419704a561ba44b.zip
[SPARK-5754] [YARN] Spark/Yarn/Windows driver/executor escaping Fix
This is my retry to suggest a fix for using Spark on Yarn on Windows. The former request lacked coding style which I hope to have learned to do better, and wasn't a true solution as I didn't really understand where the problem came from. Albeit being still a bit obscure, I can name the "players" and have come up with a better explaination of why I am suggesting this fix. I also used vanzin and srowen input to *try* to give a more elegant solution. I am not so sure if that worked out though. I still hope that this PR is a lot more useful than the last. Also do I hope that this is a _solution_ to the problem that Spark doesn't work on Yarn on Windows. With these changes it works (and I can also explain why!). I still believe that a Unit Test should be included, kind of like the one I committed the last time. But that was premature, as I want to get the principal 'Go' from vanzin and srowen. Thanks for your time both of you. Author: Carsten Blank <blank@cncengine.com> Author: cbvoxel <blank@cncengine.com> Closes #8053 from cbvoxel/master.
Diffstat (limited to 'yarn')
-rw-r--r--yarn/src/main/scala/org/apache/spark/deploy/yarn/Client.scala2
-rw-r--r--yarn/src/main/scala/org/apache/spark/deploy/yarn/ExecutorRunnable.scala2
-rw-r--r--yarn/src/main/scala/org/apache/spark/deploy/yarn/YarnSparkHadoopUtil.scala56
-rw-r--r--yarn/src/main/scala/org/apache/spark/launcher/YarnCommandBuilderUtils.scala27
4 files changed, 75 insertions, 12 deletions
diff --git a/yarn/src/main/scala/org/apache/spark/deploy/yarn/Client.scala b/yarn/src/main/scala/org/apache/spark/deploy/yarn/Client.scala
index 8672ef6017..262c6a8d63 100644
--- a/yarn/src/main/scala/org/apache/spark/deploy/yarn/Client.scala
+++ b/yarn/src/main/scala/org/apache/spark/deploy/yarn/Client.scala
@@ -431,7 +431,7 @@ private[spark] class Client(
}
// Distribute an archive with Hadoop and Spark configuration for the AM.
- val (_, confLocalizedPath) = distribute(createConfArchive().getAbsolutePath(),
+ val (_, confLocalizedPath) = distribute(createConfArchive().toURI().getPath(),
resType = LocalResourceType.ARCHIVE,
destName = Some(LOCALIZED_CONF_DIR),
appMasterOnly = true)
diff --git a/yarn/src/main/scala/org/apache/spark/deploy/yarn/ExecutorRunnable.scala b/yarn/src/main/scala/org/apache/spark/deploy/yarn/ExecutorRunnable.scala
index 52580deb37..4cc50483a1 100644
--- a/yarn/src/main/scala/org/apache/spark/deploy/yarn/ExecutorRunnable.scala
+++ b/yarn/src/main/scala/org/apache/spark/deploy/yarn/ExecutorRunnable.scala
@@ -217,7 +217,7 @@ class ExecutorRunnable(
// an inconsistent state.
// TODO: If the OOM is not recoverable by rescheduling it on different node, then do
// 'something' to fail job ... akin to blacklisting trackers in mapred ?
- "-XX:OnOutOfMemoryError='kill %p'") ++
+ YarnSparkHadoopUtil.getOutOfMemoryErrorArgument) ++
javaOpts ++
Seq("org.apache.spark.executor.CoarseGrainedExecutorBackend",
"--driver-url", masterAddress.toString,
diff --git a/yarn/src/main/scala/org/apache/spark/deploy/yarn/YarnSparkHadoopUtil.scala b/yarn/src/main/scala/org/apache/spark/deploy/yarn/YarnSparkHadoopUtil.scala
index 68d01c17ef..445d3dcd26 100644
--- a/yarn/src/main/scala/org/apache/spark/deploy/yarn/YarnSparkHadoopUtil.scala
+++ b/yarn/src/main/scala/org/apache/spark/deploy/yarn/YarnSparkHadoopUtil.scala
@@ -37,6 +37,7 @@ import org.apache.hadoop.yarn.api.records.{ApplicationAccessType, ContainerId, P
import org.apache.hadoop.yarn.util.ConverterUtils
import org.apache.spark.deploy.SparkHadoopUtil
+import org.apache.spark.launcher.YarnCommandBuilderUtils
import org.apache.spark.{SecurityManager, SparkConf, SparkException}
import org.apache.spark.util.Utils
@@ -220,25 +221,60 @@ object YarnSparkHadoopUtil {
}
/**
+ * The handler if an OOM Exception is thrown by the JVM must be configured on Windows
+ * differently: the 'taskkill' command should be used, whereas Unix-based systems use 'kill'.
+ *
+ * As the JVM interprets both %p and %%p as the same, we can use either of them. However,
+ * some tests on Windows computers suggest, that the JVM only accepts '%%p'.
+ *
+ * Furthermore, the behavior of the character '%' on the Windows command line differs from
+ * the behavior of '%' in a .cmd file: it gets interpreted as an incomplete environment
+ * variable. Windows .cmd files escape a '%' by '%%'. Thus, the correct way of writing
+ * '%%p' in an escaped way is '%%%%p'.
+ *
+ * @return The correct OOM Error handler JVM option, platform dependent.
+ */
+ def getOutOfMemoryErrorArgument : String = {
+ if (Utils.isWindows) {
+ escapeForShell("-XX:OnOutOfMemoryError=taskkill /F /PID %%%%p")
+ } else {
+ "-XX:OnOutOfMemoryError='kill %p'"
+ }
+ }
+
+ /**
* Escapes a string for inclusion in a command line executed by Yarn. Yarn executes commands
- * using `bash -c "command arg1 arg2"` and that means plain quoting doesn't really work. The
- * argument is enclosed in single quotes and some key characters are escaped.
+ * using either
+ *
+ * (Unix-based) `bash -c "command arg1 arg2"` and that means plain quoting doesn't really work.
+ * The argument is enclosed in single quotes and some key characters are escaped.
+ *
+ * (Windows-based) part of a .cmd file in which case windows escaping for each argument must be
+ * applied. Windows is quite lenient, however it is usually Java that causes trouble, needing to
+ * distinguish between arguments starting with '-' and class names. If arguments are surrounded
+ * by ' java takes the following string as is, hence an argument is mistakenly taken as a class
+ * name which happens to start with a '-'. The way to avoid this, is to surround nothing with
+ * a ', but instead with a ".
*
* @param arg A single argument.
* @return Argument quoted for execution via Yarn's generated shell script.
*/
def escapeForShell(arg: String): String = {
if (arg != null) {
- val escaped = new StringBuilder("'")
- for (i <- 0 to arg.length() - 1) {
- arg.charAt(i) match {
- case '$' => escaped.append("\\$")
- case '"' => escaped.append("\\\"")
- case '\'' => escaped.append("'\\''")
- case c => escaped.append(c)
+ if (Utils.isWindows) {
+ YarnCommandBuilderUtils.quoteForBatchScript(arg)
+ } else {
+ val escaped = new StringBuilder("'")
+ for (i <- 0 to arg.length() - 1) {
+ arg.charAt(i) match {
+ case '$' => escaped.append("\\$")
+ case '"' => escaped.append("\\\"")
+ case '\'' => escaped.append("'\\''")
+ case c => escaped.append(c)
+ }
}
+ escaped.append("'").toString()
}
- escaped.append("'").toString()
} else {
arg
}
diff --git a/yarn/src/main/scala/org/apache/spark/launcher/YarnCommandBuilderUtils.scala b/yarn/src/main/scala/org/apache/spark/launcher/YarnCommandBuilderUtils.scala
new file mode 100644
index 0000000000..3ac36ef0a1
--- /dev/null
+++ b/yarn/src/main/scala/org/apache/spark/launcher/YarnCommandBuilderUtils.scala
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.spark.launcher
+
+/**
+ * Exposes needed methods
+ */
+private[spark] object YarnCommandBuilderUtils {
+ def quoteForBatchScript(arg: String) : String = {
+ CommandBuilderUtils.quoteForBatchScript(arg)
+ }
+}