You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@oozie.apache.org by rk...@apache.org on 2014/04/24 21:08:48 UTC

git commit: OOZIE-1794 java-opts and java-opt in the Java action don't always work properly in YARN (rkanter)

Repository: oozie
Updated Branches:
  refs/heads/master eed805ec3 -> d77b0d8a7


OOZIE-1794 java-opts and java-opt in the Java action don't always work properly in YARN (rkanter)


Project: http://git-wip-us.apache.org/repos/asf/oozie/repo
Commit: http://git-wip-us.apache.org/repos/asf/oozie/commit/d77b0d8a
Tree: http://git-wip-us.apache.org/repos/asf/oozie/tree/d77b0d8a
Diff: http://git-wip-us.apache.org/repos/asf/oozie/diff/d77b0d8a

Branch: refs/heads/master
Commit: d77b0d8a768508bd165763e7b132fa4cff5fe260
Parents: eed805e
Author: Robert Kanter <rk...@cloudera.com>
Authored: Thu Apr 24 12:05:05 2014 -0700
Committer: Robert Kanter <rk...@cloudera.com>
Committed: Thu Apr 24 12:05:05 2014 -0700

----------------------------------------------------------------------
 .../oozie/action/hadoop/JavaActionExecutor.java |  38 +++---
 .../action/hadoop/TestJavaActionExecutor.java   | 121 +++++++++++++++++--
 .../src/site/twiki/WorkflowFunctionalSpec.twiki |  18 ++-
 3 files changed, 140 insertions(+), 37 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/oozie/blob/d77b0d8a/core/src/main/java/org/apache/oozie/action/hadoop/JavaActionExecutor.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/oozie/action/hadoop/JavaActionExecutor.java b/core/src/main/java/org/apache/oozie/action/hadoop/JavaActionExecutor.java
index 6fcdf2a..59ad143 100644
--- a/core/src/main/java/org/apache/oozie/action/hadoop/JavaActionExecutor.java
+++ b/core/src/main/java/org/apache/oozie/action/hadoop/JavaActionExecutor.java
@@ -280,13 +280,10 @@ public class JavaActionExecutor extends ActionExecutor {
         }
         launcherConf.setInt(YARN_AM_RESOURCE_MB, memoryMB);
 
-        // child.java.opts
-        String launcherMapOpts = launcherConf.get(HADOOP_MAP_JAVA_OPTS);
-        if (launcherMapOpts == null) {
-            launcherMapOpts = launcherConf.get(HADOOP_CHILD_JAVA_OPTS);
-        }
+        // We already made mapred.child.java.opts and mapreduce.map.java.opts equal, so just start with one of them
+        String launcherMapOpts = launcherConf.get(HADOOP_MAP_JAVA_OPTS, "");
         String amChildOpts = launcherConf.get(YARN_AM_COMMAND_OPTS);
-        StringBuffer optsStr = new StringBuffer();
+        StringBuilder optsStr = new StringBuilder();
         int heapSizeForMap = extractHeapSizeMB(launcherMapOpts);
         int heapSizeForAm = extractHeapSizeMB(amChildOpts);
         int heapSize = Math.max(heapSizeForMap, heapSizeForAm) + YARN_MEMORY_MB_MIN;
@@ -297,16 +294,12 @@ public class JavaActionExecutor extends ActionExecutor {
         if (amChildOpts != null) {
             optsStr.append(amChildOpts);
         }
-        if (launcherMapOpts != null) {
-            optsStr.append(" ");
-            optsStr.append(launcherMapOpts);
-        }
+        optsStr.append(" ").append(launcherMapOpts.trim());
         if (heapSize > 0) {
             // append calculated total heap size to the end
-            optsStr.append(" ");
-            optsStr.append("-Xmx" + heapSize + "m");
+            optsStr.append(" ").append("-Xmx").append(heapSize).append("m");
         }
-        launcherConf.set(YARN_AM_COMMAND_OPTS, optsStr.toString());
+        launcherConf.set(YARN_AM_COMMAND_OPTS, optsStr.toString().trim());
 
         // child.env
         String launcherMapEnv = launcherConf.get(HADOOP_MAP_JAVA_ENV);
@@ -759,21 +752,22 @@ public class JavaActionExecutor extends ActionExecutor {
             }
             LauncherMapperHelper.setupMainArguments(launcherJobConf, args);
 
+            // Make mapred.child.java.opts and mapreduce.map.java.opts equal, but give values from the latter priority; also append
+            // <java-opt> and <java-opts> and give those highest priority
+            StringBuilder opts = new StringBuilder(launcherJobConf.get(HADOOP_CHILD_JAVA_OPTS, ""));
+            if (launcherJobConf.get(HADOOP_MAP_JAVA_OPTS) != null) {
+                opts.append(" ").append(launcherJobConf.get(HADOOP_MAP_JAVA_OPTS));
+            }
             List<Element> javaopts = actionXml.getChildren("java-opt", ns);
             for (Element opt: javaopts) {
-                String opts = launcherJobConf.get("mapred.child.java.opts", "");
-                opts = opts + " " + opt.getTextTrim();
-                opts = opts.trim();
-                launcherJobConf.set("mapred.child.java.opts", opts);
+                opts.append(" ").append(opt.getTextTrim());
             }
-
             Element opt = actionXml.getChild("java-opts", ns);
             if (opt != null) {
-                String opts = launcherJobConf.get("mapred.child.java.opts", "");
-                opts = opts + " " + opt.getTextTrim();
-                opts = opts.trim();
-                launcherJobConf.set("mapred.child.java.opts", opts);
+                opts.append(" ").append(opt.getTextTrim());
             }
+            launcherJobConf.set(HADOOP_CHILD_JAVA_OPTS, opts.toString().trim());
+            launcherJobConf.set(HADOOP_MAP_JAVA_OPTS, opts.toString().trim());
 
             // setting for uber mode
             if (launcherJobConf.getBoolean(HADOOP_YARN_UBER_MODE, false)) {

http://git-wip-us.apache.org/repos/asf/oozie/blob/d77b0d8a/core/src/test/java/org/apache/oozie/action/hadoop/TestJavaActionExecutor.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/oozie/action/hadoop/TestJavaActionExecutor.java b/core/src/test/java/org/apache/oozie/action/hadoop/TestJavaActionExecutor.java
index 62c57a8..390ad3f 100644
--- a/core/src/test/java/org/apache/oozie/action/hadoop/TestJavaActionExecutor.java
+++ b/core/src/test/java/org/apache/oozie/action/hadoop/TestJavaActionExecutor.java
@@ -242,6 +242,7 @@ public class TestJavaActionExecutor extends ActionExecutorTestCase {
         assertEquals("MAIN-CLASS", actionConf.get("oozie.action.java.main", "null"));
         assertEquals("org.apache.oozie.action.hadoop.JavaMain", ae.getLauncherMain(conf, actionXml));
         assertTrue(conf.get("mapred.child.java.opts").contains("JAVA-OPTS"));
+        assertTrue(conf.get("mapreduce.map.java.opts").contains("JAVA-OPTS"));
         assertEquals(Arrays.asList("A1", "A2"), Arrays.asList(LauncherMapper.getMainArguments(conf)));
 
         assertTrue(getFileSystem().exists(new Path(context.getActionDir(), LauncherMapper.ACTION_CONF_XML)));
@@ -1061,8 +1062,8 @@ public class TestJavaActionExecutor extends ActionExecutorTestCase {
 
         Configuration conf = ae.createLauncherConf(getFileSystem(), context, action, actionXmlconf, actionConf);
 
-        assertTrue(conf.get("mapred.child.java.opts").contains("JAVA-OPT1"));
-        assertTrue(conf.get("mapred.child.java.opts").contains("JAVA-OPT2"));
+        assertEquals("-Xmx200m JAVA-OPT1 JAVA-OPT2", conf.get("mapred.child.java.opts"));
+        assertEquals("-Xmx200m JAVA-OPT1 JAVA-OPT2", conf.get("mapreduce.map.java.opts"));
 
         actionXml = "<java>" + "<job-tracker>" + getJobTrackerUri() + "</job-tracker>" + "<name-node>"
                 + getNameNodeUri() + "</name-node>" + "<job-xml>job.xml</job-xml>" + "<job-xml>job2.xml</job-xml>"
@@ -1086,8 +1087,90 @@ public class TestJavaActionExecutor extends ActionExecutorTestCase {
 
         conf = ae.createLauncherConf(getFileSystem(), context, action, actionXmlconf, actionConf);
 
-        assertTrue(conf.get("mapred.child.java.opts").contains("JAVA-OPT1"));
-        assertTrue(conf.get("mapred.child.java.opts").contains("JAVA-OPT2"));
+        assertEquals("-Xmx200m JAVA-OPT1 JAVA-OPT2", conf.get("mapred.child.java.opts"));
+        assertEquals("-Xmx200m JAVA-OPT1 JAVA-OPT2", conf.get("mapreduce.map.java.opts"));
+
+        actionXml = "<java>" + "<job-tracker>" + getJobTrackerUri() + "</job-tracker>" + "<name-node>"
+                + getNameNodeUri() + "</name-node>" + "<job-xml>job.xml</job-xml>" + "<job-xml>job2.xml</job-xml>"
+                + "<configuration>" + "<property><name>oozie.launcher.a</name><value>LA</value></property>"
+                + "<property><name>a</name><value>AA</value></property>"
+                + "<property><name>b</name><value>BB</value></property>"
+                + "<property><name>oozie.launcher.mapred.child.java.opts</name><value>JAVA-OPT3</value></property>"
+                + "</configuration>"
+                + "<main-class>MAIN-CLASS</main-class>" + "<java-opt>JAVA-OPT1</java-opt>"
+                + "<java-opt>JAVA-OPT2</java-opt>" + "<arg>A1</arg>" + "<arg>A2</arg>" + "<file>f.jar</file>"
+                + "<archive>a.tar</archive>" + "</java>";
+
+        wfBean = addRecordToWfJobTable("test1", actionXml);
+        action = (WorkflowActionBean) wfBean.getActions().get(0);
+        action.setType(ae.getType());
+        action.setConf(actionXml);
+
+        context = new Context(wfBean, action);
+
+        actionXmlconf = XmlUtils.parseXml(action.getConf());
+
+        actionConf = ae.createBaseHadoopConf(context, actionXmlconf);
+
+        conf = ae.createLauncherConf(getFileSystem(), context, action, actionXmlconf, actionConf);
+
+        assertEquals("JAVA-OPT3 JAVA-OPT1 JAVA-OPT2", conf.get("mapred.child.java.opts"));
+        assertEquals("JAVA-OPT3 JAVA-OPT1 JAVA-OPT2", conf.get("mapreduce.map.java.opts"));
+
+        actionXml = "<java>" + "<job-tracker>" + getJobTrackerUri() + "</job-tracker>" + "<name-node>"
+                + getNameNodeUri() + "</name-node>" + "<job-xml>job.xml</job-xml>" + "<job-xml>job2.xml</job-xml>"
+                + "<configuration>" + "<property><name>oozie.launcher.a</name><value>LA</value></property>"
+                + "<property><name>a</name><value>AA</value></property>"
+                + "<property><name>b</name><value>BB</value></property>"
+                + "<property><name>oozie.launcher.mapreduce.map.java.opts</name><value>JAVA-OPT3</value></property>"
+                + "</configuration>"
+                + "<main-class>MAIN-CLASS</main-class>" + "<java-opt>JAVA-OPT1</java-opt>"
+                + "<java-opt>JAVA-OPT2</java-opt>" + "<arg>A1</arg>" + "<arg>A2</arg>" + "<file>f.jar</file>"
+                + "<archive>a.tar</archive>" + "</java>";
+
+        wfBean = addRecordToWfJobTable("test1", actionXml);
+        action = (WorkflowActionBean) wfBean.getActions().get(0);
+        action.setType(ae.getType());
+        action.setConf(actionXml);
+
+        context = new Context(wfBean, action);
+
+        actionXmlconf = XmlUtils.parseXml(action.getConf());
+
+        actionConf = ae.createBaseHadoopConf(context, actionXmlconf);
+
+        conf = ae.createLauncherConf(getFileSystem(), context, action, actionXmlconf, actionConf);
+
+        assertEquals("-Xmx200m JAVA-OPT3 JAVA-OPT1 JAVA-OPT2", conf.get("mapred.child.java.opts"));
+        assertEquals("-Xmx200m JAVA-OPT3 JAVA-OPT1 JAVA-OPT2", conf.get("mapreduce.map.java.opts"));
+
+        actionXml = "<java>" + "<job-tracker>" + getJobTrackerUri() + "</job-tracker>" + "<name-node>"
+                + getNameNodeUri() + "</name-node>" + "<job-xml>job.xml</job-xml>" + "<job-xml>job2.xml</job-xml>"
+                + "<configuration>" + "<property><name>oozie.launcher.a</name><value>LA</value></property>"
+                + "<property><name>a</name><value>AA</value></property>"
+                + "<property><name>b</name><value>BB</value></property>"
+                + "<property><name>oozie.launcher.mapred.child.java.opts</name><value>JAVA-OPT3</value></property>"
+                + "<property><name>oozie.launcher.mapreduce.map.java.opts</name><value>JAVA-OPT4</value></property>"
+                + "</configuration>"
+                + "<main-class>MAIN-CLASS</main-class>" + "<java-opt>JAVA-OPT1</java-opt>"
+                + "<java-opt>JAVA-OPT2</java-opt>" + "<arg>A1</arg>" + "<arg>A2</arg>" + "<file>f.jar</file>"
+                + "<archive>a.tar</archive>" + "</java>";
+
+        wfBean = addRecordToWfJobTable("test1", actionXml);
+        action = (WorkflowActionBean) wfBean.getActions().get(0);
+        action.setType(ae.getType());
+        action.setConf(actionXml);
+
+        context = new Context(wfBean, action);
+
+        actionXmlconf = XmlUtils.parseXml(action.getConf());
+
+        actionConf = ae.createBaseHadoopConf(context, actionXmlconf);
+
+        conf = ae.createLauncherConf(getFileSystem(), context, action, actionXmlconf, actionConf);
+
+        assertEquals("JAVA-OPT3 JAVA-OPT4 JAVA-OPT1 JAVA-OPT2", conf.get("mapred.child.java.opts"));
+        assertEquals("JAVA-OPT3 JAVA-OPT4 JAVA-OPT1 JAVA-OPT2", conf.get("mapreduce.map.java.opts"));
     }
 
     public void testActionLibsPath() throws Exception {
@@ -1624,6 +1707,8 @@ public class TestJavaActionExecutor extends ActionExecutorTestCase {
         assertEquals("2560", launcherConf.get(JavaActionExecutor.YARN_AM_RESOURCE_MB));
         // heap size in child.opts (2048 + 512)
         int heapSize = ae.extractHeapSizeMB(launcherConf.get(JavaActionExecutor.YARN_AM_COMMAND_OPTS));
+        assertEquals("-Xmx2048m -Djava.net.preferIPv4Stack=true", launcherConf.get("mapred.child.java.opts"));
+        assertEquals("-Xmx2048m -Djava.net.preferIPv4Stack=true", launcherConf.get("mapreduce.map.java.opts"));
         // There's an extra parameter (-Xmx1024m) in here when using YARN that's not here when using MR1
         if (createJobConf().get("yarn.resourcemanager.address") != null) {
             assertEquals("-Xmx1024m -Xmx2048m -Djava.net.preferIPv4Stack=true -Xmx2560m",
@@ -1633,6 +1718,7 @@ public class TestJavaActionExecutor extends ActionExecutorTestCase {
             assertEquals("-Xmx2048m -Djava.net.preferIPv4Stack=true -Xmx2560m",
                     launcherConf.get(JavaActionExecutor.YARN_AM_COMMAND_OPTS).trim());
         }
+        assertEquals(2560, heapSize);
 
         // env
         assertEquals("A=foo", launcherConf.get(JavaActionExecutor.YARN_AM_ENV));
@@ -1664,7 +1750,9 @@ public class TestJavaActionExecutor extends ActionExecutorTestCase {
 
         // heap size (2560 + 512)
         heapSize = ae.extractHeapSizeMB(launcherConf.get(JavaActionExecutor.YARN_AM_COMMAND_OPTS));
-        assertEquals("-Xmx1024m -Djava.net.preferIPv4Stack=true -Xmx2560m -XX:NewRatio=8 -Xmx3072m",
+        assertEquals("-Xmx1536m -Xmx2560m -XX:NewRatio=8", launcherConf.get("mapred.child.java.opts"));
+        assertEquals("-Xmx1536m -Xmx2560m -XX:NewRatio=8", launcherConf.get("mapreduce.map.java.opts"));
+        assertEquals("-Xmx1024m -Djava.net.preferIPv4Stack=true -Xmx1536m -Xmx2560m -XX:NewRatio=8 -Xmx3072m",
                 launcherConf.get(JavaActionExecutor.YARN_AM_COMMAND_OPTS).trim());
         assertEquals(3072, heapSize);
 
@@ -1700,8 +1788,11 @@ public class TestJavaActionExecutor extends ActionExecutorTestCase {
 
         // heap size (limit to 3584)
         heapSize = ae.extractHeapSizeMB(launcherConf.get(JavaActionExecutor.YARN_AM_COMMAND_OPTS));
-        assertEquals("-Xmx1024m -Djava.net.preferIPv4Stack=true -Xmx4000m -XX:NewRatio=8 -Xmx3584m",
+        assertEquals("-Xmx1536m -Xmx4000m -XX:NewRatio=8", launcherConf.get("mapred.child.java.opts"));
+        assertEquals("-Xmx1536m -Xmx4000m -XX:NewRatio=8", launcherConf.get("mapreduce.map.java.opts"));
+        assertEquals("-Xmx1024m -Djava.net.preferIPv4Stack=true -Xmx1536m -Xmx4000m -XX:NewRatio=8 -Xmx3584m",
                 launcherConf.get(JavaActionExecutor.YARN_AM_COMMAND_OPTS).trim());
+        assertEquals(3584, heapSize);
 
         // env (equqls to mapreduce.map.env + am.env)
         assertEquals("A=foo,B=bar", launcherConf.get(JavaActionExecutor.YARN_AM_ENV));
@@ -1721,7 +1812,7 @@ public class TestJavaActionExecutor extends ActionExecutorTestCase {
                         + "<configuration>"
                         + "<property><name>oozie.launcher.yarn.app.mapreduce.am.command-opts</name>"
                         + "<value>-Xmx1024m -Djava.net.preferIPv4Stack=true </value></property>"
-                        + "<property><name>oozie.launcher.mapred.child.java.opts</name><value>-Xmx1536m</value></property>"
+                        + "<property><name>oozie.launcher.mapreduce.map.java.opts</name><value>-Xmx1536m</value></property>"
                         + "</configuration>" + "<main-class>MAIN-CLASS</main-class>"
                         + "<java-opt>-Xmx2048m</java-opt>"
                         + "<java-opt>-Dkey1=val1</java-opt>"
@@ -1741,7 +1832,9 @@ public class TestJavaActionExecutor extends ActionExecutorTestCase {
 
         // heap size (2048 + 512)
         int heapSize = ae.extractHeapSizeMB(launcherConf.get(JavaActionExecutor.YARN_AM_COMMAND_OPTS));
-        assertEquals("-Xmx1024m -Djava.net.preferIPv4Stack=true -Xmx1536m -Xmx2048m -Dkey1=val1 -Dkey2=val2 -Xmx2560m",
+        assertEquals("-Xmx200m -Xmx1536m -Xmx2048m -Dkey1=val1 -Dkey2=val2", launcherConf.get("mapred.child.java.opts"));
+        assertEquals("-Xmx200m -Xmx1536m -Xmx2048m -Dkey1=val1 -Dkey2=val2", launcherConf.get("mapreduce.map.java.opts"));
+        assertEquals("-Xmx1024m -Djava.net.preferIPv4Stack=true -Xmx200m -Xmx1536m -Xmx2048m -Dkey1=val1 -Dkey2=val2 -Xmx2560m",
                 launcherConf.get(JavaActionExecutor.YARN_AM_COMMAND_OPTS).trim());
         assertEquals(2560, heapSize);
 
@@ -1756,7 +1849,7 @@ public class TestJavaActionExecutor extends ActionExecutorTestCase {
                         + "<configuration>"
                         + "<property><name>oozie.launcher.yarn.app.mapreduce.am.command-opts</name>"
                         + "<value>-Xmx1024m -Djava.net.preferIPv4Stack=true </value></property>"
-                        + "<property><name>oozie.launcher.mapred.child.java.opts</name><value>-Xmx1536m</value></property>"
+                        + "<property><name>oozie.launcher.mapreduce.map.java.opts</name><value>-Xmx1536m</value></property>"
                         + "</configuration>" + "<main-class>MAIN-CLASS</main-class>"
                         + "<java-opts>-Xmx2048m -Dkey1=val1</java-opts>"
                         + "</java>");
@@ -1765,7 +1858,9 @@ public class TestJavaActionExecutor extends ActionExecutorTestCase {
 
         // heap size (2048 + 512)
         heapSize = ae.extractHeapSizeMB(launcherConf.get(JavaActionExecutor.YARN_AM_COMMAND_OPTS));
-        assertEquals("-Xmx1024m -Djava.net.preferIPv4Stack=true -Xmx1536m -Xmx2048m -Dkey1=val1 -Xmx2560m",
+        assertEquals("-Xmx200m -Xmx1536m -Xmx2048m -Dkey1=val1", launcherConf.get("mapred.child.java.opts"));
+        assertEquals("-Xmx200m -Xmx1536m -Xmx2048m -Dkey1=val1", launcherConf.get("mapreduce.map.java.opts"));
+        assertEquals("-Xmx1024m -Djava.net.preferIPv4Stack=true -Xmx200m -Xmx1536m -Xmx2048m -Dkey1=val1 -Xmx2560m",
                 launcherConf.get(JavaActionExecutor.YARN_AM_COMMAND_OPTS).trim());
         assertEquals(2560, heapSize);
 
@@ -1780,7 +1875,7 @@ public class TestJavaActionExecutor extends ActionExecutorTestCase {
                         + "<configuration>"
                         + "<property><name>oozie.launcher.yarn.app.mapreduce.am.command-opts</name>"
                         + "<value>-Xmx2048m -Djava.net.preferIPv4Stack=true </value></property>"
-                        + "<property><name>oozie.launcher.mapred.child.java.opts</name><value>-Xmx3072m</value></property>"
+                        + "<property><name>oozie.launcher.mapreduce.map.java.opts</name><value>-Xmx3072m</value></property>"
                         + "</configuration>" + "<main-class>MAIN-CLASS</main-class>"
                         + "<java-opts>-Xmx1024m -Dkey1=val1</java-opts>"
                         + "</java>");
@@ -1789,7 +1884,9 @@ public class TestJavaActionExecutor extends ActionExecutorTestCase {
 
         // heap size (2048 + 512)
         heapSize = ae.extractHeapSizeMB(launcherConf.get(JavaActionExecutor.YARN_AM_COMMAND_OPTS));
-        assertEquals("-Xmx2048m -Djava.net.preferIPv4Stack=true -Xmx3072m -Xmx1024m -Dkey1=val1 -Xmx2560m",
+        assertEquals("-Xmx200m -Xmx3072m -Xmx1024m -Dkey1=val1", launcherConf.get("mapred.child.java.opts"));
+        assertEquals("-Xmx200m -Xmx3072m -Xmx1024m -Dkey1=val1", launcherConf.get("mapreduce.map.java.opts"));
+        assertEquals("-Xmx2048m -Djava.net.preferIPv4Stack=true -Xmx200m -Xmx3072m -Xmx1024m -Dkey1=val1 -Xmx2560m",
                 launcherConf.get(JavaActionExecutor.YARN_AM_COMMAND_OPTS).trim());
         assertEquals(2560, heapSize);
     }

http://git-wip-us.apache.org/repos/asf/oozie/blob/d77b0d8a/docs/src/site/twiki/WorkflowFunctionalSpec.twiki
----------------------------------------------------------------------
diff --git a/docs/src/site/twiki/WorkflowFunctionalSpec.twiki b/docs/src/site/twiki/WorkflowFunctionalSpec.twiki
index 40dcd1f..f7590d0 100644
--- a/docs/src/site/twiki/WorkflowFunctionalSpec.twiki
+++ b/docs/src/site/twiki/WorkflowFunctionalSpec.twiki
@@ -1421,9 +1421,21 @@ hcat://[metastore server]:[port]/[database name]/[table name]/[partkey1]=[value]
 In case of a hcatalog URI, the hive-site.xml needs to be shipped using =file= tag and the hcatalog and hive jars
 need to be placed in workflow lib directory or specified using =archive= tag.
 
-The =java-opts= element, if present, contains the command line parameters which are to be used to start the JVM that
-will execute the Java application. Using this element is equivalent to use the =mapred.child.java.opts= configuration
-property.
+The =java-opts= and =java-opt= elements, if present, contains the command line parameters which are to be used to start the JVM that
+will execute the Java application. Using this element is equivalent to using the =mapred.child.java.opts=
+or =mapreduce.map.java.opts= configuration properties, with the advantage that Oozie will append to these properties instead of
+simply setting them (e.g. if you have one of these properties specified in mapred-site.xml, setting it again in
+the =configuration= element will override it, but using =java-opts= or =java-opt= will instead append to it, preserving the original
+value).  You can have either one =java-opts=, multiple =java-opt=, or neither; you cannot use both at the same time.  In any case,
+Oozie will set both =mapred.child.java.opts= and =mapreduce.map.java.opts= to the same value based on combining them.  In other
+words, after Oozie is finished:
+<verbatim>
+mapred.child.java.opts  <-- "<mapred.child.java.opts> <mapreduce.map.java.opts> <java-opt...|java-opts>"
+mapreduce.map.java.opts <-- "<mapred.child.java.opts> <mapreduce.map.java.opts> <java-opt...|java-opts>"
+</verbatim>
+In the case that parameters are repeated, the latest instance of the parameter is used by Java.  This means that =java-opt=
+(or =java-opts=) has the highest priority, followed by =mapreduce.map.java.opts=, and finally =mapred.child.java.opts=.  When
+multiple =java-opt= are specified, they are included from top to bottom ordering, where the bottom has highest priority.
 
 The =arg= elements, if present, contains arguments for the main function. The value of each =arg= element is considered
 a single argument and they are passed to the =main= method in the same order.