This is an automated email from the ASF dual-hosted git repository.

asalamon74 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/oozie.git


The following commit(s) were added to refs/heads/master by this push:
     new 06cf2cf  OOZIE-3561 Forkjoin validation is slow when there are many 
actions in chain (dionusos, pbacsko via asalamon74)
06cf2cf is described below

commit 06cf2cf005b3f98bcd40a1111934a02b530fac07
Author: Andras Salamon <[email protected]>
AuthorDate: Wed Nov 27 12:29:18 2019 +0100

    OOZIE-3561 Forkjoin validation is slow when there are many actions in chain 
(dionusos, pbacsko via asalamon74)
---
 .../oozie/workflow/lite/LiteWorkflowValidator.java |  63 ++++++++++---
 .../workflow/lite/TestLiteWorkflowAppParser.java   |  69 ++++++++++++++
 core/src/test/resources/wf-actions-20.xml          |  43 +++++++++
 core/src/test/resources/wf-actions-40.xml          |  63 +++++++++++++
 core/src/test/resources/wf-actions-80.xml          | 102 +++++++++++++++++++++
 release-log.txt                                    |   1 +
 6 files changed, 330 insertions(+), 11 deletions(-)

diff --git 
a/core/src/main/java/org/apache/oozie/workflow/lite/LiteWorkflowValidator.java 
b/core/src/main/java/org/apache/oozie/workflow/lite/LiteWorkflowValidator.java
index eceb019..e6102d8 100644
--- 
a/core/src/main/java/org/apache/oozie/workflow/lite/LiteWorkflowValidator.java
+++ 
b/core/src/main/java/org/apache/oozie/workflow/lite/LiteWorkflowValidator.java
@@ -34,12 +34,14 @@ import org.apache.oozie.ErrorCode;
 import org.apache.oozie.service.ActionService;
 import org.apache.oozie.service.Services;
 import org.apache.oozie.util.ParamChecker;
+import org.apache.oozie.util.XLog;
 import org.apache.oozie.util.XmlUtils;
 import org.apache.oozie.workflow.WorkflowException;
 import org.jdom.Element;
 import org.jdom.JDOMException;
 
 public class LiteWorkflowValidator {
+    private static XLog LOG = XLog.getLog(LiteWorkflowValidator.class);
 
     public void validateWorkflow(LiteWorkflowApp app, boolean 
validateForkJoin) throws WorkflowException {
         NodeDef startNode = app.getNode(StartNodeDef.START);
@@ -64,7 +66,8 @@ public class LiteWorkflowValidator {
                     true,
                     new ArrayDeque<String>(),
                     new HashMap<String, String>(),
-                    new HashMap<String, Optional<String>>());
+                    new HashMap<String, Optional<String>>(),
+                    new HashSet<>());
         }
     }
 
@@ -135,11 +138,18 @@ public class LiteWorkflowValidator {
      * already been visited at least once before
      * @param forkJoins Map that contains a mapping of fork-join node pairs.
      * @param nodeAndDecisionParents Map that contains a mapping of nodes and 
their eldest decision node
+     * @param visitedNodes contains the nodes that have been already visited & 
validated (except Join/End nodes)
      * @throws WorkflowException If there is any of the constraints described 
above is violated
      */
-    private void validateForkJoin(LiteWorkflowApp app, NodeDef node, NodeDef 
currentFork, String topDecisionParent,
-            boolean okPath, Deque<String> path, Map<String, String> forkJoins,
-            Map<String, Optional<String>> nodeAndDecisionParents) throws 
WorkflowException {
+    private void validateForkJoin(LiteWorkflowApp app,
+            NodeDef node,
+            NodeDef currentFork,
+            String topDecisionParent,
+            boolean okPath,
+            Deque<String> path,
+            Map<String, String> forkJoins,
+            Map<String, Optional<String>> nodeAndDecisionParents,
+            Set<NodeDef> visitedNodes) throws WorkflowException {
         final String nodeName = node.getName();
 
         path.addLast(nodeName);
@@ -186,6 +196,33 @@ public class LiteWorkflowValidator {
             }
         }
 
+        /* Memoization part: don't re-walk paths that have been visited 
already. This prevents
+         * exponential runtime in specific cases.
+         *
+         * There are three edge-cases that we have to keep in mind:
+         * 1. This part of the code cannot be above the "okTo" verification 
part. Otherwise we would
+         * accept WFs where multiple "ok" paths lead to the same node.
+         *
+         * 2. We don't store Join nodes. Firstly, we don't recurse from Join 
nodes anyway.
+         * Also, it's necessary to reach fork-join mapping verification below,
+         * so that we can throw errors "E0742" or "E0758" if needed.
+         *
+         * 3. We don't store End nodes. Similarly to Join, no recursion occurs 
after End. Plus, we
+         * could miss the erroneous condition "E0737" if we previously arrived 
at End from a valid path.
+         */
+        if (visitedNodes.contains(node)) {
+            LOG.debug("Skipping node because it's been validated: " + 
nodeName);
+            path.remove(nodeName);
+            return;
+        } else {
+            if (node instanceof JoinNodeDef || node instanceof EndNodeDef) {
+                LOG.debug("Not storing node because it's a Join or End: " + 
nodeName);
+            } else {
+                visitedNodes.add(node);
+                LOG.debug("Storing node as visited: " + nodeName);
+            }
+        }
+
         /* Fork-Join validation logic:
          *
          * At each Fork node, we recurse to every possible paths, changing the 
"currentFork" variable to the Fork node. We stop
@@ -211,7 +248,8 @@ public class LiteWorkflowValidator {
 
             for (String t : transitions) {
                 NodeDef transition = app.getNode(t);
-                validateForkJoin(app, transition, node, topDecisionParent, 
okPath, path, forkJoins, nodeAndDecisionParents);
+                validateForkJoin(app, transition, node, topDecisionParent, 
okPath, path, forkJoins, nodeAndDecisionParents,
+                        visitedNodes);
             }
 
             // get the Join node for this ForkNode & validate it (we must have 
only one)
@@ -222,7 +260,8 @@ public class LiteWorkflowValidator {
             List<String> joinTransitions = 
app.getNode(joins.iterator().next()).getTransitions();
             NodeDef next = app.getNode(joinTransitions.get(0));
 
-            validateForkJoin(app, next, currentFork, topDecisionParent, 
okPath, path, forkJoins, nodeAndDecisionParents);
+            validateForkJoin(app, next, currentFork, topDecisionParent, 
okPath, path, forkJoins, nodeAndDecisionParents,
+                    visitedNodes);
         } else if (node instanceof JoinNodeDef) {
             if (currentFork == null) {
                 throw new WorkflowException(ErrorCode.E0742, node.getName());
@@ -247,7 +286,7 @@ public class LiteWorkflowValidator {
             for (String t : transitions) {
                 NodeDef transition = app.getNode(t);
                 validateForkJoin(app, transition, currentFork, 
parentDecisionNode, okPath, path, forkJoins,
-                        nodeAndDecisionParents);
+                        nodeAndDecisionParents, visitedNodes);
             }
         } else if (node instanceof KillNodeDef) {
             // no op
@@ -262,19 +301,21 @@ public class LiteWorkflowValidator {
         } else if (node instanceof ActionNodeDef) {
             String transition = node.getTransitions().get(0);   // "ok to" 
transition
             NodeDef okNode = app.getNode(transition);
-            validateForkJoin(app, okNode, currentFork, topDecisionParent, 
okPath, path, forkJoins, nodeAndDecisionParents);
+            validateForkJoin(app, okNode, currentFork, topDecisionParent, 
okPath, path, forkJoins, nodeAndDecisionParents,
+                    visitedNodes);
 
             transition = node.getTransitions().get(1);          // "error to" 
transition
             NodeDef errorNode = app.getNode(transition);
-            validateForkJoin(app, errorNode, currentFork, topDecisionParent, 
false, path, forkJoins, nodeAndDecisionParents);
+            validateForkJoin(app, errorNode, currentFork, topDecisionParent, 
false, path, forkJoins, nodeAndDecisionParents,
+                    visitedNodes);
         } else if (node instanceof StartNodeDef) {
             String transition = node.getTransitions().get(0);   // start 
always has only 1 transition
             NodeDef tranNode = app.getNode(transition);
-            validateForkJoin(app, tranNode, currentFork, topDecisionParent, 
okPath, path, forkJoins, nodeAndDecisionParents);
+            validateForkJoin(app, tranNode, currentFork, topDecisionParent, 
okPath, path, forkJoins, nodeAndDecisionParents,
+                    visitedNodes);
         } else {
             throw new WorkflowException(ErrorCode.E0740, node.getClass());
         }
-
         path.remove(nodeName);
     }
 
diff --git 
a/core/src/test/java/org/apache/oozie/workflow/lite/TestLiteWorkflowAppParser.java
 
b/core/src/test/java/org/apache/oozie/workflow/lite/TestLiteWorkflowAppParser.java
index 1389d3e..157d406 100644
--- 
a/core/src/test/java/org/apache/oozie/workflow/lite/TestLiteWorkflowAppParser.java
+++ 
b/core/src/test/java/org/apache/oozie/workflow/lite/TestLiteWorkflowAppParser.java
@@ -1292,6 +1292,75 @@ public class TestLiteWorkflowAppParser extends XTestCase 
{
         }
     }
 
+    public void testMultiplePathsToEnd() throws Exception {
+        // Makes sure that despite using memoization, the validator
+        // still finds incorrect state transition to "end" nodes
+        LiteWorkflowAppParser parser = newLiteWorkflowAppParser();
+
+        LiteWorkflowApp def = new LiteWorkflowApp("name", "def",
+                new 
StartNodeDef(LiteWorkflowStoreService.LiteControlNodeHandler.class, "one"))
+                .addNode(new ActionNodeDef("one", dummyConf, 
TestActionNodeHandler.class, "end", "f"))
+                .addNode(new ForkNodeDef("f", 
LiteWorkflowStoreService.LiteControlNodeHandler.class,
+                        Arrays.asList(new String[]{"two", "three"})))
+                .addNode(new ActionNodeDef("two", dummyConf, 
TestActionNodeHandler.class, "end", "k")) // invalid
+                .addNode(new ActionNodeDef("three", dummyConf, 
TestActionNodeHandler.class, "j", "k"))
+                .addNode(new JoinNodeDef("j", 
LiteWorkflowStoreService.LiteControlNodeHandler.class, "end"))
+                .addNode(new KillNodeDef("k", "kill", 
LiteWorkflowStoreService.LiteControlNodeHandler.class))
+                .addNode(new EndNodeDef("end", 
LiteWorkflowStoreService.LiteControlNodeHandler.class));
+
+        try {
+            invokeForkJoin(parser, def);
+            fail("Expected to catch an exception but did not encounter any");
+        } catch (WorkflowException we) {
+            assertEquals(ErrorCode.E0737, we.getErrorCode());
+            assertTrue(we.getMessage().contains("[two]"));
+        }
+    }
+
+    public void testRuntimeWith20Actions() throws Exception {
+        testRuntimeWithActions("wf-actions-20.xml");
+    }
+
+    public void testRuntimeWith40Actions() throws Exception {
+        testRuntimeWithActions("wf-actions-40.xml");
+    }
+
+    public void testRuntimeWith80Actions() throws Exception {
+        testRuntimeWithActions("wf-actions-80.xml");
+    }
+
+    @SuppressWarnings("deprecation")
+    private void testRuntimeWithActions(String workflowXml) throws Exception {
+        LiteWorkflowAppParser parser = newLiteWorkflowAppParser();
+
+        final AtomicBoolean failure = new AtomicBoolean(false);
+        final AtomicBoolean finished = new AtomicBoolean(false);
+
+        Runnable r = () -> {
+            try {
+                parser.validateAndParse(IOUtils.getResourceAsReader(
+                        workflowXml, -1), new Configuration());
+            } catch (final Exception e) {
+                e.printStackTrace();
+                failure.set(true);
+            }
+
+            finished.set(true);
+        };
+
+        Thread t = new Thread(r);
+        t.setName("Workflow validator thread for " + workflowXml);
+        t.start();
+        t.join((long) (2000 * XTestCase.WAITFOR_RATIO));
+
+        if (!finished.get()) {
+            t.stop();  // don't let the validation keep running in the 
background which causes high CPU load
+            fail("Workflow validation did not finish in time");
+        }
+
+        assertFalse("Workflow validation failed", failure.get());
+    }
+
     private void invokeForkJoin(LiteWorkflowAppParser parser, LiteWorkflowApp 
def) throws WorkflowException {
         LiteWorkflowValidator validator = new LiteWorkflowValidator();
         validator.validateWorkflow(def, true);
diff --git a/core/src/test/resources/wf-actions-20.xml 
b/core/src/test/resources/wf-actions-20.xml
new file mode 100644
index 0000000..645fdb3
--- /dev/null
+++ b/core/src/test/resources/wf-actions-20.xml
@@ -0,0 +1,43 @@
+<!--
+  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.
+-->
+<workflow-app xmlns="uri:oozie:workflow:0.5" name="test-wf">
+    <start to="a1"/>
+
+    <action name="a1"><fs><mkdir path='/tmp'/></fs><ok to="a2"/><error 
to="a2"/></action>
+    <action name="a2"><fs><mkdir path='/tmp'/></fs><ok to="a3"/><error 
to="a3"/></action>
+    <action name="a3"><fs><mkdir path='/tmp'/></fs><ok to="a4"/><error 
to="a4"/></action>
+    <action name="a4"><fs><mkdir path='/tmp'/></fs><ok to="a5"/><error 
to="a5"/></action>
+    <action name="a5"><fs><mkdir path='/tmp'/></fs><ok to="a6"/><error 
to="a6"/></action>
+    <action name="a6"><fs><mkdir path='/tmp'/></fs><ok to="a7"/><error 
to="a7"/></action>
+    <action name="a7"><fs><mkdir path='/tmp'/></fs><ok to="a8"/><error 
to="a8"/></action>
+    <action name="a8"><fs><mkdir path='/tmp'/></fs><ok to="a9"/><error 
to="a9"/></action>
+    <action name="a9"><fs><mkdir path='/tmp'/></fs><ok to="a10"/><error 
to="a10"/></action>
+    <action name="a10"><fs><mkdir path='/tmp'/></fs><ok to="a11"/><error 
to="a11"/></action>
+    <action name="a11"><fs><mkdir path='/tmp'/></fs><ok to="a12"/><error 
to="a12"/></action>
+    <action name="a12"><fs><mkdir path='/tmp'/></fs><ok to="a13"/><error 
to="a13"/></action>
+    <action name="a13"><fs><mkdir path='/tmp'/></fs><ok to="a14"/><error 
to="a14"/></action>
+    <action name="a14"><fs><mkdir path='/tmp'/></fs><ok to="a15"/><error 
to="a15"/></action>
+    <action name="a15"><fs><mkdir path='/tmp'/></fs><ok to="a16"/><error 
to="a16"/></action>
+    <action name="a16"><fs><mkdir path='/tmp'/></fs><ok to="a17"/><error 
to="a17"/></action>
+    <action name="a17"><fs><mkdir path='/tmp'/></fs><ok to="a18"/><error 
to="a18"/></action>
+    <action name="a18"><fs><mkdir path='/tmp'/></fs><ok to="a19"/><error 
to="a19"/></action>
+    <action name="a19"><fs><mkdir path='/tmp'/></fs><ok to="a20"/><error 
to="a20"/></action>
+    <action name="a20"><fs><mkdir path='/tmp'/></fs><ok to="z"/><error 
to="z"/></action>
+
+    <end name="z"/>
+</workflow-app>
\ No newline at end of file
diff --git a/core/src/test/resources/wf-actions-40.xml 
b/core/src/test/resources/wf-actions-40.xml
new file mode 100644
index 0000000..256c19c
--- /dev/null
+++ b/core/src/test/resources/wf-actions-40.xml
@@ -0,0 +1,63 @@
+<!--
+  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.
+-->
+<workflow-app xmlns="uri:oozie:workflow:0.5" name="test-wf">
+    <start to="a1"/>
+
+    <action name="a1"><fs><mkdir path='/tmp'/></fs><ok to="a2"/><error 
to="a2"/></action>
+    <action name="a2"><fs><mkdir path='/tmp'/></fs><ok to="a3"/><error 
to="a3"/></action>
+    <action name="a3"><fs><mkdir path='/tmp'/></fs><ok to="a4"/><error 
to="a4"/></action>
+    <action name="a4"><fs><mkdir path='/tmp'/></fs><ok to="a5"/><error 
to="a5"/></action>
+    <action name="a5"><fs><mkdir path='/tmp'/></fs><ok to="a6"/><error 
to="a6"/></action>
+    <action name="a6"><fs><mkdir path='/tmp'/></fs><ok to="a7"/><error 
to="a7"/></action>
+    <action name="a7"><fs><mkdir path='/tmp'/></fs><ok to="a8"/><error 
to="a8"/></action>
+    <action name="a8"><fs><mkdir path='/tmp'/></fs><ok to="a9"/><error 
to="a9"/></action>
+    <action name="a9"><fs><mkdir path='/tmp'/></fs><ok to="a10"/><error 
to="a10"/></action>
+    <action name="a10"><fs><mkdir path='/tmp'/></fs><ok to="a11"/><error 
to="a11"/></action>
+    <action name="a11"><fs><mkdir path='/tmp'/></fs><ok to="a12"/><error 
to="a12"/></action>
+    <action name="a12"><fs><mkdir path='/tmp'/></fs><ok to="a13"/><error 
to="a13"/></action>
+    <action name="a13"><fs><mkdir path='/tmp'/></fs><ok to="a14"/><error 
to="a14"/></action>
+    <action name="a14"><fs><mkdir path='/tmp'/></fs><ok to="a15"/><error 
to="a15"/></action>
+    <action name="a15"><fs><mkdir path='/tmp'/></fs><ok to="a16"/><error 
to="a16"/></action>
+    <action name="a16"><fs><mkdir path='/tmp'/></fs><ok to="a17"/><error 
to="a17"/></action>
+    <action name="a17"><fs><mkdir path='/tmp'/></fs><ok to="a18"/><error 
to="a18"/></action>
+    <action name="a18"><fs><mkdir path='/tmp'/></fs><ok to="a19"/><error 
to="a19"/></action>
+    <action name="a19"><fs><mkdir path='/tmp'/></fs><ok to="a20"/><error 
to="a20"/></action>
+    <action name="a20"><fs><mkdir path='/tmp'/></fs><ok to="a21"/><error 
to="a21"/></action>
+    <action name="a21"><fs><mkdir path='/tmp'/></fs><ok to="a22"/><error 
to="a22"/></action>
+    <action name="a22"><fs><mkdir path='/tmp'/></fs><ok to="a23"/><error 
to="a23"/></action>
+    <action name="a23"><fs><mkdir path='/tmp'/></fs><ok to="a24"/><error 
to="a24"/></action>
+    <action name="a24"><fs><mkdir path='/tmp'/></fs><ok to="a25"/><error 
to="a25"/></action>
+    <action name="a25"><fs><mkdir path='/tmp'/></fs><ok to="a26"/><error 
to="a26"/></action>
+    <action name="a26"><fs><mkdir path='/tmp'/></fs><ok to="a27"/><error 
to="a27"/></action>
+    <action name="a27"><fs><mkdir path='/tmp'/></fs><ok to="a28"/><error 
to="a28"/></action>
+    <action name="a28"><fs><mkdir path='/tmp'/></fs><ok to="a29"/><error 
to="a29"/></action>
+    <action name="a29"><fs><mkdir path='/tmp'/></fs><ok to="a30"/><error 
to="a30"/></action>
+    <action name="a30"><fs><mkdir path='/tmp'/></fs><ok to="a31"/><error 
to="a31"/></action>
+    <action name="a31"><fs><mkdir path='/tmp'/></fs><ok to="a32"/><error 
to="a32"/></action>
+    <action name="a32"><fs><mkdir path='/tmp'/></fs><ok to="a33"/><error 
to="a33"/></action>
+    <action name="a33"><fs><mkdir path='/tmp'/></fs><ok to="a34"/><error 
to="a34"/></action>
+    <action name="a34"><fs><mkdir path='/tmp'/></fs><ok to="a35"/><error 
to="a35"/></action>
+    <action name="a35"><fs><mkdir path='/tmp'/></fs><ok to="a36"/><error 
to="a36"/></action>
+    <action name="a36"><fs><mkdir path='/tmp'/></fs><ok to="a37"/><error 
to="a37"/></action>
+    <action name="a37"><fs><mkdir path='/tmp'/></fs><ok to="a38"/><error 
to="a38"/></action>
+    <action name="a38"><fs><mkdir path='/tmp'/></fs><ok to="a39"/><error 
to="a39"/></action>
+    <action name="a39"><fs><mkdir path='/tmp'/></fs><ok to="a40"/><error 
to="a40"/></action>
+    <action name="a40"><fs><mkdir path='/tmp'/></fs><ok to="z"/><error 
to="z"/></action>
+
+    <end name="z"/>
+</workflow-app>
\ No newline at end of file
diff --git a/core/src/test/resources/wf-actions-80.xml 
b/core/src/test/resources/wf-actions-80.xml
new file mode 100644
index 0000000..95a623b
--- /dev/null
+++ b/core/src/test/resources/wf-actions-80.xml
@@ -0,0 +1,102 @@
+<!--
+  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.
+-->
+<workflow-app xmlns="uri:oozie:workflow:0.5" name="test-wf">
+    <start to="a1"/>
+
+    <action name="a1"><fs><mkdir path='/tmp'/></fs><ok to="a2"/><error 
to="a2"/></action>
+    <action name="a2"><fs><mkdir path='/tmp'/></fs><ok to="a3"/><error 
to="a3"/></action>
+    <action name="a3"><fs><mkdir path='/tmp'/></fs><ok to="a4"/><error 
to="a4"/></action>
+    <action name="a4"><fs><mkdir path='/tmp'/></fs><ok to="a5"/><error 
to="a5"/></action>
+    <action name="a5"><fs><mkdir path='/tmp'/></fs><ok to="a6"/><error 
to="a6"/></action>
+    <action name="a6"><fs><mkdir path='/tmp'/></fs><ok to="a7"/><error 
to="a7"/></action>
+    <action name="a7"><fs><mkdir path='/tmp'/></fs><ok to="a8"/><error 
to="a8"/></action>
+    <action name="a8"><fs><mkdir path='/tmp'/></fs><ok to="a9"/><error 
to="a9"/></action>
+    <action name="a9"><fs><mkdir path='/tmp'/></fs><ok to="a10"/><error 
to="a10"/></action>
+    <action name="a10"><fs><mkdir path='/tmp'/></fs><ok to="a11"/><error 
to="a11"/></action>
+    <action name="a11"><fs><mkdir path='/tmp'/></fs><ok to="a12"/><error 
to="a12"/></action>
+    <action name="a12"><fs><mkdir path='/tmp'/></fs><ok to="a13"/><error 
to="a13"/></action>
+    <action name="a13"><fs><mkdir path='/tmp'/></fs><ok to="a14"/><error 
to="a14"/></action>
+    <action name="a14"><fs><mkdir path='/tmp'/></fs><ok to="a15"/><error 
to="a15"/></action>
+    <action name="a15"><fs><mkdir path='/tmp'/></fs><ok to="a16"/><error 
to="a16"/></action>
+    <action name="a16"><fs><mkdir path='/tmp'/></fs><ok to="a17"/><error 
to="a17"/></action>
+    <action name="a17"><fs><mkdir path='/tmp'/></fs><ok to="a18"/><error 
to="a18"/></action>
+    <action name="a18"><fs><mkdir path='/tmp'/></fs><ok to="a19"/><error 
to="a19"/></action>
+    <action name="a19"><fs><mkdir path='/tmp'/></fs><ok to="a20"/><error 
to="a20"/></action>
+    <action name="a20"><fs><mkdir path='/tmp'/></fs><ok to="a21"/><error 
to="a21"/></action>
+    <action name="a21"><fs><mkdir path='/tmp'/></fs><ok to="a22"/><error 
to="a22"/></action>
+    <action name="a22"><fs><mkdir path='/tmp'/></fs><ok to="a23"/><error 
to="a23"/></action>
+    <action name="a23"><fs><mkdir path='/tmp'/></fs><ok to="a24"/><error 
to="a24"/></action>
+    <action name="a24"><fs><mkdir path='/tmp'/></fs><ok to="a25"/><error 
to="a25"/></action>
+    <action name="a25"><fs><mkdir path='/tmp'/></fs><ok to="a26"/><error 
to="a26"/></action>
+    <action name="a26"><fs><mkdir path='/tmp'/></fs><ok to="a27"/><error 
to="a27"/></action>
+    <action name="a27"><fs><mkdir path='/tmp'/></fs><ok to="a28"/><error 
to="a28"/></action>
+    <action name="a28"><fs><mkdir path='/tmp'/></fs><ok to="a29"/><error 
to="a29"/></action>
+    <action name="a29"><fs><mkdir path='/tmp'/></fs><ok to="a30"/><error 
to="a30"/></action>
+    <action name="a30"><fs><mkdir path='/tmp'/></fs><ok to="a31"/><error 
to="a31"/></action>
+    <action name="a31"><fs><mkdir path='/tmp'/></fs><ok to="a32"/><error 
to="a32"/></action>
+    <action name="a32"><fs><mkdir path='/tmp'/></fs><ok to="a33"/><error 
to="a33"/></action>
+    <action name="a33"><fs><mkdir path='/tmp'/></fs><ok to="a34"/><error 
to="a34"/></action>
+    <action name="a34"><fs><mkdir path='/tmp'/></fs><ok to="a35"/><error 
to="a35"/></action>
+    <action name="a35"><fs><mkdir path='/tmp'/></fs><ok to="a36"/><error 
to="a36"/></action>
+    <action name="a36"><fs><mkdir path='/tmp'/></fs><ok to="a37"/><error 
to="a37"/></action>
+    <action name="a37"><fs><mkdir path='/tmp'/></fs><ok to="a38"/><error 
to="a38"/></action>
+    <action name="a38"><fs><mkdir path='/tmp'/></fs><ok to="a39"/><error 
to="a39"/></action>
+    <action name="a39"><fs><mkdir path='/tmp'/></fs><ok to="a40"/><error 
to="a40"/></action>
+    <action name="a40"><fs><mkdir path='/tmp'/></fs><ok to="a41"/><error 
to="a41"/></action>
+    <action name="a41"><fs><mkdir path='/tmp'/></fs><ok to="a42"/><error 
to="a42"/></action>
+    <action name="a42"><fs><mkdir path='/tmp'/></fs><ok to="a43"/><error 
to="a43"/></action>
+    <action name="a43"><fs><mkdir path='/tmp'/></fs><ok to="a44"/><error 
to="a44"/></action>
+    <action name="a44"><fs><mkdir path='/tmp'/></fs><ok to="a45"/><error 
to="a45"/></action>
+    <action name="a45"><fs><mkdir path='/tmp'/></fs><ok to="a46"/><error 
to="a46"/></action>
+    <action name="a46"><fs><mkdir path='/tmp'/></fs><ok to="a47"/><error 
to="a47"/></action>
+    <action name="a47"><fs><mkdir path='/tmp'/></fs><ok to="a48"/><error 
to="a48"/></action>
+    <action name="a48"><fs><mkdir path='/tmp'/></fs><ok to="a49"/><error 
to="a49"/></action>
+    <action name="a49"><fs><mkdir path='/tmp'/></fs><ok to="a50"/><error 
to="a50"/></action>
+    <action name="a50"><fs><mkdir path='/tmp'/></fs><ok to="a51"/><error 
to="a51"/></action>
+    <action name="a51"><fs><mkdir path='/tmp'/></fs><ok to="a52"/><error 
to="a52"/></action>
+    <action name="a52"><fs><mkdir path='/tmp'/></fs><ok to="a53"/><error 
to="a53"/></action>
+    <action name="a53"><fs><mkdir path='/tmp'/></fs><ok to="a54"/><error 
to="a54"/></action>
+    <action name="a54"><fs><mkdir path='/tmp'/></fs><ok to="a55"/><error 
to="a55"/></action>
+    <action name="a55"><fs><mkdir path='/tmp'/></fs><ok to="a56"/><error 
to="a56"/></action>
+    <action name="a56"><fs><mkdir path='/tmp'/></fs><ok to="a57"/><error 
to="a57"/></action>
+    <action name="a57"><fs><mkdir path='/tmp'/></fs><ok to="a58"/><error 
to="a58"/></action>
+    <action name="a58"><fs><mkdir path='/tmp'/></fs><ok to="a59"/><error 
to="a59"/></action>
+    <action name="a59"><fs><mkdir path='/tmp'/></fs><ok to="a60"/><error 
to="a60"/></action>
+    <action name="a60"><fs><mkdir path='/tmp'/></fs><ok to="a61"/><error 
to="a61"/></action>
+    <action name="a61"><fs><mkdir path='/tmp'/></fs><ok to="a62"/><error 
to="a62"/></action>
+    <action name="a62"><fs><mkdir path='/tmp'/></fs><ok to="a63"/><error 
to="a63"/></action>
+    <action name="a63"><fs><mkdir path='/tmp'/></fs><ok to="a64"/><error 
to="a64"/></action>
+    <action name="a64"><fs><mkdir path='/tmp'/></fs><ok to="a65"/><error 
to="a65"/></action>
+    <action name="a65"><fs><mkdir path='/tmp'/></fs><ok to="a66"/><error 
to="a66"/></action>
+    <action name="a66"><fs><mkdir path='/tmp'/></fs><ok to="a67"/><error 
to="a67"/></action>
+    <action name="a67"><fs><mkdir path='/tmp'/></fs><ok to="a68"/><error 
to="a68"/></action>
+    <action name="a68"><fs><mkdir path='/tmp'/></fs><ok to="a69"/><error 
to="a69"/></action>
+    <action name="a69"><fs><mkdir path='/tmp'/></fs><ok to="a70"/><error 
to="a70"/></action>
+    <action name="a70"><fs><mkdir path='/tmp'/></fs><ok to="a71"/><error 
to="a71"/></action>
+    <action name="a71"><fs><mkdir path='/tmp'/></fs><ok to="a72"/><error 
to="a72"/></action>
+    <action name="a72"><fs><mkdir path='/tmp'/></fs><ok to="a73"/><error 
to="a73"/></action>
+    <action name="a73"><fs><mkdir path='/tmp'/></fs><ok to="a74"/><error 
to="a74"/></action>
+    <action name="a74"><fs><mkdir path='/tmp'/></fs><ok to="a75"/><error 
to="a75"/></action>
+    <action name="a75"><fs><mkdir path='/tmp'/></fs><ok to="a76"/><error 
to="a76"/></action>
+    <action name="a76"><fs><mkdir path='/tmp'/></fs><ok to="a77"/><error 
to="a77"/></action>
+    <action name="a77"><fs><mkdir path='/tmp'/></fs><ok to="a78"/><error 
to="a78"/></action>
+    <action name="a78"><fs><mkdir path='/tmp'/></fs><ok to="a79"/><error 
to="a79"/></action>
+    <action name="a79"><fs><mkdir path='/tmp'/></fs><ok to="a80"/><error 
to="a80"/></action>
+    <action name="a80"><fs><mkdir path='/tmp'/></fs><ok to="z"/><error 
to="z"/></action>
+    <end name="z"/>
+</workflow-app>
\ No newline at end of file
diff --git a/release-log.txt b/release-log.txt
index caf5a08..e0c6329 100644
--- a/release-log.txt
+++ b/release-log.txt
@@ -1,5 +1,6 @@
 -- Oozie 5.3.0 release (trunk - unreleased)
 
+OOZIE-3561 Forkjoin validation is slow when there are many actions in chain 
(dionusos, pbacsko via asalamon74)
 OOZIE-3491 Confusing System ID error message (matijhs via asalamon74)
 OOZIE-3536 Invalid configuration tag <additionalparam> in maven-javadoc-plugin 
(nobigo via asalamon74)
 OOZIE-3559 Code generation encoding error in fluent-job-api (nobigo via 
asalamon74)

Reply via email to