From d1cdd567c2ebc7edb3b2214ff80d5011b508037f Mon Sep 17 00:00:00 2001 From: Mark Proctor Date: Thu, 3 Mar 2016 01:20:33 +0000 Subject: [PATCH] [DROOLS-1025] new tests + improved flush + implement insertPeerRightTuple --- .../AbstractAddRemoveGenerated2RulesTest.java | 16 - .../AbstractAddRemoveRulesTest.java | 78 ++--- .../AddRemoveGenerated2RulesNotNotTest.java | 22 ++ .../AddRemoveRulesTest.java | 239 +++++++++++++- .../org/drools/core/phreak/AddRemoveRule.java | 291 +++++++++--------- .../core/phreak/PhreakQueryTerminalNode.java | 3 +- .../drools/core/phreak/PhreakTimerNode.java | 2 +- .../core/phreak/RuleNetworkEvaluator.java | 67 ++-- .../org/drools/core/phreak/StackEntry.java | 11 +- .../core/reteoo/AbstractTerminalNode.java | 9 +- .../core/reteoo/RightInputAdapterNode.java | 2 +- 11 files changed, 478 insertions(+), 262 deletions(-) create mode 100644 drools-compiler/src/test/java/org/drools/compiler/integrationtests/incrementalcompilation/AddRemoveGenerated2RulesNotNotTest.java diff --git a/drools-compiler/src/test/java/org/drools/compiler/integrationtests/incrementalcompilation/AbstractAddRemoveGenerated2RulesTest.java b/drools-compiler/src/test/java/org/drools/compiler/integrationtests/incrementalcompilation/AbstractAddRemoveGenerated2RulesTest.java index 03c7290771c..6203af9f0f3 100644 --- a/drools-compiler/src/test/java/org/drools/compiler/integrationtests/incrementalcompilation/AbstractAddRemoveGenerated2RulesTest.java +++ b/drools-compiler/src/test/java/org/drools/compiler/integrationtests/incrementalcompilation/AbstractAddRemoveGenerated2RulesTest.java @@ -83,8 +83,6 @@ private static List getConstraintsCombinations(final List constr @Test(timeout = 10000) public void testInsertFactsFireRulesRemoveRules() { checkRunTurtleTests(); - logger.info("Rule 1: \n" + rule1); - logger.info("Rule 2: \n" + rule2); final List> testPlans = AddRemoveTestBuilder.createInsertFactsFireRulesRemoveRulesTestPlan( rule1, rule2, RULE1_NAME, RULE2_NAME, getFacts()); @@ -95,8 +93,6 @@ public void testInsertFactsFireRulesRemoveRules() { @Test(timeout = 10000) public void testInsertFactsFireRulesRemoveRulesRevertedRules() { checkRunTurtleTests(); - logger.info("Rule 1: \n" + rule2); - logger.info("Rule 2: \n" + rule1); final List> testPlans = AddRemoveTestBuilder.createInsertFactsFireRulesRemoveRulesTestPlan( rule2, rule1, RULE2_NAME, RULE1_NAME, getFacts()); @@ -107,8 +103,6 @@ public void testInsertFactsFireRulesRemoveRulesRevertedRules() { @Test(timeout = 10000) public void testFireRulesInsertFactsFireRulesRemoveRules() { checkRunTurtleTests(); - logger.info("Rule 1: \n" + rule1); - logger.info("Rule 2: \n" + rule2); final List> testPlans = AddRemoveTestBuilder.createFireRulesInsertFactsFireRulesRemoveRulesTestPlan( rule1, rule2, RULE1_NAME, RULE2_NAME, getFacts()); @@ -119,8 +113,6 @@ public void testFireRulesInsertFactsFireRulesRemoveRules() { @Test(timeout = 10000) public void testFireRulesInsertFactsFireRulesRemoveRulesRevertedRules() { checkRunTurtleTests(); - logger.info("Rule 1: \n" + rule2); - logger.info("Rule 2: \n" + rule1); final List> testPlans = AddRemoveTestBuilder.createFireRulesInsertFactsFireRulesRemoveRulesTestPlan( rule2, rule1, RULE2_NAME, RULE1_NAME, getFacts()); @@ -131,8 +123,6 @@ public void testFireRulesInsertFactsFireRulesRemoveRulesRevertedRules() { @Test(timeout = 10000) public void testInsertFactsRemoveRulesFireRulesRemoveRules() { checkRunTurtleTests(); - logger.info("Rule 1: \n" + rule1); - logger.info("Rule 2: \n" + rule2); final List> testPlans = AddRemoveTestBuilder.createInsertFactsRemoveRulesFireRulesRemoveRulesTestPlan( rule1, rule2, RULE1_NAME, RULE2_NAME, getFacts()); @@ -143,8 +133,6 @@ public void testInsertFactsRemoveRulesFireRulesRemoveRules() { @Test(timeout = 10000) public void testInsertFactsRemoveRulesFireRulesRemoveRulesRevertedRules() { checkRunTurtleTests(); - logger.info("Rule 1: \n" + rule2); - logger.info("Rule 2: \n" + rule1); final List> testPlans = AddRemoveTestBuilder.createInsertFactsRemoveRulesFireRulesRemoveRulesTestPlan( rule2, rule1, RULE2_NAME, RULE1_NAME, getFacts()); @@ -155,8 +143,6 @@ public void testInsertFactsRemoveRulesFireRulesRemoveRulesRevertedRules() { @Test(timeout = 10000) public void testInsertFactsFireRulesRemoveRulesReinsertRules() { checkRunTurtleTests(); - logger.info("Rule 1: \n" + rule1); - logger.info("Rule 2: \n" + rule2); final List> testPlans = AddRemoveTestBuilder.createInsertFactsFireRulesRemoveRulesReinsertRulesTestPlan( rule1, rule2, RULE1_NAME, RULE2_NAME, getFacts()); @@ -167,8 +153,6 @@ public void testInsertFactsFireRulesRemoveRulesReinsertRules() { @Test(timeout = 10000) public void testInsertFactsFireRulesRemoveRulesReinsertRulesRevertedRules() { checkRunTurtleTests(); - logger.info("Rule 1: \n" + rule2); - logger.info("Rule 2: \n" + rule1); final List> testPlans = AddRemoveTestBuilder.createInsertFactsFireRulesRemoveRulesReinsertRulesTestPlan( rule2, rule1, RULE2_NAME, RULE1_NAME, getFacts()); diff --git a/drools-compiler/src/test/java/org/drools/compiler/integrationtests/incrementalcompilation/AbstractAddRemoveRulesTest.java b/drools-compiler/src/test/java/org/drools/compiler/integrationtests/incrementalcompilation/AbstractAddRemoveRulesTest.java index 437d0a06120..2c87d47641d 100644 --- a/drools-compiler/src/test/java/org/drools/compiler/integrationtests/incrementalcompilation/AbstractAddRemoveRulesTest.java +++ b/drools-compiler/src/test/java/org/drools/compiler/integrationtests/incrementalcompilation/AbstractAddRemoveRulesTest.java @@ -116,47 +116,47 @@ protected StatefulKnowledgeSession runAddRemoveTest(final List te if (testOperationType != TestOperationType.CREATE_SESSION) { checkSessionInitialized(session); } - switch (testOperationType) { - case CREATE_SESSION: - session = createNewSession((String[]) testOperationParameter, resultsList, additionalGlobals); - break; - case ADD_RULES: - addRulesToSession(session, (String[]) testOperationParameter, false); - break; - case ADD_RULES_REINSERT_OLD: - addRulesToSession(session, (String[]) testOperationParameter, true); - break; - case REMOVE_RULES: - removeRulesFromSession(session, (String[]) testOperationParameter); - break; - case FIRE_RULES: - try { + try { + switch (testOperationType) { + case CREATE_SESSION: + session = createNewSession((String[]) testOperationParameter, resultsList, additionalGlobals); + break; + case ADD_RULES: + addRulesToSession(session, (String[]) testOperationParameter, false); + break; + case ADD_RULES_REINSERT_OLD: + addRulesToSession(session, (String[]) testOperationParameter, true); + break; + case REMOVE_RULES: + removeRulesFromSession(session, (String[]) testOperationParameter); + break; + case FIRE_RULES: session.fireAllRules(); - } catch (Exception e) { - throw new RuntimeException( createTestFailMessage(testOperations, index, null, null), e ); - } - break; - case CHECK_RESULTS: - final Set expectedResultsSet = new HashSet(); - expectedResultsSet.addAll(Arrays.asList((String[])testOperationParameter)); - if (expectedResultsSet.size() > 0) { + break; + case CHECK_RESULTS: + final Set expectedResultsSet = new HashSet(); + expectedResultsSet.addAll(Arrays.asList((String[]) testOperationParameter)); + if (expectedResultsSet.size() > 0) { + assertTrue(createTestFailMessage(testOperations, index, expectedResultsSet, resultsList), + resultsList.size() > 0); + } assertTrue(createTestFailMessage(testOperations, index, expectedResultsSet, resultsList), - resultsList.size() > 0); - } - assertTrue(createTestFailMessage(testOperations, index, expectedResultsSet, resultsList), - expectedResultsSet.containsAll(resultsList)); - assertTrue(createTestFailMessage(testOperations, index, expectedResultsSet, resultsList), - resultsList.containsAll(expectedResultsSet)); - resultsList.clear(); - break; - case INSERT_FACTS: - insertFactsIntoSession(session, (Object[]) testOperationParameter); - break; - case DUMP_RETE: - ReteDumper.dumpRete( (KieSession)session ); - break; - default: - throw new IllegalArgumentException("Unsupported test operation: " + testOperationType + "!"); + expectedResultsSet.containsAll(resultsList)); + assertTrue(createTestFailMessage(testOperations, index, expectedResultsSet, resultsList), + resultsList.containsAll(expectedResultsSet)); + resultsList.clear(); + break; + case INSERT_FACTS: + insertFactsIntoSession(session, (Object[]) testOperationParameter); + break; + case DUMP_RETE: + ReteDumper.dumpRete((KieSession) session); + break; + default: + throw new IllegalArgumentException("Unsupported test operation: " + testOperationType + "!"); + } + } catch (Exception e) { + throw new RuntimeException(createTestFailMessage(testOperations, index, null, null), e); } index++; } diff --git a/drools-compiler/src/test/java/org/drools/compiler/integrationtests/incrementalcompilation/AddRemoveGenerated2RulesNotNotTest.java b/drools-compiler/src/test/java/org/drools/compiler/integrationtests/incrementalcompilation/AddRemoveGenerated2RulesNotNotTest.java new file mode 100644 index 00000000000..24caa0bc4a6 --- /dev/null +++ b/drools-compiler/src/test/java/org/drools/compiler/integrationtests/incrementalcompilation/AddRemoveGenerated2RulesNotNotTest.java @@ -0,0 +1,22 @@ +package org.drools.compiler.integrationtests.incrementalcompilation; + +import java.util.Collection; + +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +@RunWith(Parameterized.class) +public class AddRemoveGenerated2RulesNotNotTest extends AbstractAddRemoveGenerated2RulesTest { + + public AddRemoveGenerated2RulesNotNotTest(final ConstraintsPair constraintsPair) { + super(constraintsPair); + } + + @Parameterized.Parameters + public static Collection getRulesConstraints() { + return generateRulesConstraintsCombinations( + " Integer() \n", + " Integer() not(not(exists(Integer() and Integer()))) \n", + " exists(Integer() and exists(Integer() and Integer())) \n"); + } +} diff --git a/drools-compiler/src/test/java/org/drools/compiler/integrationtests/incrementalcompilation/AddRemoveRulesTest.java b/drools-compiler/src/test/java/org/drools/compiler/integrationtests/incrementalcompilation/AddRemoveRulesTest.java index c01c41acce0..5a67b49229e 100644 --- a/drools-compiler/src/test/java/org/drools/compiler/integrationtests/incrementalcompilation/AddRemoveRulesTest.java +++ b/drools-compiler/src/test/java/org/drools/compiler/integrationtests/incrementalcompilation/AddRemoveRulesTest.java @@ -19,6 +19,7 @@ import org.drools.core.common.InternalFactHandle; import org.drools.core.reteoo.LeftTuple; import org.drools.core.reteoo.RightTuple; +import org.drools.core.reteoo.SubnetworkTuple; import org.junit.Ignore; import org.junit.Test; import org.kie.api.KieBase; @@ -1936,7 +1937,7 @@ public void testSubNetworkWithNot3() { runAddRemoveTest(builder.build(), new HashMap()); } - @Test @Ignore + @Test public void testSubNetworkWithNot4() { final String rule1 = "package " + PKG_NAME_TEST + ";" + "global java.util.List list\n" + @@ -1972,4 +1973,240 @@ public void testSubNetworkWithNot4() { runAddRemoveTest(builder.build(), new HashMap()); } + + @Test + public void testInsertFireRemoveWith2Nots() { + final String rule1 = " package " + PKG_NAME_TEST + ";\n" + + " global java.util.List list\n" + + " rule " + RULE1_NAME + " \n" + + " when \n" + + " Integer() \n" + + " Integer() \n" + + " then\n" + + " list.add('" + RULE1_NAME + "'); \n" + + " end"; + + final String rule2 = " package " + PKG_NAME_TEST + ";\n" + + " global java.util.List list\n" + + " rule " + RULE2_NAME + " \n" + + " when \n" + + " Integer() \n" + + " Integer() \n" + + " not(not(Integer() and Integer())) \n" + + " then\n" + + " list.add('" + RULE2_NAME + "'); \n" + + " end"; + + final AddRemoveTestBuilder builder = new AddRemoveTestBuilder(); + builder.addOperation(TestOperationType.CREATE_SESSION, new String[]{rule2, rule1}) + .addOperation(TestOperationType.INSERT_FACTS, new Object[] {1}) + .addOperation(TestOperationType.REMOVE_RULES, new String[]{RULE2_NAME}) + .addOperation(TestOperationType.REMOVE_RULES, new String[]{RULE1_NAME}) + .addOperation(TestOperationType.FIRE_RULES) + .addOperation(TestOperationType.CHECK_RESULTS, new String[]{}); + + runAddRemoveTest(builder.build(), new HashMap()); + + } + + @Test + public void testSubSubNetwork5() { + final String rule1 = "package " + PKG_NAME_TEST + ";" + + "global java.util.List list\n" + + "rule " + RULE1_NAME + " \n" + + "when\n" + + " Integer() \n" + + " Integer() \n" + + " exists(Integer() and Integer()) \n" + + "then\n" + + " list.add('" + RULE1_NAME + "'); \n" + + "end\n"; + + final String rule2 = "package " + PKG_NAME_TEST + ";" + + "global java.util.List list\n" + + "rule " + RULE2_NAME + " \n" + + "when \n" + + " Integer() \n" + + " exists(Integer() and Integer()) \n" + + "then \n" + + " list.add('" + RULE2_NAME + "'); \n" + + "end"; + + AddRemoveTestBuilder builder = new AddRemoveTestBuilder(); + builder.addOperation(TestOperationType.CREATE_SESSION, new String[]{rule1, rule2}) + .addOperation(TestOperationType.INSERT_FACTS, new Object[] {1}) + .addOperation(TestOperationType.REMOVE_RULES, new String[]{RULE1_NAME}) + .addOperation(TestOperationType.FIRE_RULES) + .addOperation(TestOperationType.CHECK_RESULTS, new String[]{RULE2_NAME}) + ; + + runAddRemoveTest(builder.build(), new HashMap()); + } + + @Test + public void testInsertRemoveFireWith2Nots() { + final String rule1 = " package " + PKG_NAME_TEST + ";\n" + + " global java.util.List list\n" + + " rule " + RULE1_NAME + " \n" + + " when \n" + + " exists(Integer() and Integer()) \n" + + " Integer() \n" + + " not(exists(Integer() and Integer())) \n" + + " then\n" + + " list.add('" + RULE1_NAME + "'); \n" + + " end"; + + final String rule2 = " package " + PKG_NAME_TEST + ";\n" + + " global java.util.List list\n" + + " rule " + RULE2_NAME + " \n" + + " when \n" + + " exists(Integer() and Integer()) \n" + + " not(exists(Integer() and Integer())) \n" + + " then\n" + + " list.add('" + RULE2_NAME + "'); \n" + + " end"; + + final AddRemoveTestBuilder builder = new AddRemoveTestBuilder(); + builder.addOperation(TestOperationType.CREATE_SESSION, new String[]{rule1, rule2}); + + runAddRemoveTest(builder.build(), new HashMap()); + } + + @Test + public void testSharedRian() { + + final String rule1 = " package " + PKG_NAME_TEST + ";\n" + + " global java.util.List list\n" + + " rule " + RULE1_NAME + " \n" + + " when \n" + + " Integer() \n" + + " not(Integer() and Integer()) \n" + + " then\n" + + " list.add('" + RULE1_NAME + "'); \n" + + " end"; + + final String rule2 = " package " + PKG_NAME_TEST + ";\n" + + " global java.util.List list\n" + + " rule " + RULE2_NAME + " \n" + + " when \n" + + " Integer() \n" + + " exists(Integer() and Integer()) \n" + + " then\n" + + " list.add('" + RULE2_NAME + "'); \n" + + " end"; + + final AddRemoveTestBuilder builder = new AddRemoveTestBuilder(); + builder.addOperation(TestOperationType.CREATE_SESSION, new String[]{rule1}) + .addOperation(TestOperationType.INSERT_FACTS, new Object[]{1}) + .addOperation(TestOperationType.ADD_RULES, new String[]{rule2}) + .addOperation(TestOperationType.FIRE_RULES) + .addOperation(TestOperationType.CHECK_RESULTS, new String[]{RULE2_NAME}); + + runAddRemoveTest(builder.build(), new HashMap()); + } + + @Test + public void testSharedRianWithFire() { + + final String rule1 = " package " + PKG_NAME_TEST + ";\n" + + " global java.util.List list\n" + + " rule " + RULE1_NAME + " \n" + + " when \n" + + " Integer() \n" + + " not(Integer() and Integer()) \n" + + " then\n" + + " list.add('" + RULE1_NAME + "'); \n" + + " end"; + + final String rule2 = " package " + PKG_NAME_TEST + ";\n" + + " global java.util.List list\n" + + " rule " + RULE2_NAME + " \n" + + " when \n" + + " Integer() \n" + + " exists(Integer() and Integer()) \n" + + " then\n" + + " list.add('" + RULE2_NAME + "'); \n" + + " end"; + + final AddRemoveTestBuilder builder = new AddRemoveTestBuilder(); + builder.addOperation(TestOperationType.CREATE_SESSION, new String[]{rule1}) + .addOperation(TestOperationType.INSERT_FACTS, new Object[]{1}) + .addOperation(TestOperationType.FIRE_RULES) + .addOperation(TestOperationType.ADD_RULES, new String[]{rule2}) + .addOperation(TestOperationType.FIRE_RULES) + .addOperation(TestOperationType.CHECK_RESULTS, new String[]{RULE2_NAME}); + + runAddRemoveTest(builder.build(), new HashMap()); + } + + @Test + public void testSharedRian2() { + + final String rule1 = " package " + PKG_NAME_TEST + ";\n" + + " global java.util.List list\n" + + " rule " + RULE1_NAME + " \n" + + " when \n" + + " Integer() \n" + + " Integer() \n" + + " not(not(Integer() and Integer())) \n" + + " then\n" + + " list.add('" + RULE1_NAME + "'); \n" + + " end"; + + final String rule2 = " package " + PKG_NAME_TEST + ";\n" + + " global java.util.List list\n" + + " rule " + RULE2_NAME + " \n" + + " when \n" + + " Integer() \n" + + " exists(Integer() and exists(Integer() and Integer())) \n" + + " then\n" + + " list.add('" + RULE2_NAME + "'); \n" + + " end"; + + final AddRemoveTestBuilder builder = new AddRemoveTestBuilder(); + builder.addOperation(TestOperationType.CREATE_SESSION, new String[]{rule1}) + .addOperation(TestOperationType.INSERT_FACTS, new Object[]{1}) + .addOperation(TestOperationType.FIRE_RULES) + .addOperation(TestOperationType.CHECK_RESULTS, new String[]{RULE1_NAME}) + .addOperation(TestOperationType.ADD_RULES, new String[]{rule2}) + .addOperation(TestOperationType.FIRE_RULES) + .addOperation(TestOperationType.CHECK_RESULTS, new String[]{RULE2_NAME}); + + runAddRemoveTest(builder.build(), new HashMap()); + } + + @Test + public void testRemoveRuleWithSharedRia() { + final String rule1Name = "rule1"; + final String rule2Name = "rule2"; + final String rule1 = "rule " + rule1Name + " \n" + + "when \n" + + " Integer() \n" + + " not(Integer() and Integer()) \n" + + "then \n" + + "System.out.println('test rule 1'); \n"+ + "end"; + + final String rule2 = "rule " + rule2Name + " \n" + + "when \n" + + " Integer() \n" + + " exists(Integer() and Integer()) \n" + + "then \n" + + "System.out.println('test rule 2'); \n"+ + "end"; + + KieSession session = base.newKieSession(); + + this.addRuleToEngine(rule1); + InternalFactHandle fh = (InternalFactHandle)session.insert( 1 ); + session.fireAllRules(); + + this.addRuleToEngine(rule2); + + SubnetworkTuple tuple = (SubnetworkTuple)fh.getFirstLeftTuple().getFirstChild().getFirstChild(); + assertNotNull( tuple.getPeer() ); + + this.deleteRule(rule2Name); + assertNull( tuple.getPeer() ); + } } diff --git a/drools-core/src/main/java/org/drools/core/phreak/AddRemoveRule.java b/drools-core/src/main/java/org/drools/core/phreak/AddRemoveRule.java index ec7060f8e8a..54e99bfd4ae 100644 --- a/drools-core/src/main/java/org/drools/core/phreak/AddRemoveRule.java +++ b/drools-core/src/main/java/org/drools/core/phreak/AddRemoveRule.java @@ -41,6 +41,7 @@ import org.drools.core.reteoo.LeftTupleSinkNode; import org.drools.core.reteoo.LeftTupleSource; import org.drools.core.reteoo.NodeTypeEnums; +import org.drools.core.reteoo.ObjectSink; import org.drools.core.reteoo.ObjectSource; import org.drools.core.reteoo.ObjectTypeNode; import org.drools.core.reteoo.ObjectTypeNode.ObjectTypeNodeMemory; @@ -50,7 +51,6 @@ import org.drools.core.reteoo.RightInputAdapterNode; import org.drools.core.reteoo.RightInputAdapterNode.RiaNodeMemory; import org.drools.core.reteoo.RightTuple; -import org.drools.core.reteoo.RuleTerminalNode; import org.drools.core.reteoo.SegmentMemory; import org.drools.core.reteoo.TerminalNode; import org.drools.core.reteoo.TupleMemory; @@ -104,7 +104,6 @@ public static void addRule(TerminalNode tn, InternalWorkingMemory[] wms, Interna // Insert the facts for the new paths. This will iterate each new path from EndNode to the splitStart - but will not process the splitStart itself (as tha already exist). // It does not matter that the prior segments have not yet been processed for splitting, as this will only apply for branches of paths that did not exist before - for (InternalWorkingMemory wm : wms) { wm.flushPropagations(); @@ -164,33 +163,31 @@ public static void removeRule(TerminalNode tn, InternalWorkingMemory[] wms, Inte for (InternalWorkingMemory wm : wms) { wm.flushPropagations(); - PathEndNodeMemories tnms = getPathEndMemories(wm, pathEndNodes, true); - if (NodeTypeEnums.LeftInputAdapterNode == firstSplit.getType() && firstSplit.getAssociatedRuleSize() == 1) { - if ( tnms.subjectPmem != null ) { - flushStagedTuples(firstSplit, tnms.subjectPmem, wm); - } + if ( !tnms.subjectPmems.isEmpty() ) { + if (NodeTypeEnums.LeftInputAdapterNode == firstSplit.getType() && firstSplit.getAssociatedRuleSize() == 1) { + if (tnms.subjectPmem != null) { + flushStagedTuples(firstSplit, tnms.subjectPmem, wm); + } - processLeftTuples(firstSplit, wm, false, tn.getRule()); + processLeftTuples(firstSplit, wm, false, tn.getRule()); - removeNewPaths(wm, tnms.subjectPmems); - } else { + removeNewPaths(wm, tnms.subjectPmems); + } else { + flushStagedTuples(tnms.subjectPmem, pathEndNodes, wm); - for (PathMemory pmem : tnms.pmemsToBeFlushed) { - flushStagedTuples(firstSplit, pmem, wm); - } + processLeftTuples(firstSplit, wm, false, tn.getRule()); - processLeftTuples(firstSplit, wm, false, tn.getRule()); + removeNewPaths(wm, tnms.subjectPmems); - Map prevSmemsLookup = reInitPathMemories(wm, tnms.otherPmems, rule); + Map prevSmemsLookup = reInitPathMemories(wm, tnms.otherPmems, rule); - // must collect all visited SegmentMemories, for link notification - Set smemsToNotify = handleExistingPaths(rule, prevSmemsLookup, tnms.otherPmems, wm, ExistingPathStrategy.REMOVE_STRATEGY); + // must collect all visited SegmentMemories, for link notification + Set smemsToNotify = handleExistingPaths(rule, prevSmemsLookup, tnms.otherPmems, wm, ExistingPathStrategy.REMOVE_STRATEGY); - removeNewPaths(wm, tnms.subjectPmems); - - notifySegments(smemsToNotify, wm); + notifySegments(smemsToNotify, wm); + } } if (tnms.subjectPmem != null && tnms.subjectPmem.getRuleAgendaItem() != null && tnms.subjectPmem.getRuleAgendaItem().isQueued()) { @@ -534,6 +531,58 @@ private static boolean isSplit(LeftTupleNode node, Rule excludingRule) { } + public static class Flushed { + SegmentMemory segmentMemory; + PathMemory pathMemory; + + public Flushed(SegmentMemory segmentMemory, PathMemory pathMemory) { + this.segmentMemory = segmentMemory; + this.pathMemory = pathMemory; + } + } + + private static void flushStagedTuples(PathMemory pmem, PathEndNodes pathEndNodes, InternalWorkingMemory wm) { + // first flush the subject rule, then flush any staging lists that are part of a merge + if ( pmem.getRuleAgendaItem() != null ) { + new RuleNetworkEvaluator().evaluateNetwork(pmem, pmem.getRuleAgendaItem().getRuleExecutor(), wm); + } + + // With the removing rules being flushed, we need to check any splits that will be merged, to see if they need flushing + // Beware that flushing a higher up node, might again cause lower nodes to have more staged items. So track flushed items + // incase they need to be reflushed + List flushed = new ArrayList(); + + for ( LeftTupleNode node : pathEndNodes.subjectSplits ) { + if (!isSplit(node, pmem.getRule())) { // check if the split is there even without the processed rule + Memory mem = wm.getNodeMemories().peekNodeMemory(node.getId()); + if ( mem != null) { + SegmentMemory smem = mem.getSegmentMemory(); + + if ( !smem.isEmpty() ) { + for ( SegmentMemory childSmem = smem.getFirst(); childSmem != null; childSmem = childSmem.getNext() ) { + if ( !childSmem.getStagedLeftTuples().isEmpty() ) { + PathMemory childPmem = childSmem.getPathMemories().get(0); + flushed.add( new Flushed(childSmem, childPmem)); + forceFlushLeftTuple(childPmem, childSmem, wm, childSmem.getStagedLeftTuples().takeAll()); + } + } + } + } + } + } + + int flushCount = 1; // need to ensure that there is one full iteration, without any flushing. To avoid one flush causing populat of another already flushed segment + while (!flushed.isEmpty() && flushCount != 0) { + flushCount = 0; + for (Flushed path : flushed) { + if ( !path.segmentMemory.getStagedLeftTuples().isEmpty() ) { + flushCount++; + forceFlushLeftTuple(pmem, path.segmentMemory, wm, path.segmentMemory.getStagedLeftTuples().takeAll()); + } + } + } + } + private static void flushStagedTuples(LeftTupleNode splitStartNode, PathMemory pmem, InternalWorkingMemory wm) { if (pmem.getRuleAgendaItem() == null ) { // The rule has never been linked in and evaluated, so there will be nothing to flush. @@ -543,34 +592,24 @@ private static void flushStagedTuples(LeftTupleNode splitStartNode, PathMemory p SegmentMemory[] smems = pmem.getSegmentMemories(); SegmentMemory sm = null; - LeftTupleSink sink = null; - Memory mem = null; - long bit = 1; - if (splitStartNode.getAssociatedRuleSize() == 1 && (smems[0] == null || smems[0].getTipNode().getType() != NodeTypeEnums.LeftInputAdapterNode)) { - // there is no sharing - sm = smems[0]; + + // If there is no sharing, then there will not be any staged tuples in later segemnts, and thus no need to search for them if the current sm is empty. + int length = smems.length; + if ( splitStartNode.getAssociatedRuleSize() == 1 ) { + length = 1; + } + + while (smemIndex < length) { + sm = smems[smemIndex]; if (sm != null && !sm.getStagedLeftTuples().isEmpty()) { - sink = sm.getRootNode().getSinkPropagator().getFirstLeftTupleSink(); - mem = sm.getNodeMemories().get(1); - bit = 2; // adjust bit to point to next node + break; } - } else { smemIndex++; - while (smemIndex < smems.length) { - sm = smems[smemIndex]; - if (sm != null && !sm.getStagedLeftTuples().isEmpty()) { - sink = (LeftTupleSink) sm.getRootNode(); - mem = sm.getNodeMemories().get(0); - break; - } - smemIndex++; - } } - if ( sink != null ) { - new RuleNetworkEvaluator().outerEval( (LeftInputAdapterNode) smems[0].getRootNode(), - pmem, sink, bit, mem, smems, smemIndex, - sm.getStagedLeftTuples().takeAll(), wm, new LinkedList(), true, pmem.getRuleAgendaItem().getRuleExecutor() ); + if ( smemIndex < length ) { + // it only found a SM that needed flushing, if smemIndex < length + forceFlushLeftTuple(pmem, sm, wm, sm.getStagedLeftTuples().takeAll()); } } @@ -578,36 +617,41 @@ public static boolean flushLeftTupleIfNecessary(InternalWorkingMemory wm, Segmen PathMemory pmem = streamMode ? sm.getPathMemories().get(0) : sm.getFirstDataDrivenPathMemory(); - return pmem != null && forceFlushLeftTuple(pmem, sm, wm, leftTuple); + + TupleSets leftTupleSets = new TupleSetsImpl(); + if (leftTuple != null) { + leftTupleSets.addInsert(leftTuple); + } + + return pmem != null && forceFlushLeftTuple(pmem, sm, wm, leftTupleSets); } - private static boolean forceFlushLeftTuple(PathMemory pmem, SegmentMemory sm, InternalWorkingMemory wm, LeftTuple leftTuple) { + private static boolean forceFlushLeftTuple(PathMemory pmem, SegmentMemory sm, InternalWorkingMemory wm, TupleSets leftTupleSets) { SegmentMemory[] smems = pmem.getSegmentMemories(); - if (smems[0] == null) { - return false; // segment has not yet been initialized - } - LeftTupleSink sink; + LeftTupleNode node; Memory mem; long bit = 1; - if (sm.getRootNode() instanceof LeftInputAdapterNode) { - sink = ((LeftInputAdapterNode) sm.getRootNode()).getSinkPropagator().getFirstLeftTupleSink(); + if ( sm.getRootNode().getType() == NodeTypeEnums.LeftInputAdapterNode && sm.getTipNode().getType() != NodeTypeEnums.LeftInputAdapterNode) { + // The segment is the first and it has the lian shared with other nodes, the lian must be skipped, so adjust the bit and sink + node = sm.getRootNode().getSinkPropagator().getFirstLeftTupleSink(); mem = sm.getNodeMemories().get(1); bit = 2; // adjust bit to point to next node } else { - sink = (LeftTupleSink) sm.getRootNode(); + node = sm.getRootNode(); mem = sm.getNodeMemories().get(0); } - TupleSets leftTupleSets = new TupleSetsImpl(); - if (leftTuple != null) { - leftTupleSets.addInsert(leftTuple); + PathMemory rtnPmem; + if ( NodeTypeEnums.isTerminalNode(pmem.getPathEndNode()) ) { + rtnPmem = pmem; + } else { + rtnPmem = wm.getNodeMemory((AbstractTerminalNode) pmem.getPathEndNode().getPathEndNodes()[0]); } - new RuleNetworkEvaluator().outerEval((LeftInputAdapterNode) smems[0].getRootNode(), - pmem, sink, bit, mem, smems, sm.getPos(), leftTupleSets, wm, + new RuleNetworkEvaluator().outerEval(pmem, node, bit, mem, smems, sm.getPos(), leftTupleSets, wm, new LinkedList(), - true, pmem.getOrCreateRuleAgendaItem(wm).getRuleExecutor()); + true, rtnPmem.getOrCreateRuleAgendaItem(wm).getRuleExecutor()); return true; } @@ -622,7 +666,7 @@ private static Map reInitPathMemories(InternalWorki RightInputAdapterNode rian = (RightInputAdapterNode) pmem.getPathEndNode(); startRianLts = rian.getStartTupleSource(); } - AbstractTerminalNode.initPathMemory(pmem, pmem.getPathEndNode(), startRianLts, wm, removingRule); // re-initialise the PathMemory + AbstractTerminalNode.initPathMemory(pmem, startRianLts, wm, removingRule); // re-initialise the PathMemory } return previousSmems; } @@ -785,12 +829,6 @@ private static void processLeftTuples(LeftTupleNode node, InternalWorkingMemory if (NodeTypeEnums.isBetaNode(node)) { BetaMemory bm; - SegmentMemory childSmem = sm; // if there is no split the child smem is same as current node - - if (sm.getTipNode() == node) { - // There is a network split, so must use the next sm - childSmem = sm.getFirst(); - } if (NodeTypeEnums.AccumulateNode == node.getType()) { AccumulateMemory am = (AccumulateMemory) memory; bm = am.getBetaMemory(); @@ -798,7 +836,7 @@ private static void processLeftTuples(LeftTupleNode node, InternalWorkingMemory Tuple lt = BetaNode.getFirstTuple(bm.getLeftTupleMemory(), it); for (; lt != null; lt = (LeftTuple) it.next(lt)) { AccumulateContext accctx = (AccumulateContext) lt.getContextObject(); - visitChild(accctx.getResultLeftTuple(), childSmem, insert, wm, rule); + visitChild(accctx.getResultLeftTuple(), insert, wm, rule); } } else if (NodeTypeEnums.ExistsNode == node.getType()) { bm = (BetaMemory) wm.getNodeMemory((MemoryFactory) node); @@ -806,14 +844,14 @@ private static void processLeftTuples(LeftTupleNode node, InternalWorkingMemory RightTuple rt = (RightTuple) BetaNode.getFirstTuple(bm.getRightTupleMemory(), it); for (; rt != null; rt = (RightTuple) it.next(rt)) { for (LeftTuple lt = rt.getBlocked(); lt != null; lt = lt.getBlockedNext()) { - visitChild(wm, insert, rule, childSmem, it, lt); + visitChild(wm, insert, rule, it, lt); } } } else { bm = (BetaMemory) wm.getNodeMemory((MemoryFactory) node); FastIterator it = bm.getLeftTupleMemory().fullFastIterator(); Tuple lt = BetaNode.getFirstTuple(bm.getLeftTupleMemory(), it); - visitChild(wm, insert, rule, childSmem, it, lt); + visitChild(wm, insert, rule, it, lt); } return; } else if (NodeTypeEnums.FromNode == node.getType()) { @@ -821,7 +859,7 @@ private static void processLeftTuples(LeftTupleNode node, InternalWorkingMemory TupleMemory ltm = fm.getBetaMemory().getLeftTupleMemory(); FastIterator it = ltm.fullFastIterator(); for (LeftTuple lt = (LeftTuple) ltm.getFirst(null); lt != null; lt = (LeftTuple) it.next(lt)) { - visitChild(lt, sm, insert, wm, rule); + visitChild(lt, insert, wm, rule); } return; } @@ -855,12 +893,7 @@ private static void processLeftTuples(LeftTupleNode node, InternalWorkingMemory // Each lt is for a different lian, skip any lian not associated with the rule. Need to use lt parent (souce) not child to check the lian. if (lt.getTupleSource().isAssociatedWith(rule)) { - SegmentMemory childSmem = sm; - if (sm.getFirst() != null && sm.getFirst().getRootNode() == lt.getTupleSink()) { - // child lt sink is root of next segment, so assign. This happens when the Lian is in a segment of it's own - childSmem = sm.getFirst(); - } - visitChild(lt, childSmem, insert, wm, rule); + visitChild(lt, insert, wm, rule); if (lt.getHandlePrevious() != null) { lt.getHandlePrevious().setHandleNext( nextLt ); @@ -875,18 +908,18 @@ private static void processLeftTuples(LeftTupleNode node, InternalWorkingMemory } } - private static void visitChild(InternalWorkingMemory wm, boolean insert, Rule rule, SegmentMemory childSmem, FastIterator it, Tuple lt) { + private static void visitChild(InternalWorkingMemory wm, boolean insert, Rule rule, FastIterator it, Tuple lt) { for (; lt != null; lt = (LeftTuple) it.next(lt)) { LeftTuple childLt = lt.getFirstChild(); while (childLt != null) { LeftTuple nextLt = childLt.getHandleNext(); - visitChild(childLt, childSmem, insert, wm, rule); + visitChild(childLt, insert, wm, rule); childLt = nextLt; } } } - private static void visitChild(LeftTuple lt, SegmentMemory smem, boolean insert, InternalWorkingMemory wm, Rule rule) { + private static void visitChild(LeftTuple lt, boolean insert, InternalWorkingMemory wm, Rule rule) { LeftTuple prevLt = null; LeftTupleSinkNode sink = lt.getTupleSink(); @@ -897,16 +930,11 @@ private static void visitChild(LeftTuple lt, SegmentMemory smem, boolean insert, if (lt.getTupleSink().getAssociatedRuleSize() > 1) { if (lt.getFirstChild() != null) { - SegmentMemory childSmem = smem; // if there is no split the child smem is same as current node - - if ( smem.getFirst() != null && smem.getFirst().getRootNode() == lt.getFirstChild().getTupleSink() ) { - // There is a network split, so must use child smem - childSmem = smem.getFirst(); - } - for ( LeftTuple child = lt.getFirstChild(); child != null; child = child.getHandleNext() ) { - visitChild(child, childSmem, insert, wm, rule); + visitChild(child, insert, wm, rule); } + } else if (lt.getTupleSink().getType() == NodeTypeEnums.RightInputAdaterNode) { + insertPeerRightTuple(lt, wm, rule, insert); } } else if (!insert) { LeftTuple lt2 = null; @@ -927,15 +955,30 @@ private static void visitChild(LeftTuple lt, SegmentMemory smem, boolean insert, // there is a sink without a peer LT, so create the peer LT prevLt = insertPeerLeftTuple(prevLt, sink, wm); } + } + } + + private static void insertPeerRightTuple( LeftTuple lt, InternalWorkingMemory wm, Rule rule, boolean insert ) { + // There's a shared RightInputAdaterNode, so check if one of its sinks is associated only to the new rule + LeftTuple prevLt = null; + RightInputAdapterNode rian = (RightInputAdapterNode) lt.getTupleSink(); - if (smem != null) { - // will go null when it reaches an LT for a newly added sink, as these need to be initialised - smem = smem.getNext(); + for (ObjectSink sink : rian.getObjectSinkPropagator().getSinks()) { + if (lt != null) { + if (prevLt != null && !insert && sink.isAssociatedWith(rule) && sink.getAssociatedRuleSize() == 1) { + prevLt.setPeer( null ); + } + prevLt = lt; + lt = lt.getPeer(); + } else if (insert) { + BetaMemory bm = (BetaMemory) wm.getNodeMemory( (BetaNode) sink ); + prevLt = rian.createPeer( prevLt ); + bm.linkNode( wm ); + bm.getStagedRightTuples().addInsert((RightTuple)prevLt); } } } - /** * Create all missing peers */ @@ -945,21 +988,20 @@ private static LeftTuple insertPeerLeftTuple(LeftTuple lt, LeftTupleSinkNode nod liaMem = wm.getNodeMemory(((LeftInputAdapterNode) node.getLeftTupleSource())); } - lt = node.createPeer(lt); + LeftTuple peer = node.createPeer(lt); Memory memory = wm.getNodeMemories().peekNodeMemory(node.getId()); if (memory == null || memory.getSegmentMemory() == null) { throw new IllegalStateException("Defensive Programming: this should not be possilbe, as the addRule code should init child segments if they are needed "); } - if ( liaMem == null) { - memory.getSegmentMemory().getStagedLeftTuples().addInsert(lt); + memory.getSegmentMemory().getStagedLeftTuples().addInsert(peer); } else { // If parent is Lian, then this must be called, so that any linking or unlinking can be done. - LeftInputAdapterNode.doInsertSegmentMemory(wm, true, liaMem, memory.getSegmentMemory(), lt, node.getLeftTupleSource().isStreamMode()); + LeftInputAdapterNode.doInsertSegmentMemory(wm, true, liaMem, memory.getSegmentMemory(), peer, node.getLeftTupleSource().isStreamMode()); } - return lt; + return peer; } private static void deletePeerLeftTuple(LeftTuple lt, LeftTuple lt2, LeftTuple prevLt, InternalWorkingMemory wm) { @@ -973,12 +1015,17 @@ private static void deletePeerLeftTuple(LeftTuple lt, LeftTuple lt2, LeftTuple p private static void iterateLeftTuple(LeftTuple lt, InternalWorkingMemory wm) { if (NodeTypeEnums.isTerminalNode(lt.getTupleSink())) { - PathMemory pmem = wm.getNodeMemory((RuleTerminalNode) lt.getTupleSink()); - PhreakRuleTerminalNode.doLeftDelete(wm, pmem.getRuleAgendaItem().getRuleExecutor(), lt); + PathMemory pmem = (PathMemory) wm.getNodeMemories().peekNodeMemory( lt.getTupleSink().getId() ); + if (pmem != null) { + PhreakRuleTerminalNode.doLeftDelete( wm, pmem.getRuleAgendaItem().getRuleExecutor(), lt ); + } } else { for (LeftTuple child = lt.getFirstChild(); child != null; child = child.getHandleNext()) { for (LeftTuple peer = child; peer != null; peer = peer.getPeer()) { - iterateLeftTuple(peer, wm); + if (peer.getPeer() == null) { + // it's unnnecessary to visit the unshared networks, so only iterate the last peer + iterateLeftTuple( peer, wm ); + } } } } @@ -1264,29 +1311,11 @@ private static int nodeSegmentPosition(SegmentMemory sm1, LeftTupleNode splitNod return nodePos; } - - private static boolean isUnsharedSinkForRule(Rule rule, LeftTupleNode sink) { - return sink.getAssociatedRuleSize() == 1 && sink.isAssociatedWith(rule); - } - private static PathEndNodeMemories getPathEndMemories(InternalWorkingMemory wm, PathEndNodes pathEndNodes, boolean isRemoving) { PathEndNodeMemories tnMems = new PathEndNodeMemories(); - if (isRemoving) { - List nodes = new ArrayList(); - nodes.addAll(pathEndNodes.subjectSplits); - nodes.addAll(pathEndNodes.otherSplits); - - for (LeftTupleNode splitNode : nodes) { - findPmemToBeFlushed( tnMems, wm.getNodeMemories().peekNodeMemory(splitNode.getId()) ); - for (LeftTupleSink sink : splitNode.getSinkPropagator().getSinks()) { - findPmemToBeFlushed( tnMems, wm.getNodeMemories().peekNodeMemory(sink.getId()) ); - } - } - } - for (LeftTupleNode node : pathEndNodes.otherEndNodes) { if (node.getType() == NodeTypeEnums.RightInputAdaterNode) { RiaNodeMemory riaMem = (RiaNodeMemory) wm.getNodeMemories().peekNodeMemory(node.getId()); @@ -1327,25 +1356,10 @@ private static PathEndNodeMemories getPathEndMemories(InternalWorkingMemory wm, return tnMems; } - private static void findPmemToBeFlushed( PathEndNodeMemories tnMems, Memory mem ) { - if (mem != null) { - SegmentMemory smem = mem.getSegmentMemory(); - if (smem != null && !smem.getStagedLeftTuples().isEmpty()) { - for (PathMemory pmem : smem.getPathMemories()) { - if (pmem.getRuleAgendaItem() != null) { - tnMems.pmemsToBeFlushed.add( pmem ); - break; - } - } - } - } - } - private static class PathEndNodeMemories { PathMemory subjectPmem; List subjectPmems = new ArrayList(); List otherPmems = new ArrayList(); - Set pmemsToBeFlushed = new HashSet(); } private static PathEndNodes getPathEndNodes(InternalKnowledgeBase kBase, @@ -1399,10 +1413,8 @@ private static void collectPathEndNodes(InternalKnowledgeBase kBase, } if (NodeTypeEnums.isLeftTupleSource(sink)) { if (hasWms && SegmentUtilities.isTipNode(sink, null)) { - if (isUnsharedSinkForRule(tn.getRule(), sink)) { + if (!SegmentUtilities.isTipNode(sink, tn.getRule())) { endNodes.subjectSplits.add(sink); - } else { - endNodes.otherSplits.add(sink); } } @@ -1410,12 +1422,12 @@ private static void collectPathEndNodes(InternalKnowledgeBase kBase, } else if (NodeTypeEnums.isTerminalNode(sink)) { endNodes.otherEndNodes.add((PathEndNode) sink); } else if (NodeTypeEnums.RightInputAdaterNode == sink.getType()) { - if (isUnsharedSinkForRule(tn.getRule(), sink)) { - endNodes.subjectEndNodes.add((PathEndNode) sink); - } else { - endNodes.otherEndNodes.add((PathEndNode) sink); + if (sink.isAssociatedWith( processedRule )) { + endNodes.subjectEndNodes.add( (PathEndNode) sink ); + } + if (sink.getAssociatedRuleSize() > 1 || !sink.isAssociatedWith(processedRule)) { + endNodes.otherEndNodes.add( (PathEndNode) sink ); } - } else { throw new RuntimeException("Error: Unknown Node. Defensive programming test.."); } @@ -1435,6 +1447,5 @@ private static class PathEndNodes { List subjectEndNodes = new ArrayList(); List subjectSplits = new ArrayList(); List otherEndNodes = new ArrayList(); - List otherSplits = new ArrayList(); } } diff --git a/drools-core/src/main/java/org/drools/core/phreak/PhreakQueryTerminalNode.java b/drools-core/src/main/java/org/drools/core/phreak/PhreakQueryTerminalNode.java index 3ce6fd90bc4..cfec97c1e6a 100644 --- a/drools-core/src/main/java/org/drools/core/phreak/PhreakQueryTerminalNode.java +++ b/drools-core/src/main/java/org/drools/core/phreak/PhreakQueryTerminalNode.java @@ -169,7 +169,8 @@ public static void checkAndTriggerQueryReevaluation(InternalWorkingMemory wm, Li // node must be marked as dirty ((QueryElementNodeMemory)stackEntry.getNodeMem()).setNodeDirtyWithoutNotify(); - if (stackEntry.getLiaNode()== ((LeftTupleSink)rootEntry.getTupleSink()).getLeftTupleSource()) { + + if (stackEntry.getRmem().getPathEndNode().getPathNodes()[0] == ((LeftTupleSink)rootEntry.getTupleSink()).getLeftTupleSource()) { // query is recursive, so just re-add the stack entry to the current stack. This happens for reactive queries, triggered by a beta node right input stack.add(stackEntry); } else { diff --git a/drools-core/src/main/java/org/drools/core/phreak/PhreakTimerNode.java b/drools-core/src/main/java/org/drools/core/phreak/PhreakTimerNode.java index f21b4356f06..64639bcba7f 100644 --- a/drools-core/src/main/java/org/drools/core/phreak/PhreakTimerNode.java +++ b/drools-core/src/main/java/org/drools/core/phreak/PhreakTimerNode.java @@ -471,7 +471,7 @@ private static LinkedList evaluate(PathMemory pmem, RuleNetworkEvaluator rne = new RuleNetworkEvaluator(); LinkedList outerStack = new LinkedList(); - rne.outerEval(lian, pmem, sink, bit, tm, + rne.outerEval(pmem, sink, bit, tm, smems, smemIndex, trgLeftTuples, wm, new LinkedList(), true, pmem.getRuleAgendaItem().getRuleExecutor()); diff --git a/drools-core/src/main/java/org/drools/core/phreak/RuleNetworkEvaluator.java b/drools-core/src/main/java/org/drools/core/phreak/RuleNetworkEvaluator.java index f43f8bb6cdf..13856da6e08 100644 --- a/drools-core/src/main/java/org/drools/core/phreak/RuleNetworkEvaluator.java +++ b/drools-core/src/main/java/org/drools/core/phreak/RuleNetworkEvaluator.java @@ -22,39 +22,13 @@ import org.drools.core.common.NetworkNode; import org.drools.core.common.TupleSets; import org.drools.core.common.TupleSetsImpl; -import org.drools.core.reteoo.AccumulateNode; +import org.drools.core.reteoo.*; import org.drools.core.reteoo.AccumulateNode.AccumulateMemory; -import org.drools.core.reteoo.BetaMemory; -import org.drools.core.reteoo.BetaNode; -import org.drools.core.reteoo.ConditionalBranchNode; import org.drools.core.reteoo.ConditionalBranchNode.ConditionalBranchMemory; -import org.drools.core.reteoo.EvalConditionNode; import org.drools.core.reteoo.EvalConditionNode.EvalMemory; -import org.drools.core.reteoo.ExistsNode; -import org.drools.core.reteoo.FromNode; import org.drools.core.reteoo.FromNode.FromMemory; -import org.drools.core.reteoo.JoinNode; -import org.drools.core.reteoo.LeftInputAdapterNode; -import org.drools.core.reteoo.LeftTuple; -import org.drools.core.reteoo.LeftTupleSink; -import org.drools.core.reteoo.LeftTupleSinkNode; -import org.drools.core.reteoo.LeftTupleSource; -import org.drools.core.reteoo.NodeTypeEnums; -import org.drools.core.reteoo.NotNode; -import org.drools.core.reteoo.ObjectSink; -import org.drools.core.reteoo.PathMemory; -import org.drools.core.reteoo.QueryElementNode; import org.drools.core.reteoo.QueryElementNode.QueryElementNodeMemory; -import org.drools.core.reteoo.QueryTerminalNode; -import org.drools.core.reteoo.ReactiveFromNode; -import org.drools.core.reteoo.RiaPathMemory; -import org.drools.core.reteoo.RightInputAdapterNode; -import org.drools.core.reteoo.RightTuple; -import org.drools.core.reteoo.SegmentMemory; -import org.drools.core.reteoo.TerminalNode; -import org.drools.core.reteoo.TimerNode; import org.drools.core.reteoo.TimerNode.TimerNodeMemory; -import org.drools.core.reteoo.TupleMemory; import org.drools.core.rule.ContextEntry; import org.drools.core.spi.Tuple; import org.drools.core.util.FastIterator; @@ -117,7 +91,7 @@ public void evaluateNetwork(PathMemory pmem, RuleExecutor executor, InternalWork if (log.isTraceEnabled()) { log.trace("Rule[name={}] segments={} {}", ((TerminalNode)pmem.getPathEndNode()).getRule().getName(), smems.length, srcTuples.toStringSizes()); } - outerEval(liaNode, pmem, node, bit, nodeMem, smems, smemIndex, srcTuples, wm, stack, true, executor); + outerEval(pmem, node, bit, nodeMem, smems, smemIndex, srcTuples, wm, stack, true, executor); } public static String indent(int size) { @@ -148,8 +122,7 @@ public static int getOffset(NetworkNode node) { return offset; } - public void outerEval(LeftInputAdapterNode liaNode, - PathMemory pmem, + public void outerEval(PathMemory pmem, NetworkNode node, long bit, Memory nodeMem, @@ -160,7 +133,7 @@ public void outerEval(LeftInputAdapterNode liaNode, LinkedList stack, boolean processRian, RuleExecutor executor) { - innerEval(liaNode, pmem, node, bit, nodeMem, smems, smemIndex, trgTuples, wm, stack, processRian, executor); + innerEval(pmem, node, bit, nodeMem, smems, smemIndex, trgTuples, wm, stack, processRian, executor); while (true) { // eval if (!stack.isEmpty()) { @@ -222,11 +195,10 @@ public void evalStackEntry(StackEntry entry, LinkedList stack, RuleE int offset = getOffset(node); log.trace("{} Resume {} {}", indent(offset), node.toString(), trgTuples.toStringSizes()); } - innerEval(entry.getLiaNode(), pmem, node, bit, nodeMem, smems, smemIndex, trgTuples, wm, stack, processRian, executor); + innerEval(pmem, node, bit, nodeMem, smems, smemIndex, trgTuples, wm, stack, processRian, executor); } - public void innerEval(LeftInputAdapterNode liaNode, - PathMemory pmem, + public void innerEval(PathMemory pmem, NetworkNode node, long bit, Memory nodeMem, @@ -326,7 +298,7 @@ public void innerEval(LeftInputAdapterNode liaNode, stagedLeftTuples = getTargetStagedLeftTuples(node, wm, smem); LeftTupleSinkNode sink = ((LeftTupleSource) node).getSinkPropagator().getFirstLeftTupleSink(); - trgTuples = evalNode( liaNode, pmem, node, bit, nodeMem, smems, smemIndex, wm, stack, processRian, executor, srcTuples, smem, stagedLeftTuples, sink ); + trgTuples = evalNode( pmem, node, bit, nodeMem, smems, smemIndex, wm, stack, processRian, executor, srcTuples, smem, stagedLeftTuples, sink ); if ( trgTuples == null ) { break; // Queries exists and has been placed StackEntry, and there are no current trgTuples to process } @@ -360,13 +332,13 @@ public void innerEval(LeftInputAdapterNode liaNode, } } - public TupleSets evalNode( LeftInputAdapterNode liaNode, PathMemory pmem, NetworkNode node, long bit, Memory nodeMem, + public TupleSets evalNode( PathMemory pmem, NetworkNode node, long bit, Memory nodeMem, SegmentMemory[] smems, int smemIndex, InternalWorkingMemory wm, LinkedList stack, boolean processRian, RuleExecutor executor, TupleSets srcTuples, SegmentMemory smem, TupleSets stagedLeftTuples, LeftTupleSinkNode sink ) { TupleSets trgTuples = new TupleSetsImpl(); if ( NodeTypeEnums.isBetaNode( node )) { - boolean exitInnerEval = evalBetaNode(liaNode, pmem, node, nodeMem, smems, smemIndex, trgTuples, wm, stack, processRian, executor, srcTuples, stagedLeftTuples, sink); + boolean exitInnerEval = evalBetaNode(pmem, node, nodeMem, smems, smemIndex, trgTuples, wm, stack, processRian, executor, srcTuples, stagedLeftTuples, sink); if ( exitInnerEval ) { return null; } @@ -390,7 +362,7 @@ public TupleSets evalNode( LeftInputAdapterNode liaNode, PathMemory p break; } case NodeTypeEnums.QueryElementNode: { - exitInnerEval = evalQueryNode(liaNode, pmem, node, bit, nodeMem, smems, smemIndex, trgTuples, wm, stack, srcTuples, sink, stagedLeftTuples); + exitInnerEval = evalQueryNode(pmem, node, bit, nodeMem, smems, smemIndex, trgTuples, wm, stack, srcTuples, sink, stagedLeftTuples); break; } case NodeTypeEnums.TimerConditionNode: { @@ -422,8 +394,7 @@ private static TupleSets getTargetStagedLeftTuples(NetworkNode node, } } - private boolean evalQueryNode(LeftInputAdapterNode liaNode, - PathMemory pmem, + private boolean evalQueryNode(PathMemory pmem, NetworkNode node, long bit, Memory nodeMem, @@ -456,7 +427,7 @@ private boolean evalQueryNode(LeftInputAdapterNode liaNode, if (!srcTuples.isEmpty()) { // only process the Query Node if there are src tuples - StackEntry stackEntry = new StackEntry(liaNode, node, bit, sink, pmem, nodeMem, smems, + StackEntry stackEntry = new StackEntry(node, bit, sink, pmem, nodeMem, smems, smemIndex, trgTuples, true, true); stack.add(stackEntry); @@ -475,7 +446,8 @@ private boolean evalQueryNode(LeftInputAdapterNode liaNode, smems = qpmem.getSegmentMemories(); smemIndex = 0; SegmentMemory smem = smems[smemIndex]; // 0 - liaNode = (LeftInputAdapterNode) smem.getRootNode(); + + LeftTupleNode liaNode = (LeftInputAdapterNode) qpmem.getPathEndNode().getPathNodes()[0]; if (liaNode == smem.getTipNode()) { // segment only has liaNode in it @@ -492,7 +464,7 @@ private boolean evalQueryNode(LeftInputAdapterNode liaNode, } trgTuples = smem.getStagedLeftTuples().takeAll(); - stackEntry = new StackEntry(liaNode, node, bit, null, pmem, + stackEntry = new StackEntry(node, bit, null, pmem, nodeMem, smems, smemIndex, trgTuples, false, true); if (log.isTraceEnabled()) { @@ -508,7 +480,7 @@ private boolean evalQueryNode(LeftInputAdapterNode liaNode, } - private boolean evalBetaNode(LeftInputAdapterNode liaNode, PathMemory pmem, NetworkNode node, Memory nodeMem, + private boolean evalBetaNode(PathMemory pmem, NetworkNode node, Memory nodeMem, SegmentMemory[] smems, int smemIndex, TupleSets trgTuples, InternalWorkingMemory wm, LinkedList stack, boolean processRian, RuleExecutor executor, TupleSets srcTuples, TupleSets stagedLeftTuples, LeftTupleSinkNode sink) { @@ -525,7 +497,7 @@ private boolean evalBetaNode(LeftInputAdapterNode liaNode, PathMemory pmem, Netw if (processRian && betaNode.isRightInputIsRiaNode()) { // if the subnetwork is nested in this segment, it will create srcTuples containing // peer LeftTuples, suitable for the node in the main path. - doRiaNode( wm, liaNode, pmem, srcTuples, + doRiaNode( wm, pmem, srcTuples, betaNode, sink, smems, smemIndex, nodeMem, bm, stack, executor ); return true; // return here, doRiaNode queues the evaluation on the stack, which is necessary to handled nested query nodes } @@ -567,7 +539,6 @@ private void switchOnDoBetaNode(NetworkNode node, TupleSets trgTuples } private void doRiaNode(InternalWorkingMemory wm, - LeftInputAdapterNode liaNode, PathMemory pmem, TupleSets srcTuples, BetaNode betaNode, @@ -588,7 +559,7 @@ private void doRiaNode(InternalWorkingMemory wm, } // Resume the node after the riaNode segment has been processed and the right input memory populated - StackEntry stackEntry = new StackEntry(liaNode, betaNode, bm.getNodePosMaskBit(), sink, pmem, nodeMem, smems, + StackEntry stackEntry = new StackEntry(betaNode, bm.getNodePosMaskBit(), sink, pmem, nodeMem, smems, smemIndex, srcTuples, false, false); stack.add(stackEntry); if (log.isTraceEnabled()) { @@ -599,7 +570,7 @@ private void doRiaNode(InternalWorkingMemory wm, TupleSets subLts = subSmem.getStagedLeftTuples().takeAll(); // node is first in the segment, so bit is 1 - innerEval( liaNode, pathMem, subSmem.getRootNode(), 1, + innerEval( pathMem, subSmem.getRootNode(), 1, subSmem.getNodeMemories().getFirst(), subnetworkSmems, subSmem.getPos(), subLts, wm, stack, true, executor ); diff --git a/drools-core/src/main/java/org/drools/core/phreak/StackEntry.java b/drools-core/src/main/java/org/drools/core/phreak/StackEntry.java index d4d3a7a1dc7..eb5f2d895f6 100644 --- a/drools-core/src/main/java/org/drools/core/phreak/StackEntry.java +++ b/drools-core/src/main/java/org/drools/core/phreak/StackEntry.java @@ -33,7 +33,6 @@ * To change this template use File | Settings | File Templates. */ public class StackEntry extends AbstractBaseLinkedListNode { - private final LeftInputAdapterNode liaNode; private final long bit; private final NetworkNode node; private final LeftTupleSinkNode sink; @@ -46,8 +45,7 @@ public class StackEntry extends AbstractBaseLinkedListNode { private final boolean processRian; - public StackEntry(LeftInputAdapterNode liaNode, - NetworkNode node, + public StackEntry(NetworkNode node, long bit, LeftTupleSinkNode sink, PathMemory pmem, @@ -57,7 +55,6 @@ public StackEntry(LeftInputAdapterNode liaNode, TupleSets trgTuples, boolean resumeFromNextNode, boolean processRian) { - this.liaNode = liaNode; this.bit = bit; this.node = node; this.sink = sink; @@ -70,12 +67,6 @@ public StackEntry(LeftInputAdapterNode liaNode, this.processRian = processRian; } - - - public LeftInputAdapterNode getLiaNode() { - return this.liaNode; - } - public long getBit() { return bit; } diff --git a/drools-core/src/main/java/org/drools/core/reteoo/AbstractTerminalNode.java b/drools-core/src/main/java/org/drools/core/reteoo/AbstractTerminalNode.java index 4138183dc15..7cccfbac7fd 100644 --- a/drools-core/src/main/java/org/drools/core/reteoo/AbstractTerminalNode.java +++ b/drools-core/src/main/java/org/drools/core/reteoo/AbstractTerminalNode.java @@ -40,7 +40,6 @@ import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; -import java.util.ArrayList; import java.util.List; import static org.drools.core.reteoo.PropertySpecificUtil.*; @@ -154,19 +153,19 @@ public void modifyLeftTuple(InternalFactHandle factHandle, public PathMemory createMemory(RuleBaseConfiguration config, InternalWorkingMemory wm) { PathMemory pmem = new PathMemory(this); - initPathMemory(pmem, this, null, wm, null ); + initPathMemory(pmem, null, wm, null); return pmem; } /** * Creates and return the node memory */ - public static void initPathMemory(PathMemory pmem, LeftTupleNode endNode, LeftTupleSource startTupleSource, InternalWorkingMemory wm, Rule removingRule) { + public static void initPathMemory(PathMemory pmem, LeftTupleSource startTupleSource, InternalWorkingMemory wm, Rule removingRule) { int counter = 1; long allLinkedTestMask = 0; - LeftTupleSource tupleSource = endNode.getLeftTupleSource(); - if ( SegmentUtilities.isRootNode(endNode, removingRule)) { + LeftTupleSource tupleSource = pmem.getPathEndNode().getLeftTupleSource(); + if ( SegmentUtilities.isRootNode(pmem.getPathEndNode(), removingRule)) { counter++; } diff --git a/drools-core/src/main/java/org/drools/core/reteoo/RightInputAdapterNode.java b/drools-core/src/main/java/org/drools/core/reteoo/RightInputAdapterNode.java index 551660c40d5..0712342e9e5 100644 --- a/drools-core/src/main/java/org/drools/core/reteoo/RightInputAdapterNode.java +++ b/drools-core/src/main/java/org/drools/core/reteoo/RightInputAdapterNode.java @@ -132,7 +132,7 @@ public RiaNodeMemory createMemory(final RuleBaseConfiguration config, InternalWo RiaNodeMemory rianMem = new RiaNodeMemory(); RiaPathMemory pmem = new RiaPathMemory(this); - AbstractTerminalNode.initPathMemory(pmem, this, getStartTupleSource(), wm, null ); + AbstractTerminalNode.initPathMemory(pmem, getStartTupleSource(), wm, null); rianMem.setRiaPathMemory(pmem); return rianMem;