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

mariofusco pushed a commit to branch 8.44.x
in repository https://gitbox.apache.org/repos/asf/incubator-kie-drools.git


The following commit(s) were added to refs/heads/8.44.x by this push:
     new 29ae61b055 [KIE-1064] simplify session serialization by adding dormant 
activations to rule executor (#5852)
29ae61b055 is described below

commit 29ae61b0550128600c2f7cd4a762a4d856c9dcf5
Author: mdproctor <[email protected]>
AuthorDate: Fri Apr 19 06:14:45 2024 +0100

    [KIE-1064] simplify session serialization by adding dormant activations to 
rule executor (#5852)
    
    backported from main
---
 .../org/drools/core/common/ActivationsManager.java |   2 +-
 .../drools/core/common/AgendaGroupsManager.java    |   8 +-
 .../org/drools/core/phreak/EagerPhreakBuilder.java |   5 +-
 .../org/drools/core/phreak/LazyPhreakBuilder.java  |   5 +-
 .../org/drools/core/phreak/PhreakBranchNode.java   |  42 ++--
 .../drools/core/phreak/PhreakRuleTerminalNode.java |  84 ++++----
 .../java/org/drools/core/phreak/RuleExecutor.java  | 135 +++++++++---
 .../org/drools/core/reteoo/AlphaTerminalNode.java  |   8 +-
 .../drools/core/reteoo/ModifyPreviousTuples.java   |   2 +-
 .../org/drools/core/reteoo/RuleTerminalNode.java   |   2 +-
 .../core/reteoo/RuleTerminalNodeLeftTuple.java     |  19 +-
 .../main/java/org/drools/core/util/LinkedList.java |   2 +-
 .../java/org/drools/core/util/index/TupleList.java |  14 +-
 .../drools/kiesession/agenda/DefaultAgenda.java    |   2 +-
 .../iterators/PhreakActivationIterator.java        | 230 +++------------------
 .../integrationtests/ExecutionFlowControlTest.java |  12 +-
 ...MaintenanceSystemRuleTerminalNodeLeftTuple.java |   2 +-
 17 files changed, 252 insertions(+), 322 deletions(-)

diff --git 
a/drools-core/src/main/java/org/drools/core/common/ActivationsManager.java 
b/drools-core/src/main/java/org/drools/core/common/ActivationsManager.java
index bee0ce5d22..14139c6c23 100644
--- a/drools-core/src/main/java/org/drools/core/common/ActivationsManager.java
+++ b/drools-core/src/main/java/org/drools/core/common/ActivationsManager.java
@@ -93,7 +93,7 @@ public interface ActivationsManager {
         if (!ruleAgendaItem.isQueued()) {
             
ruleAgendaItem.getRuleExecutor().getPathMemory().queueRuleAgendaItem(this);
         }
-        ruleAgendaItem.getRuleExecutor().addLeftTuple( justified.getTuple() );
+        
ruleAgendaItem.getRuleExecutor().modifyActiveTuple((RuleTerminalNodeLeftTuple) 
justified.getTuple() );
     }
 
     default ActivationsManager getPartitionedAgenda(int partitionNr) {
diff --git 
a/drools-core/src/main/java/org/drools/core/common/AgendaGroupsManager.java 
b/drools-core/src/main/java/org/drools/core/common/AgendaGroupsManager.java
index 320be2dd17..73b5337bd9 100644
--- a/drools-core/src/main/java/org/drools/core/common/AgendaGroupsManager.java
+++ b/drools-core/src/main/java/org/drools/core/common/AgendaGroupsManager.java
@@ -216,8 +216,8 @@ public interface AgendaGroupsManager extends Externalizable 
{
             }
             int count = 0;
             for ( RuleAgendaItem item : mainAgendaGroup.getActivations() ) {
-                if (!(item.getRuleExecutor().getLeftTupleList().isEmpty())) {
-                    count = count + 
item.getRuleExecutor().getLeftTupleList().size();
+                if (!(item.getRuleExecutor().getActiveMatches().isEmpty())) {
+                    count = count + 
item.getRuleExecutor().getActiveMatches().size();
                 }
             }
             return count;
@@ -510,8 +510,8 @@ public interface AgendaGroupsManager extends Externalizable 
{
 
             int count = 0;
             for ( RuleAgendaItem item : group.getActivations() ) {
-                if (!item.getRuleExecutor().getLeftTupleList().isEmpty()) {
-                    count = count + 
item.getRuleExecutor().getLeftTupleList().size();
+                if (!item.getRuleExecutor().getActiveMatches().isEmpty()) {
+                    count = count + 
item.getRuleExecutor().getActiveMatches().size();
                 }
             }
             return count;
diff --git 
a/drools-core/src/main/java/org/drools/core/phreak/EagerPhreakBuilder.java 
b/drools-core/src/main/java/org/drools/core/phreak/EagerPhreakBuilder.java
index 3c58d684a5..765b26b77d 100644
--- a/drools-core/src/main/java/org/drools/core/phreak/EagerPhreakBuilder.java
+++ b/drools-core/src/main/java/org/drools/core/phreak/EagerPhreakBuilder.java
@@ -47,6 +47,7 @@ import org.drools.core.reteoo.PathMemory;
 import org.drools.core.reteoo.QueryElementNode;
 import org.drools.core.reteoo.RightInputAdapterNode;
 import org.drools.core.reteoo.RightTuple;
+import org.drools.core.reteoo.RuleTerminalNodeLeftTuple;
 import org.drools.core.reteoo.RuntimeComponentFactory;
 import org.drools.core.reteoo.SegmentMemory;
 import org.drools.core.reteoo.SegmentMemory.MemoryPrototype;
@@ -1224,7 +1225,7 @@ public class EagerPhreakBuilder implements PhreakBuilder {
                 TerminalNode rtn = ( TerminalNode ) node;
                 InternalAgenda agenda = wm.getAgenda();
                 RuleAgendaItem agendaItem = 
AlphaTerminalNode.getRuleAgendaItem( wm, agenda, rtn, insert );
-                PhreakRuleTerminalNode.doLeftTupleInsert( rtn, 
agendaItem.getRuleExecutor(), agenda, agendaItem, peer );
+                PhreakRuleTerminalNode.doLeftTupleInsert( rtn, 
agendaItem.getRuleExecutor(), agenda, agendaItem, (RuleTerminalNodeLeftTuple) 
peer);
             }
             return peer;
         }
@@ -1253,7 +1254,7 @@ public class EagerPhreakBuilder implements PhreakBuilder {
         if (NodeTypeEnums.isTerminalNode(lt.getTupleSink())) {
             PathMemory pmem = (PathMemory) 
wm.getNodeMemories().peekNodeMemory( lt.getTupleSink() );
             if (pmem != null) {
-                PhreakRuleTerminalNode.doLeftDelete( 
pmem.getActualActivationsManager( wm ), 
pmem.getRuleAgendaItem().getRuleExecutor(), lt );
+                PhreakRuleTerminalNode.doLeftDelete( 
pmem.getActualActivationsManager( wm ), 
pmem.getRuleAgendaItem().getRuleExecutor(), (RuleTerminalNodeLeftTuple) lt );
             }
         } else {
             if (lt.getContextObject() instanceof AccumulateContext) {
diff --git 
a/drools-core/src/main/java/org/drools/core/phreak/LazyPhreakBuilder.java 
b/drools-core/src/main/java/org/drools/core/phreak/LazyPhreakBuilder.java
index 698e2fb244..862f828189 100644
--- a/drools-core/src/main/java/org/drools/core/phreak/LazyPhreakBuilder.java
+++ b/drools-core/src/main/java/org/drools/core/phreak/LazyPhreakBuilder.java
@@ -57,6 +57,7 @@ import org.drools.core.reteoo.QueryElementNode;
 import org.drools.core.reteoo.RightInputAdapterNode;
 import org.drools.core.reteoo.RightInputAdapterNode.RiaPathMemory;
 import org.drools.core.reteoo.RightTuple;
+import org.drools.core.reteoo.RuleTerminalNodeLeftTuple;
 import org.drools.core.reteoo.RuntimeComponentFactory;
 import org.drools.core.reteoo.SegmentMemory;
 import org.drools.core.reteoo.SegmentNodeMemory;
@@ -975,7 +976,7 @@ class LazyPhreakBuilder implements PhreakBuilder {
                 TerminalNode rtn = ( TerminalNode ) node;
                 InternalAgenda agenda = wm.getAgenda();
                 RuleAgendaItem agendaItem = 
AlphaTerminalNode.getRuleAgendaItem( wm, agenda, rtn, insert );
-                PhreakRuleTerminalNode.doLeftTupleInsert( rtn, 
agendaItem.getRuleExecutor(), agenda, agendaItem, peer );
+                PhreakRuleTerminalNode.doLeftTupleInsert( rtn, 
agendaItem.getRuleExecutor(), agenda, agendaItem, (RuleTerminalNodeLeftTuple) 
peer);
             }
             return peer;
         }
@@ -1004,7 +1005,7 @@ class LazyPhreakBuilder implements PhreakBuilder {
         if (NodeTypeEnums.isTerminalNode(lt.getTupleSink())) {
             PathMemory pmem = (PathMemory) 
wm.getNodeMemories().peekNodeMemory( lt.getTupleSink() );
             if (pmem != null) {
-                PhreakRuleTerminalNode.doLeftDelete( 
pmem.getActualActivationsManager( wm ), 
pmem.getRuleAgendaItem().getRuleExecutor(), lt );
+                PhreakRuleTerminalNode.doLeftDelete( 
pmem.getActualActivationsManager( wm ), 
pmem.getRuleAgendaItem().getRuleExecutor(), (RuleTerminalNodeLeftTuple) lt );
             }
         } else {
             if (lt.getContextObject() instanceof AccumulateContext) {
diff --git 
a/drools-core/src/main/java/org/drools/core/phreak/PhreakBranchNode.java 
b/drools-core/src/main/java/org/drools/core/phreak/PhreakBranchNode.java
index 8cd2b535c9..d72d9a606c 100644
--- a/drools-core/src/main/java/org/drools/core/phreak/PhreakBranchNode.java
+++ b/drools-core/src/main/java/org/drools/core/phreak/PhreakBranchNode.java
@@ -15,6 +15,7 @@
 
 package org.drools.core.phreak;
 
+import org.drools.base.reteoo.NodeTypeEnums;
 import org.drools.core.common.ActivationsManager;
 import org.drools.core.common.TupleSets;
 import org.drools.core.reteoo.ConditionalBranchEvaluator;
@@ -24,6 +25,7 @@ import 
org.drools.core.reteoo.ConditionalBranchNode.ConditionalBranchMemory;
 import org.drools.core.reteoo.LeftTuple;
 import org.drools.core.reteoo.LeftTupleSink;
 import org.drools.core.reteoo.RuleTerminalNode;
+import org.drools.core.reteoo.RuleTerminalNodeLeftTuple;
 
 import static 
org.drools.core.phreak.RuleNetworkEvaluator.normalizeStagedTuples;
 
@@ -62,8 +64,6 @@ public class PhreakBranchNode {
                               RuleExecutor executor) {
         ConditionalBranchEvaluator branchEvaluator = 
branchNode.getBranchEvaluator();
 
-        RuleAgendaItem ruleAgendaItem = executor.getRuleAgendaItem();
-
         for (LeftTuple leftTuple = srcLeftTuples.getInsertFirst(); leftTuple 
!= null; ) {
             LeftTuple next = leftTuple.getStagedNext();
 
@@ -74,9 +74,10 @@ public class PhreakBranchNode {
 
             if (conditionalExecution != null) {
                 RuleTerminalNode rtn = (RuleTerminalNode) 
conditionalExecution.getSink().getFirstLeftTupleSink();
-                LeftTuple branchedLeftTuple = rtn.createLeftTuple(leftTuple,
-                                                                  rtn,
-                                                                  
leftTuple.getPropagationContext(), useLeftMemory);
+                RuleTerminalNodeLeftTuple branchedLeftTuple = 
(RuleTerminalNodeLeftTuple) rtn.createLeftTuple(leftTuple,
+                                                                               
                               rtn,
+                                                                               
                               leftTuple.getPropagationContext(),
+                                                                               
                               useLeftMemory);
                 PhreakRuleTerminalNode.doLeftTupleInsert( rtn, executor, 
activationsManager,
                                                           
executor.getRuleAgendaItem(), branchedLeftTuple) ;
                 breaking = conditionalExecution.isBreaking();
@@ -102,7 +103,6 @@ public class PhreakBranchNode {
                               TupleSets<LeftTuple> stagedLeftTuples,
                               RuleExecutor executor) {
         ConditionalBranchEvaluator branchEvaluator = 
branchNode.getBranchEvaluator();
-        RuleAgendaItem ruleAgendaItem = executor.getRuleAgendaItem();
 
         for (LeftTuple leftTuple = srcLeftTuples.getUpdateFirst(); leftTuple 
!= null; ) {
             LeftTuple next = leftTuple.getStagedNext();
@@ -129,7 +129,7 @@ public class PhreakBranchNode {
                 if (newRtn == null) {
                     // old exits, new does not, so delete
                     if ( branchTuples.rtnLeftTuple.getMemory() != null ) {
-                        executor.removeLeftTuple(branchTuples.rtnLeftTuple);
+                        executor.removeActiveTuple(branchTuples.rtnLeftTuple);
                     }
                     PhreakRuleTerminalNode.doLeftDelete(activationsManager, 
executor, branchTuples.rtnLeftTuple);
 
@@ -140,21 +140,21 @@ public class PhreakBranchNode {
                 } else {
                     // old and new on different branches, delete one and 
insert the other
                     if ( branchTuples.rtnLeftTuple.getMemory() != null ) {
-                        executor.removeLeftTuple(branchTuples.rtnLeftTuple);
+                        executor.removeActiveTuple(branchTuples.rtnLeftTuple);
                     }
                     PhreakRuleTerminalNode.doLeftDelete(activationsManager, 
executor, branchTuples.rtnLeftTuple);
 
-                    branchTuples.rtnLeftTuple = 
newRtn.createLeftTuple(leftTuple,
-                                                                       newRtn,
-                                                                       
leftTuple.getPropagationContext(), true);
+                    branchTuples.rtnLeftTuple = (RuleTerminalNodeLeftTuple) 
newRtn.createLeftTuple(leftTuple,
+                                                                               
                    newRtn,
+                                                                               
                    leftTuple.getPropagationContext(), true);
                     PhreakRuleTerminalNode.doLeftTupleInsert( newRtn, 
executor, activationsManager,
                                                               
executor.getRuleAgendaItem(), branchTuples.rtnLeftTuple) ;
                 }
 
             } else if (newRtn != null) {
                 // old does not exist, new exists, so insert
-                branchTuples.rtnLeftTuple = newRtn.createLeftTuple(leftTuple, 
newRtn,
-                                                                   
leftTuple.getPropagationContext(), true);
+                branchTuples.rtnLeftTuple = (RuleTerminalNodeLeftTuple) 
newRtn.createLeftTuple(leftTuple, newRtn,
+                                                                               
                leftTuple.getPropagationContext(), true);
                 PhreakRuleTerminalNode.doLeftTupleInsert( newRtn, executor, 
activationsManager,
                                                           
executor.getRuleAgendaItem(), branchTuples.rtnLeftTuple) ;
             }
@@ -163,12 +163,12 @@ public class PhreakBranchNode {
             if (branchTuples.mainLeftTuple != null) {
                 normalizeStagedTuples( stagedLeftTuples, 
branchTuples.mainLeftTuple );
 
-                if (!breaking) {
-                    // child exist, new one does, so update
-                    trgLeftTuples.addUpdate(branchTuples.mainLeftTuple);
-                } else {
+                if (breaking && 
!NodeTypeEnums.isTerminalNode(branchTuples.mainLeftTuple.getTupleSink())) {
                     // child exist, new one does not, so delete
                     trgLeftTuples.addDelete(branchTuples.mainLeftTuple);
+                } else {
+                    // child exist, new one does, so update
+                    trgLeftTuples.addUpdate(branchTuples.mainLeftTuple);
                 }
             } else if (!breaking) {
                 // child didn't exist, new one does, so insert
@@ -195,7 +195,7 @@ public class PhreakBranchNode {
 
             if (branchTuples.rtnLeftTuple != null) {
                 if ( branchTuples.rtnLeftTuple.getMemory() != null ) {
-                    executor.removeLeftTuple(branchTuples.rtnLeftTuple);
+                    executor.removeActiveTuple(branchTuples.rtnLeftTuple);
                 }
                 PhreakRuleTerminalNode.doLeftDelete(activationsManager, 
executor, branchTuples.rtnLeftTuple);
             }
@@ -225,14 +225,14 @@ public class PhreakBranchNode {
             if ( child.getTupleSink() == sink ) {
                 branchTuples.mainLeftTuple = child;
             } else {
-                branchTuples.rtnLeftTuple = child;
+                branchTuples.rtnLeftTuple = (RuleTerminalNodeLeftTuple) child;
             }
             child = child.getHandleNext();
             if ( child != null ) {
                 if ( child.getTupleSink() == sink ) {
                     branchTuples.mainLeftTuple = child;
                 } else {
-                    branchTuples.rtnLeftTuple = child;
+                    branchTuples.rtnLeftTuple = (RuleTerminalNodeLeftTuple) 
child;
                 }
             }
         }
@@ -240,7 +240,7 @@ public class PhreakBranchNode {
     }
 
     private static class BranchTuples {
-        LeftTuple rtnLeftTuple;
+        RuleTerminalNodeLeftTuple rtnLeftTuple;
         LeftTuple mainLeftTuple;
     }
 }
diff --git 
a/drools-core/src/main/java/org/drools/core/phreak/PhreakRuleTerminalNode.java 
b/drools-core/src/main/java/org/drools/core/phreak/PhreakRuleTerminalNode.java
index 1ea2957922..2e2f0c1709 100644
--- 
a/drools-core/src/main/java/org/drools/core/phreak/PhreakRuleTerminalNode.java
+++ 
b/drools-core/src/main/java/org/drools/core/phreak/PhreakRuleTerminalNode.java
@@ -33,13 +33,6 @@ import org.drools.core.rule.consequence.InternalMatch;
 import org.kie.api.definition.rule.Rule;
 import org.kie.api.event.rule.MatchCancelledCause;
 
-/**
-* Created with IntelliJ IDEA.
-* User: mdproctor
-* Date: 03/05/2013
-* Time: 15:42
-* To change this template use File | Settings | File Templates.
-*/
 public class PhreakRuleTerminalNode {
     public void doNode(TerminalNode rtnNode,
                        ActivationsManager activationsManager,
@@ -70,8 +63,8 @@ public class PhreakRuleTerminalNode {
             activationsManager.getAgendaGroupsManager().setFocus( 
ruleAgendaItem.getAgendaGroup() );
         }
 
-        for (LeftTuple leftTuple = srcLeftTuples.getInsertFirst(); leftTuple 
!= null; ) {
-            LeftTuple next = leftTuple.getStagedNext();
+        for (RuleTerminalNodeLeftTuple leftTuple = (RuleTerminalNodeLeftTuple) 
srcLeftTuples.getInsertFirst(); leftTuple != null; ) {
+            RuleTerminalNodeLeftTuple next = (RuleTerminalNodeLeftTuple) 
leftTuple.getStagedNext();
 
             doLeftTupleInsert(rtnNode, executor, activationsManager, 
ruleAgendaItem, leftTuple);
 
@@ -91,10 +84,10 @@ public class PhreakRuleTerminalNode {
     }
     public static void doLeftTupleInsert(TerminalNode rtnNode, RuleExecutor 
executor,
                                          ActivationsManager 
activationsManager, RuleAgendaItem ruleAgendaItem,
-                                         LeftTuple leftTuple) {
+                                         RuleTerminalNodeLeftTuple leftTuple) {
         ReteEvaluator reteEvaluator = activationsManager.getReteEvaluator();
         if ( reteEvaluator.getRuleSessionConfiguration().isDirectFiring() ) {
-            executor.addLeftTuple(leftTuple);
+            executor.addActiveTuple(leftTuple);
             return;
         }
 
@@ -108,32 +101,32 @@ public class PhreakRuleTerminalNode {
             pctx = leftTuple.getPropagationContext();
         }
 
-        int salienceInt = getSalienceValue(rtnNode, ruleAgendaItem, 
(InternalMatch) leftTuple, reteEvaluator);
+        int salienceInt = getSalienceValue(rtnNode, ruleAgendaItem, leftTuple, 
reteEvaluator);
 
-        RuleTerminalNodeLeftTuple rtnLeftTuple = (RuleTerminalNodeLeftTuple) 
leftTuple;
-        activationsManager.createAgendaItem( rtnLeftTuple, salienceInt, pctx, 
ruleAgendaItem, ruleAgendaItem.getAgendaGroup() );
+        activationsManager.createAgendaItem( leftTuple, salienceInt, pctx, 
ruleAgendaItem, ruleAgendaItem.getAgendaGroup() );
 
-        
activationsManager.getAgendaEventSupport().fireActivationCreated(rtnLeftTuple, 
activationsManager.getReteEvaluator());
+        
activationsManager.getAgendaEventSupport().fireActivationCreated(leftTuple, 
activationsManager.getReteEvaluator());
 
         if ( rtnNode.getRule().isLockOnActive() && pctx.getType() != 
PropagationContext.Type.RULE_ADDITION ) {
             pctx = leftTuple.findMostRecentPropagationContext();
             InternalAgendaGroup agendaGroup = 
executor.getRuleAgendaItem().getAgendaGroup();
             if (blockedByLockOnActive(rtnNode.getRule(), pctx, agendaGroup)) {
-                
activationsManager.getAgendaEventSupport().fireActivationCancelled(rtnLeftTuple,
 reteEvaluator, MatchCancelledCause.FILTER );
+                
activationsManager.getAgendaEventSupport().fireActivationCancelled(leftTuple, 
reteEvaluator, MatchCancelledCause.FILTER );
                 return;
             }
         }
 
-        if (activationsManager.getActivationsFilter() != null && 
!activationsManager.getActivationsFilter().accept( rtnLeftTuple )) {
+        if (activationsManager.getActivationsFilter() != null && 
!activationsManager.getActivationsFilter().accept( leftTuple )) {
             // only relevant for seralization, to not refire Matches already 
fired
+            executor.addDormantTuple(leftTuple );
             return;
         }
 
-        executor.addLeftTuple( leftTuple );
+        executor.addActiveTuple(leftTuple);
 
-        activationsManager.addItemToActivationGroup( rtnLeftTuple );
+        activationsManager.addItemToActivationGroup( leftTuple );
         if ( !rtnNode.isFireDirect() && executor.isDeclarativeAgendaEnabled() 
) {
-            insertAndStageActivation( reteEvaluator, rtnLeftTuple );
+            insertAndStageActivation( reteEvaluator, leftTuple );
         }
     }
 
@@ -160,8 +153,8 @@ public class PhreakRuleTerminalNode {
             
activationsManager.getAgendaGroupsManager().setFocus(ruleAgendaItem.getAgendaGroup());
         }
 
-        for (LeftTuple leftTuple = srcLeftTuples.getUpdateFirst(); leftTuple 
!= null; ) {
-            LeftTuple next = leftTuple.getStagedNext();
+        for (RuleTerminalNodeLeftTuple leftTuple = (RuleTerminalNodeLeftTuple) 
srcLeftTuples.getUpdateFirst(); leftTuple != null; ) {
+            RuleTerminalNodeLeftTuple next = (RuleTerminalNodeLeftTuple) 
leftTuple.getStagedNext();
 
             doLeftTupleUpdate(rtnNode, executor, activationsManager, 
leftTuple);
 
@@ -171,14 +164,13 @@ public class PhreakRuleTerminalNode {
     }
 
     public static void doLeftTupleUpdate(TerminalNode rtnNode, RuleExecutor 
executor,
-                                         ActivationsManager 
activationsManager, LeftTuple leftTuple) {
-        RuleTerminalNodeLeftTuple rtnLeftTuple = (RuleTerminalNodeLeftTuple) 
leftTuple;
+                                         ActivationsManager 
activationsManager, RuleTerminalNodeLeftTuple leftTuple) {
         ReteEvaluator reteEvaluator = activationsManager.getReteEvaluator();
 
         if ( reteEvaluator.getRuleSessionConfiguration().isDirectFiring() ) {
-            if (!rtnLeftTuple.isQueued() ) {
-                executor.addLeftTuple( leftTuple );
-                reteEvaluator.getRuleEventSupport().onUpdateMatch( 
rtnLeftTuple );
+            if (!leftTuple.isQueued() ) {
+                executor.modifyActiveTuple(leftTuple );
+                reteEvaluator.getRuleEventSupport().onUpdateMatch( leftTuple );
             }
             return;
         }
@@ -187,7 +179,7 @@ public class PhreakRuleTerminalNode {
 
         boolean blocked = false;
         if ( executor.isDeclarativeAgendaEnabled() ) {
-           if ( rtnLeftTuple.hasBlockers() ) {
+           if ( leftTuple.hasBlockers() ) {
                blocked = true; // declarativeAgenda still blocking LeftTuple, 
so don't add back ot list
            }
         } else {
@@ -197,10 +189,11 @@ public class PhreakRuleTerminalNode {
             }
         }
 
-        int salienceInt = getSalienceValue(rtnNode, 
executor.getRuleAgendaItem(), (InternalMatch) leftTuple, reteEvaluator);
+        int salienceInt = getSalienceValue(rtnNode, 
executor.getRuleAgendaItem(), leftTuple, reteEvaluator);
         
-        if (activationsManager.getActivationsFilter() != null && 
!activationsManager.getActivationsFilter().accept( rtnLeftTuple)) {
+        if (activationsManager.getActivationsFilter() != null && 
!activationsManager.getActivationsFilter().accept( leftTuple)) {
             // only relevant for serialization, to not re-fire Matches already 
fired
+            executor.addDormantTuple(leftTuple);
             return;
         }
         
@@ -214,23 +207,23 @@ public class PhreakRuleTerminalNode {
                 }
             }
             if ( addToExector ) {
-                if (!rtnLeftTuple.isQueued() ) {
+                if (!leftTuple.isQueued() ) {
                     // not queued, so already fired, so it's effectively 
recreated
-                    
activationsManager.getAgendaEventSupport().fireActivationCreated( rtnLeftTuple, 
reteEvaluator );
+                    
activationsManager.getAgendaEventSupport().fireActivationCreated( leftTuple, 
reteEvaluator );
 
-                    rtnLeftTuple.update( salienceInt, pctx );
-                    executor.addLeftTuple( leftTuple );
-                    reteEvaluator.getRuleEventSupport().onUpdateMatch( 
rtnLeftTuple );
+                    leftTuple.update( salienceInt, pctx );
+                    executor.modifyActiveTuple(leftTuple );
+                    reteEvaluator.getRuleEventSupport().onUpdateMatch( 
leftTuple );
                 }
             }
 
         } else {
             // LeftTuple is blocked, and thus not queued, so just update it's 
values
-            rtnLeftTuple.update(salienceInt, pctx);
+            leftTuple.update(salienceInt, pctx);
         }
 
         if( !rtnNode.isFireDirect() && executor.isDeclarativeAgendaEnabled()) {
-            modifyActivation(reteEvaluator, rtnLeftTuple);
+            modifyActivation(reteEvaluator, leftTuple);
         }
     }
 
@@ -249,22 +242,23 @@ public class PhreakRuleTerminalNode {
 
         for (LeftTuple leftTuple = srcLeftTuples.getDeleteFirst(); leftTuple 
!= null; ) {
             LeftTuple next = leftTuple.getStagedNext();
-            doLeftDelete(activationsManager, executor, leftTuple);
+            doLeftDelete(activationsManager, executor, 
(RuleTerminalNodeLeftTuple) leftTuple);
 
             leftTuple.clearStaged();
             leftTuple = next;
         }
     }
 
-    public static void doLeftDelete(ActivationsManager activationsManager, 
RuleExecutor executor, Tuple leftTuple) {
-        RuleTerminalNodeLeftTuple rtnLt = ( RuleTerminalNodeLeftTuple ) 
leftTuple;
-        rtnLt.setMatched( false );
+    public static void doLeftDelete(ActivationsManager activationsManager, 
RuleExecutor executor, RuleTerminalNodeLeftTuple leftTuple) {
+        leftTuple.setMatched( false );
 
-        rtnLt.cancelActivation( activationsManager );
+        leftTuple.cancelActivation( activationsManager );
 
         if ( leftTuple.getMemory() != null ) {
             // Expiration propagations should not be removed from the list, as 
they still need to fire
-            executor.removeLeftTuple(leftTuple);
+            executor.removeActiveTuple( leftTuple );
+        } else if ( leftTuple.getStagedType() == Tuple.DELETE && 
!leftTuple.isQueued() ) {
+            executor.removeDormantTuple( leftTuple );
         }
 
         leftTuple.setContextObject( null );
@@ -282,10 +276,10 @@ public class PhreakRuleTerminalNode {
             if ( isActive && activatedForRecency < handleRecency &&
                  agendaGroup.getAutoFocusActivator() != pctx ) {
                 return true;
-            } else {
-                return clearedForRecency != -1 && clearedForRecency >= 
handleRecency;
             }
 
+            return clearedForRecency != -1 && clearedForRecency >= 
handleRecency;
+
         }
         return false;
     }
diff --git a/drools-core/src/main/java/org/drools/core/phreak/RuleExecutor.java 
b/drools-core/src/main/java/org/drools/core/phreak/RuleExecutor.java
index df3b9f06c7..64d677ddbd 100644
--- a/drools-core/src/main/java/org/drools/core/phreak/RuleExecutor.java
+++ b/drools-core/src/main/java/org/drools/core/phreak/RuleExecutor.java
@@ -27,12 +27,14 @@ import org.drools.core.common.ReteEvaluator;
 import org.drools.core.conflict.MatchConflictResolver;
 import org.drools.core.conflict.RuleAgendaConflictResolver;
 import org.drools.core.event.RuleEventListenerSupport;
+import org.drools.core.reteoo.AbstractTuple;
 import org.drools.core.reteoo.PathMemory;
 import org.drools.core.reteoo.RuleTerminalNode;
 import org.drools.core.reteoo.RuleTerminalNodeLeftTuple;
 import org.drools.core.reteoo.Tuple;
 import org.drools.core.rule.consequence.InternalMatch;
 import org.drools.core.rule.consequence.KnowledgeHelper;
+import org.drools.core.util.LinkedList;
 import org.drools.core.util.Queue;
 import org.drools.core.util.QueueFactory;
 import org.drools.core.util.index.TupleList;
@@ -44,12 +46,15 @@ import org.slf4j.LoggerFactory;
 
 public class RuleExecutor {
 
+    private static final boolean DEBUG_DORMANT_TUPLE = true;
+
     protected static final Logger log = 
LoggerFactory.getLogger(RuleExecutor.class);
 
     private final PathMemory pmem;
-    private final RuleAgendaItem ruleAgendaItem;
-    private final TupleList tupleList;
-    private final Queue<InternalMatch> queue;
+    private final RuleAgendaItem       ruleAgendaItem;
+    private final TupleList                 activeMatches;
+    private final DormantTupleList dormantMatches;
+    private final Queue<InternalMatch>      queue;
     private volatile boolean dirty;
     private final boolean declarativeAgendaEnabled;
     private boolean fireExitedEarly;
@@ -58,12 +63,38 @@ public class RuleExecutor {
             RuleAgendaItem ruleAgendaItem,
             boolean declarativeAgendaEnabled) {
         this.pmem = pmem;
-        this.ruleAgendaItem = ruleAgendaItem;
-        this.tupleList = new TupleList();
+        this.ruleAgendaItem           = ruleAgendaItem;
+        this.activeMatches            = new TupleList();
+        this.dormantMatches           = new DormantTupleList();
         this.declarativeAgendaEnabled = declarativeAgendaEnabled;
         this.queue = ruleAgendaItem.getRule().getSalience().isDynamic() ? 
QueueFactory.createQueue(MatchConflictResolver.INSTANCE) : null;
     }
 
+    public static class DormantTupleList<C> extends TupleList<C> {
+        public DormantTupleList() {
+        }
+
+        public DormantTupleList(C c) {
+            super(c);
+        }
+
+        public DormantTupleList( Tuple first, Tuple last, int size ) {
+            super( first, last, size );
+        }
+
+        public void add(final Tuple tuple) {
+            if ( this.last != null ) {
+                this.last.setNext( (AbstractTuple) tuple );
+                tuple.setPrevious( this.last );
+                this.last = tuple;
+            } else {
+                this.first = tuple;
+                this.last = tuple;
+            }
+            this.size++;
+        }
+    }
+
     public int evaluateNetworkAndFire( ReteEvaluator reteEvaluator,
                                        AgendaFilter filter,
                                        int fireCount,
@@ -85,15 +116,15 @@ public class RuleExecutor {
 
     private int doDirectFirings(ActivationsManager activationsManager, 
AgendaFilter filter, ReteEvaluator reteEvaluator) {
         RuleTerminalNode rtn = (RuleTerminalNode) pmem.getPathEndNode();
-        int directFirings = tupleList.size();
+        int directFirings = activeMatches.size();
 
-        for (Tuple tuple = tupleList.getFirst(); tuple != null; tuple = 
tupleList.getFirst()) {
+        for (Tuple tuple = activeMatches.getFirst(); tuple != null; tuple = 
activeMatches.getFirst()) {
             if (cancelAndContinue(reteEvaluator, rtn, tuple, filter)) {
                 directFirings--;
             } else {
                 fireActivationEvent(reteEvaluator, activationsManager, 
(InternalMatch) tuple, ((InternalMatch) tuple).getConsequence());
             }
-            removeLeftTuple( tuple );
+            removeActiveTuple((RuleTerminalNodeLeftTuple) tuple);
         }
         ruleAgendaItem.remove();
         return directFirings;
@@ -114,7 +145,7 @@ public class RuleExecutor {
                       int fireLimit) {
         int localFireCount = 0;
 
-        if (!tupleList.isEmpty()) {
+        if (!activeMatches.isEmpty()) {
             if (!fireExitedEarly && isDeclarativeAgendaEnabled()) {
                 // Network Evaluation can notify meta rules, which should be 
given a chance to fire first
                 RuleAgendaItem nextRule = activationsManager.peekNextRule();
@@ -185,17 +216,19 @@ public class RuleExecutor {
     }
 
     private Tuple getNextTuple() {
-        if (tupleList.isEmpty()) {
+        if (activeMatches.isEmpty()) {
             return null;
         }
         Tuple leftTuple;
         if (queue != null) {
             leftTuple = (Tuple) queue.dequeue();
-            tupleList.remove(leftTuple);
+            activeMatches.remove(leftTuple);
         } else {
-            leftTuple = tupleList.removeFirst();
+            leftTuple = activeMatches.removeFirst();
             ((InternalMatch) leftTuple).setQueued(false);
         }
+
+        addDormantTuple((RuleTerminalNodeLeftTuple) leftTuple);
         return leftTuple;
     }
 
@@ -204,7 +237,7 @@ public class RuleExecutor {
     }
 
     public void removeRuleAgendaItemWhenEmpty(ReteEvaluator reteEvaluator) {
-        if (!dirty && tupleList.isEmpty()) {
+        if (!dirty && activeMatches.isEmpty()) {
             if (log.isTraceEnabled()) {
                 log.trace("Removing RuleAgendaItem " + ruleAgendaItem);
             }
@@ -280,40 +313,81 @@ public class RuleExecutor {
         return RuleAgendaConflictResolver.doCompare(ruleAgendaItem, nextRule) 
>= 0;
     }
 
-    public TupleList getLeftTupleList() {
-        return tupleList;
+    public TupleList getActiveMatches() {
+        return activeMatches;
+    }
+
+    public DormantTupleList getDormantMatches() {
+        return dormantMatches;
+    }
+
+    public void addDormantTuple(RuleTerminalNodeLeftTuple tuple) {
+        if (DEBUG_DORMANT_TUPLE) {
+            if (tuple.isDormant()) {
+                throw new IllegalStateException();
+            }
+        }
+        dormantMatches.add(tuple);
+        if (DEBUG_DORMANT_TUPLE) {
+            tuple.setDormant(true);
+        }
     }
 
-    public void addLeftTuple(Tuple tuple) {
-        ((InternalMatch) tuple).setQueued(true);
-        this.tupleList.add(tuple);
+    public void removeDormantTuple(RuleTerminalNodeLeftTuple tuple) {
+        if (DEBUG_DORMANT_TUPLE) {
+            if (!tuple.isDormant()) {
+                throw new IllegalStateException();
+            }
+        }
+        dormantMatches.remove(tuple);
+        if (DEBUG_DORMANT_TUPLE) {
+            tuple.setDormant(false);
+        }
+    }
+
+    public void addActiveTuple(RuleTerminalNodeLeftTuple tuple) {
+        tuple.setQueued(true);
+        if (DEBUG_DORMANT_TUPLE) {
+            if (tuple.isDormant()) {
+                throw new IllegalStateException();
+            }
+        }
+        this.activeMatches.add(tuple);
         if (queue != null) {
             addQueuedLeftTuple(tuple);
         }
     }
 
-    public void addQueuedLeftTuple(Tuple tuple) {
-        int currentSalience = queue.isEmpty() ? 0 : queue.peek().getSalience();
-        queue.enqueue((InternalMatch) tuple);
-        updateSalience(currentSalience);
+    public void modifyActiveTuple(RuleTerminalNodeLeftTuple tuple) {
+        removeDormantTuple(tuple);
+        addActiveTuple(tuple);
     }
 
-    public void removeLeftTuple(Tuple tuple) {
-        ((InternalMatch) tuple).setQueued(false);
-        this.tupleList.remove(tuple);
+    public void removeActiveTuple(RuleTerminalNodeLeftTuple tuple) {
+        tuple.setQueued(false);
+        activeMatches.remove(tuple);
+        if (tuple.getStagedType() != Tuple.DELETE) {
+            addDormantTuple(tuple);
+        }
         if (queue != null) {
             removeQueuedLeftTuple(tuple);
         }
     }
 
-    private void removeQueuedLeftTuple(Tuple tuple) {
+    public void addQueuedLeftTuple(RuleTerminalNodeLeftTuple tuple) {
+        int currentSalience = queue.isEmpty() ? 0 : queue.peek().getSalience();
+        queue.enqueue(tuple);
+        updateSalience(currentSalience);
+    }
+
+    private void removeQueuedLeftTuple(RuleTerminalNodeLeftTuple tuple) {
         int currentSalience = queue.isEmpty() ? 0 : queue.peek().getSalience();
-        queue.dequeue(((InternalMatch) tuple));
+        queue.dequeue((tuple));
         updateSalience(currentSalience);
     }
 
     private void updateSalience(int currentSalience) {
-        // the queue may be emtpy if no more matches are left, so reset it to 
default salience 0
+        // the queue may be empty if no more matches are left, so reset it to 
default salience 0
         int newSalience = queue.isEmpty() ? 
SalienceInteger.DEFAULT_SALIENCE.getValue() : queue.peek().getSalience();
         if (currentSalience != newSalience) {
             // salience changed, so the RuleAgendaItem needs to be removed and 
re-added, for sorting
@@ -326,8 +400,8 @@ public class RuleExecutor {
     }
 
     public void cancel(ReteEvaluator reteEvaluator, EventSupport es) {
-        while (!tupleList.isEmpty()) {
-            RuleTerminalNodeLeftTuple rtnLt = (RuleTerminalNodeLeftTuple) 
tupleList.removeFirst();
+        while (!activeMatches.isEmpty()) {
+            RuleTerminalNodeLeftTuple rtnLt = (RuleTerminalNodeLeftTuple) 
activeMatches.removeFirst();
             if (queue != null) {
                 queue.dequeue(rtnLt);
             }
@@ -391,7 +465,6 @@ public class RuleExecutor {
             internalMatch.setActive(false);
             knowledgeHelper.reset();
         } catch ( final Exception e ) {
-            e.printStackTrace();
             
knowledgeHelper.restoreActivationOnConsequenceFailure(internalMatch);
             activationsManager.handleException(internalMatch, e);
         } finally {
diff --git 
a/drools-core/src/main/java/org/drools/core/reteoo/AlphaTerminalNode.java 
b/drools-core/src/main/java/org/drools/core/reteoo/AlphaTerminalNode.java
index ae622a915f..056e7f567d 100644
--- a/drools-core/src/main/java/org/drools/core/reteoo/AlphaTerminalNode.java
+++ b/drools-core/src/main/java/org/drools/core/reteoo/AlphaTerminalNode.java
@@ -42,7 +42,7 @@ public class AlphaTerminalNode extends LeftInputAdapterNode {
         for (int i = 0; i < sinks.length; i++) {
             TerminalNode rtn = ( TerminalNode ) sinks[i];
             RuleAgendaItem agendaItem = getRuleAgendaItem( reteEvaluator, 
activationsManager, rtn, true );
-            LeftTuple leftTuple = rtn.createLeftTuple(factHandle, true );
+            RuleTerminalNodeLeftTuple leftTuple = (RuleTerminalNodeLeftTuple) 
rtn.createLeftTuple(factHandle, true );
             leftTuple.setPropagationContext( propagationContext );
 
             if ( rtn.getRule().getAutoFocus() && 
!agendaItem.getAgendaGroup().isActive() ) {
@@ -71,7 +71,7 @@ public class AlphaTerminalNode extends LeftInputAdapterNode {
                 leftTuple.reAdd();
                 if ( context.getModificationMask().intersects( 
rtn.getLeftInferredMask() ) ) {
                     leftTuple.setPropagationContext( context );
-                    PhreakRuleTerminalNode.doLeftTupleUpdate( rtn, executor, 
activationsManager, leftTuple );
+                    PhreakRuleTerminalNode.doLeftTupleUpdate( rtn, executor, 
activationsManager, (RuleTerminalNodeLeftTuple) leftTuple );
                     if (leftTuple instanceof InternalMatch) {
                         ((InternalMatch) leftTuple).setActive(true);
                     }
@@ -80,7 +80,7 @@ public class AlphaTerminalNode extends LeftInputAdapterNode {
                 if ( context.getModificationMask().intersects( 
rtn.getLeftInferredMask() ) ) {
                     leftTuple = rtn.createLeftTuple( factHandle, true );
                     leftTuple.setPropagationContext( context );
-                    PhreakRuleTerminalNode.doLeftTupleInsert( rtn, executor, 
activationsManager, agendaItem, leftTuple );
+                    PhreakRuleTerminalNode.doLeftTupleInsert( rtn, executor, 
activationsManager, agendaItem, (RuleTerminalNodeLeftTuple) leftTuple );
                 }
             }
         }
@@ -91,7 +91,7 @@ public class AlphaTerminalNode extends LeftInputAdapterNode {
         ActivationsManager activationsManager = 
reteEvaluator.getActivationsManager();
         leftTuple.setPropagationContext( context );
         TerminalNode rtn = (TerminalNode) leftTuple.getTupleSink();
-        PhreakRuleTerminalNode.doLeftDelete( activationsManager, 
getRuleAgendaItem( reteEvaluator, activationsManager, rtn, false 
).getRuleExecutor(), leftTuple );
+        PhreakRuleTerminalNode.doLeftDelete( activationsManager, 
getRuleAgendaItem( reteEvaluator, activationsManager, rtn, false 
).getRuleExecutor(), (RuleTerminalNodeLeftTuple) leftTuple );
     }
 
     public static RuleAgendaItem getRuleAgendaItem(ReteEvaluator 
reteEvaluator, ActivationsManager activationsManager, TerminalNode rtn, boolean 
linkPmem ) {
diff --git 
a/drools-core/src/main/java/org/drools/core/reteoo/ModifyPreviousTuples.java 
b/drools-core/src/main/java/org/drools/core/reteoo/ModifyPreviousTuples.java
index b2760f0f53..efc271ad68 100644
--- a/drools-core/src/main/java/org/drools/core/reteoo/ModifyPreviousTuples.java
+++ b/drools-core/src/main/java/org/drools/core/reteoo/ModifyPreviousTuples.java
@@ -79,7 +79,7 @@ public class ModifyPreviousTuples {
             ActivationsManager activationsManager = 
reteEvaluator.getActivationsManager();
             TerminalNode rtn = (TerminalNode) leftTuple.getTupleSink();
             PathMemory pathMemory = reteEvaluator.getNodeMemory( rtn );
-            PhreakRuleTerminalNode.doLeftDelete(activationsManager, 
pathMemory.getRuleAgendaItem().getRuleExecutor(), leftTuple);
+            PhreakRuleTerminalNode.doLeftDelete(activationsManager, 
pathMemory.getRuleAgendaItem().getRuleExecutor(), (RuleTerminalNodeLeftTuple) 
leftTuple);
         }
     }
 
diff --git 
a/drools-core/src/main/java/org/drools/core/reteoo/RuleTerminalNode.java 
b/drools-core/src/main/java/org/drools/core/reteoo/RuleTerminalNode.java
index f4fbdb09a4..ee22d798a6 100644
--- a/drools-core/src/main/java/org/drools/core/reteoo/RuleTerminalNode.java
+++ b/drools-core/src/main/java/org/drools/core/reteoo/RuleTerminalNode.java
@@ -142,7 +142,7 @@ public class RuleTerminalNode extends AbstractTerminalNode {
                 }
             }
             RuleExecutor ruleExecutor = 
((RuleTerminalNodeLeftTuple)leftTuple).getRuleAgendaItem().getRuleExecutor();
-            
PhreakRuleTerminalNode.doLeftDelete(ruleExecutor.getPathMemory().getActualActivationsManager(
 reteEvaluator ), ruleExecutor, leftTuple);
+            
PhreakRuleTerminalNode.doLeftDelete(ruleExecutor.getPathMemory().getActualActivationsManager(
 reteEvaluator ), ruleExecutor, (RuleTerminalNodeLeftTuple) leftTuple);
         }
     }
 
diff --git 
a/drools-core/src/main/java/org/drools/core/reteoo/RuleTerminalNodeLeftTuple.java
 
b/drools-core/src/main/java/org/drools/core/reteoo/RuleTerminalNodeLeftTuple.java
index 4626a017d9..222e0a98a7 100644
--- 
a/drools-core/src/main/java/org/drools/core/reteoo/RuleTerminalNodeLeftTuple.java
+++ 
b/drools-core/src/main/java/org/drools/core/reteoo/RuleTerminalNodeLeftTuple.java
@@ -62,6 +62,9 @@ public class RuleTerminalNodeLeftTuple extends LeftTuple 
implements InternalMatc
     private RuleImpl rule;
     private Consequence consequence;
 
+    // left here for debugging purposes: switch 
RuleExecutor.DEBUG_DORMANT_TUPLE to true to enable this debugging
+    private boolean dormant;
+
     public RuleTerminalNodeLeftTuple() {
         // constructor needed for serialisation
     }
@@ -218,7 +221,7 @@ public class RuleTerminalNodeLeftTuple extends LeftTuple 
implements InternalMatc
     }
 
     public void dequeue() {
-        ruleAgendaItem.getRuleExecutor().removeLeftTuple(this);
+        ruleAgendaItem.getRuleExecutor().removeActiveTuple(this);
     }
 
     public void remove() {
@@ -335,4 +338,18 @@ public class RuleTerminalNodeLeftTuple extends LeftTuple 
implements InternalMatc
     public int hashCode() {
         return Objects.hash(super.hashCode(), 
ruleAgendaItem.getRule().getName());
     }
+
+    public boolean isFullMatch() {
+        return true;
+    }
+
+    public boolean isDormant() {
+        //throw new IllegalStateException("This method can be called only for 
debugging purposes. Uncomment dormant boolean to enable debugging.");
+        return dormant;
+    }
+
+    public void setDormant(boolean dormant) {
+        //throw new IllegalStateException("This method can be called only for 
debugging purposes. Uncomment dormant boolean to enable debugging.");
+        this.dormant = dormant;
+    }
 }
diff --git a/drools-core/src/main/java/org/drools/core/util/LinkedList.java 
b/drools-core/src/main/java/org/drools/core/util/LinkedList.java
index c78fb30ca8..3123640acc 100644
--- a/drools-core/src/main/java/org/drools/core/util/LinkedList.java
+++ b/drools-core/src/main/java/org/drools/core/util/LinkedList.java
@@ -22,6 +22,7 @@ import java.io.Externalizable;
 import java.io.IOException;
 import java.io.ObjectInput;
 import java.io.ObjectOutput;
+import java.util.Collection;
 import java.util.NoSuchElementException;
 
 /**
@@ -471,5 +472,4 @@ public class LinkedList<T extends LinkedListNode<T>>
             }
         }
     }
-
 }
diff --git 
a/drools-core/src/main/java/org/drools/core/util/index/TupleList.java 
b/drools-core/src/main/java/org/drools/core/util/index/TupleList.java
index d31445f4a4..3790379edb 100644
--- a/drools-core/src/main/java/org/drools/core/util/index/TupleList.java
+++ b/drools-core/src/main/java/org/drools/core/util/index/TupleList.java
@@ -16,6 +16,7 @@
 
 package org.drools.core.util.index;
 
+import java.util.Collection;
 import java.io.Serializable;
 
 import org.drools.core.common.InternalFactHandle;
@@ -27,18 +28,19 @@ import org.drools.core.util.FastIterator;
 import org.drools.core.util.Iterator;
 import org.drools.core.util.LinkedList;
 
+
 public class TupleList<C> implements TupleMemory, Entry<TupleList<C>>, 
Serializable {
 
     public static final long       serialVersionUID = 510l;
 
     private TupleList<C>           next;
 
-    private Tuple                  first;
-    private Tuple                  last;
+    protected Tuple                  first;
+    protected Tuple                  last;
 
     private TupleHashTableIterator iterator;
 
-    private int                    size;
+    protected int                    size;
 
     private C                      context;
 
@@ -279,4 +281,10 @@ public class TupleList<C> implements TupleMemory, 
Entry<TupleList<C>>, Serializa
             current.setMemory(other);
         }
     }
+
+    public <I> void addAllToCollection(Collection<I> c) {
+        for (Tuple item = getFirst(); item != null; item = item.getNext()) {
+            c.add((I) item);
+        }
+    }
 }
diff --git 
a/drools-kiesession/src/main/java/org/drools/kiesession/agenda/DefaultAgenda.java
 
b/drools-kiesession/src/main/java/org/drools/kiesession/agenda/DefaultAgenda.java
index 146d870740..e92968d094 100644
--- 
a/drools-kiesession/src/main/java/org/drools/kiesession/agenda/DefaultAgenda.java
+++ 
b/drools-kiesession/src/main/java/org/drools/kiesession/agenda/DefaultAgenda.java
@@ -282,7 +282,7 @@ public class DefaultAgenda implements InternalAgenda {
             // The lazy RuleAgendaItem must be fully evaluated, to see if 
there is a rule match
             RuleExecutor ruleExecutor = item.getRuleExecutor();
             ruleExecutor.evaluateNetwork(this);
-            TupleList list = ruleExecutor.getLeftTupleList();
+            TupleList list = ruleExecutor.getActiveMatches();
             for (RuleTerminalNodeLeftTuple lt = (RuleTerminalNodeLeftTuple) 
list.getFirst(); lt != null; lt = (RuleTerminalNodeLeftTuple) lt.getNext()) {
                 if ( ruleName.equals( lt.getRule().getName() ) && ( 
lt.checkProcessInstance( workingMemory, processInstanceId ) )) {
                     return true;
diff --git 
a/drools-serialization-protobuf/src/main/java/org/drools/serialization/protobuf/iterators/PhreakActivationIterator.java
 
b/drools-serialization-protobuf/src/main/java/org/drools/serialization/protobuf/iterators/PhreakActivationIterator.java
index d4ea495dbe..fe77550a88 100644
--- 
a/drools-serialization-protobuf/src/main/java/org/drools/serialization/protobuf/iterators/PhreakActivationIterator.java
+++ 
b/drools-serialization-protobuf/src/main/java/org/drools/serialization/protobuf/iterators/PhreakActivationIterator.java
@@ -1,76 +1,48 @@
-/*
- * Copyright 2015 Red Hat, Inc. and/or its affiliates.
+/**
+ * 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
  *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * 
- *      http://www.apache.org/licenses/LICENSE-2.0
+ *   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.
-*/
-
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
 package org.drools.serialization.protobuf.iterators;
 
 import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.HashSet;
 import java.util.List;
-import java.util.Set;
 
 import org.drools.base.reteoo.NodeTypeEnums;
-import org.drools.core.common.InternalFactHandle;
-import org.drools.core.common.InternalWorkingMemory;
-import org.drools.core.common.Memory;
 import org.drools.core.common.ReteEvaluator;
 import org.drools.core.impl.InternalRuleBase;
-import org.drools.core.reteoo.AccumulateNode.AccumulateContext;
-import org.drools.core.reteoo.AccumulateNode.AccumulateMemory;
-import org.drools.core.reteoo.BetaMemory;
-import org.drools.core.reteoo.BetaNode;
-import org.drools.core.reteoo.FromNode.FromMemory;
-import org.drools.core.reteoo.LeftInputAdapterNode;
-import org.drools.core.reteoo.LeftTuple;
-import org.drools.core.reteoo.LeftTupleSink;
-import org.drools.core.reteoo.LeftTupleSource;
-import org.drools.core.reteoo.ObjectSource;
-import org.drools.core.reteoo.ObjectTypeNode;
-import org.drools.core.reteoo.RightTuple;
-import org.drools.core.reteoo.RuleTerminalNode;
+import org.drools.core.phreak.RuleExecutor;
+import org.drools.core.reteoo.PathMemory;
 import org.drools.core.reteoo.TerminalNode;
-import org.drools.core.reteoo.Tuple;
-import org.drools.core.reteoo.TupleMemory;
 import org.drools.core.rule.consequence.InternalMatch;
-import org.drools.core.util.FastIterator;
 import org.drools.core.util.Iterator;
 
-public class PhreakActivationIterator
-    implements
-    Iterator {
-
-    private java.util.Iterator<InternalMatch> agendaItemIter;
-
-    List<InternalMatch> internalMatches;
+public class PhreakActivationIterator implements Iterator<InternalMatch> {
 
-    PhreakActivationIterator() {
+    private final java.util.Iterator<InternalMatch> agendaItemIter;
 
-    }
-
-    private PhreakActivationIterator(ReteEvaluator reteEvaluator,
-                                     InternalRuleBase kbase) {
-        internalMatches = collectAgendaItems(kbase, reteEvaluator);
-        agendaItemIter =  internalMatches.iterator();
+    private PhreakActivationIterator(ReteEvaluator reteEvaluator, 
InternalRuleBase kbase) {
+        agendaItemIter =  collectAgendaItems(kbase, reteEvaluator).iterator();
     }
 
     public static PhreakActivationIterator iterator(ReteEvaluator 
reteEvaluator) {
         return new PhreakActivationIterator( reteEvaluator, 
reteEvaluator.getKnowledgeBase() );
     }
 
-    public Object next() {
+    public InternalMatch next() {
         if ( agendaItemIter.hasNext() ) {
             return agendaItemIter.next();
         } else {
@@ -78,158 +50,22 @@ public class PhreakActivationIterator
         }
     }
 
-    public static List<RuleTerminalNode> 
populateRuleTerminalNodes(InternalRuleBase kbase, Set<RuleTerminalNode>  
nodeSet) {
-        Collection<TerminalNode[]> nodesWithArray = 
kbase.getReteooBuilder().getTerminalNodes().values();
+    private static List<InternalMatch> collectAgendaItems(InternalRuleBase 
kbase, ReteEvaluator reteEvaluator) {
+        List<InternalMatch> internalMatches = new ArrayList<>();
 
-        for (TerminalNode[] nodeArray : nodesWithArray) {
+        for (TerminalNode[] nodeArray : 
kbase.getReteooBuilder().getTerminalNodes().values()) {
             for (TerminalNode node : nodeArray) {
                 if (node.getType() == NodeTypeEnums.RuleTerminalNode) {
-                    nodeSet.add((RuleTerminalNode) node);
-                }
-            }
-        }
-
-        return Arrays.asList(nodeSet.toArray(new 
RuleTerminalNode[nodeSet.size()]));
-    }
-
-    public static List<InternalMatch> collectAgendaItems(InternalRuleBase 
kbase, ReteEvaluator reteEvaluator) {
-        Set<RuleTerminalNode> nodeSet = new HashSet<>();
-        List<RuleTerminalNode> nodeList = populateRuleTerminalNodes(kbase, 
nodeSet);
-
-        List<InternalMatch> internalMatches = new ArrayList<>();
-        for ( RuleTerminalNode rtn : nodeList ) {
-            if ( !nodeSet.contains(rtn) ) {
-                // this node has already been processed
-                continue;
-            }
-            processLeftTuples(rtn.getLeftTupleSource(), internalMatches, 
nodeSet, reteEvaluator);
-        }
-        return internalMatches;
-    }
-
-    public static void processLeftTuples(LeftTupleSource node, 
List<InternalMatch> internalMatches, Set<RuleTerminalNode> nodeSet, 
ReteEvaluator reteEvaluator) {
-        LeftTupleSource node1 = node;
-        while (NodeTypeEnums.LeftInputAdapterNode != node1.getType()) {
-            node1 = node1.getLeftTupleSource();
-        }
-        int maxShareCount = node1.getAssociationsSize();
-
-        while (NodeTypeEnums.LeftInputAdapterNode != node.getType()) {
-            Memory memory = 
reteEvaluator.getNodeMemories().peekNodeMemory(node);
-            if (memory == null || memory.getSegmentMemory() == null) {
-                // segment has never been initialized, which means the rule 
has never been linked.
-                return;
-            }
-            if ( node.getAssociationsSize() == maxShareCount ) {
-                // the recurse must start from the first split node, otherwise 
we get partial overlaps in propagations
-                if (NodeTypeEnums.isBetaNode(node)) {
-                    BetaMemory bm;
-                    if (NodeTypeEnums.AccumulateNode == node.getType()) {
-                        AccumulateMemory am = (AccumulateMemory) memory;
-                        bm = am.getBetaMemory();
-                        FastIterator it = 
bm.getLeftTupleMemory().fullFastIterator();
-                        Tuple lt = BetaNode.getFirstTuple( 
bm.getLeftTupleMemory(), it );
-                        for (; lt != null; lt = (LeftTuple) it.next(lt)) {
-                            AccumulateContext accctx = (AccumulateContext) 
lt.getContextObject();
-                            collectFromPeers((LeftTuple) 
accctx.getResultLeftTuple(), internalMatches, nodeSet, reteEvaluator);
-                        }
-                    } else if ( NodeTypeEnums.ExistsNode == node.getType() ) {
-                        bm = (BetaMemory) 
reteEvaluator.getNodeMemories().peekNodeMemory(node);
-                        if (bm != null) {
-                            bm = (BetaMemory) 
reteEvaluator.getNodeMemories().peekNodeMemory(node);
-                            FastIterator it = 
bm.getRightTupleMemory().fullFastIterator(); // done off the RightTupleMemory, 
as exists only have unblocked tuples on the left side
-                            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()) {
-                                    if (lt.getFirstChild() != null) {
-                                        collectFromPeers(lt.getFirstChild(), 
internalMatches, nodeSet, reteEvaluator);
-                                    }
-                                }
-                            }
-                        }
-                    } else {
-                        bm = (BetaMemory) 
reteEvaluator.getNodeMemories().peekNodeMemory(node);
-                        if (bm != null) {
-                            FastIterator it = 
bm.getLeftTupleMemory().fullFastIterator();
-                            Tuple lt = 
BetaNode.getFirstTuple(bm.getLeftTupleMemory(), it);
-                            for (; lt != null; lt = (LeftTuple) it.next(lt)) {
-                                if (lt.getFirstChild() != null) {
-                                    collectFromLeftInput(lt.getFirstChild(), 
internalMatches, nodeSet, reteEvaluator);
-                                }
-                            }
-                        }
-                    }
-                    return;
-                } else if (NodeTypeEnums.FromNode == node.getType()) {
-                    FromMemory fm = (FromMemory) 
reteEvaluator.getNodeMemories().peekNodeMemory(node);
-                    if (fm != null) {
-                        TupleMemory ltm = 
fm.getBetaMemory().getLeftTupleMemory();
-                        FastIterator it = ltm.fullFastIterator();
-                        for (LeftTuple lt = (LeftTuple) ltm.getFirst(null); lt 
!= null; lt = (LeftTuple) it.next(lt)) {
-                            if (lt.getFirstChild() != null) {
-                                collectFromLeftInput(lt.getFirstChild(), 
internalMatches, nodeSet, reteEvaluator);
-                            }
-                        }
+                    PathMemory pathMemory = (PathMemory) 
reteEvaluator.getNodeMemories().peekNodeMemory(node);
+                    if (pathMemory != null && pathMemory.getRuleAgendaItem() 
!= null) {
+                        RuleExecutor ruleExecutor = 
pathMemory.getRuleAgendaItem().getRuleExecutor();
+                        
ruleExecutor.getDormantMatches().addAllToCollection(internalMatches);
+                        
ruleExecutor.getActiveMatches().addAllToCollection(internalMatches);
                     }
-                    return;
                 }
             }
-            node = node.getLeftTupleSource();
-        }
-
-        // No beta or from nodes, so must retrieve LeftTuples from the LiaNode.
-        // This is done by scanning all the LeftTuples referenced from the 
FactHandles in the ObjectTypeNode
-        LeftInputAdapterNode lian = (LeftInputAdapterNode) node;
-        if ( !lian.isTerminal() ) {
-            Memory memory = 
reteEvaluator.getNodeMemories().peekNodeMemory(node);
-            if (memory == null || memory.getSegmentMemory() == null) {
-                // segment has never been initialized, which means the rule 
has never been linked.
-                return;
-            }
-        }
-
-        ObjectSource os = lian.getObjectSource();
-        while (os.getType() != NodeTypeEnums.ObjectTypeNode) {
-            os = os.getParentObjectSource();
-        }
-        ObjectTypeNode otn = (ObjectTypeNode) os;
-        LeftTupleSink firstLiaSink = 
lian.getSinkPropagator().getFirstLeftTupleSink();
-
-        java.util.Iterator<InternalFactHandle> it = 
otn.getFactHandlesIterator((InternalWorkingMemory) reteEvaluator);
-        while (it.hasNext()) {
-            InternalFactHandle fh = it.next();
-            fh.forEachLeftTuple( lt -> {
-                if ( lt.getTupleSink() == firstLiaSink ) {
-                    collectFromLeftInput(lt, internalMatches, nodeSet, 
reteEvaluator);
-                }
-            });
         }
-    }
 
-    private static void collectFromLeftInput(LeftTuple lt, List<InternalMatch> 
internalMatches, Set<RuleTerminalNode> nodeSet, ReteEvaluator reteEvaluator) {
-        for (; lt != null; lt = lt.getHandleNext()) {
-            collectFromPeers(lt, internalMatches, nodeSet, reteEvaluator);
-        }
-    }
-
-    private static void collectFromPeers(LeftTuple peer, List<InternalMatch> 
internalMatches, Set<RuleTerminalNode> nodeSet, ReteEvaluator reteEvaluator) {
-        while (peer != null) {
-            if ( peer.getTupleSink().getType() == NodeTypeEnums.AccumulateNode 
) {
-                Object accctx = peer.getContextObject();
-                if (accctx instanceof AccumulateContext) {
-                    // lefttuple representing an accumulated value now have 
that value as context object (it was null before) and must be skipped here
-                    collectFromLeftInput((LeftTuple) ((AccumulateContext) 
accctx).getResultLeftTuple(), internalMatches, nodeSet, reteEvaluator);
-                }
-            } else if ( peer.getFirstChild() != null ) {
-                for (LeftTuple childLt = peer.getFirstChild(); childLt != 
null; childLt = childLt.getHandleNext()) {
-                    collectFromPeers(childLt, internalMatches, nodeSet, 
reteEvaluator);
-                }
-            } else if ( peer.getTupleSink().getType() == 
NodeTypeEnums.RuleTerminalNode ) {
-                internalMatches.add((InternalMatch) peer);
-                nodeSet.remove(peer.getTupleSink()); // remove this 
RuleTerminalNode, as we know we've visited it already
-            }
-            peer = peer.getPeer();
-        }
+        return internalMatches;
     }
-
-}
+}
\ No newline at end of file
diff --git 
a/drools-test-coverage/test-compiler-integration/src/test/java/org/drools/mvel/integrationtests/ExecutionFlowControlTest.java
 
b/drools-test-coverage/test-compiler-integration/src/test/java/org/drools/mvel/integrationtests/ExecutionFlowControlTest.java
index 2422c93680..81351d090a 100644
--- 
a/drools-test-coverage/test-compiler-integration/src/test/java/org/drools/mvel/integrationtests/ExecutionFlowControlTest.java
+++ 
b/drools-test-coverage/test-compiler-integration/src/test/java/org/drools/mvel/integrationtests/ExecutionFlowControlTest.java
@@ -472,31 +472,31 @@ public class ExecutionFlowControlTest {
         assertThat(group1.size()).isEqualTo(1);
         RuleAgendaItem ruleItem1 = group1.getActivations().iterator().next();
         ruleItem1.getRuleExecutor().evaluateNetwork(wm.getAgenda());
-        
assertThat(ruleItem1.getRuleExecutor().getLeftTupleList().size()).isEqualTo(3);
+        
assertThat(ruleItem1.getRuleExecutor().getActiveMatches().size()).isEqualTo(3);
 
         ruleItem1.getRuleExecutor().fire(agenda);
         assertThat(group1.size()).isEqualTo(1);
-        
assertThat(ruleItem1.getRuleExecutor().getLeftTupleList().size()).isEqualTo(2);
+        
assertThat(ruleItem1.getRuleExecutor().getActiveMatches().size()).isEqualTo(2);
 
         ksession.update( brieHandle, brie );
         assertThat(group1.size()).isEqualTo(1);
         ruleItem1.getRuleExecutor().evaluateNetwork(wm.getAgenda());
-        
assertThat(ruleItem1.getRuleExecutor().getLeftTupleList().size()).isEqualTo(2);
+        
assertThat(ruleItem1.getRuleExecutor().getActiveMatches().size()).isEqualTo(2);
 
         InternalAgendaGroup group2 = 
agenda.getAgendaGroupsManager().getAgendaGroup( "group2" );
         agenda.getAgendaGroupsManager().setFocus( group2);
         assertThat(group2.size()).isEqualTo(1);
         RuleAgendaItem ruleItem2 = group2.getActivations().iterator().next();
         ruleItem2.getRuleExecutor().evaluateNetwork(wm.getAgenda());
-        
assertThat(ruleItem2.getRuleExecutor().getLeftTupleList().size()).isEqualTo(3);
+        
assertThat(ruleItem2.getRuleExecutor().getActiveMatches().size()).isEqualTo(3);
 
         ruleItem2.getRuleExecutor().fire(agenda);
         assertThat(group2.size()).isEqualTo(1);
-        
assertThat(ruleItem2.getRuleExecutor().getLeftTupleList().size()).isEqualTo(2);
+        
assertThat(ruleItem2.getRuleExecutor().getActiveMatches().size()).isEqualTo(2);
 
         ksession.update( brieHandle, brie );
         assertThat(group2.size()).isEqualTo(1);
-        
assertThat(ruleItem2.getRuleExecutor().getLeftTupleList().size()).isEqualTo(2);
+        
assertThat(ruleItem2.getRuleExecutor().getActiveMatches().size()).isEqualTo(2);
     }
 
     @Test
diff --git 
a/drools-tms/src/main/java/org/drools/tms/agenda/TruthMaintenanceSystemRuleTerminalNodeLeftTuple.java
 
b/drools-tms/src/main/java/org/drools/tms/agenda/TruthMaintenanceSystemRuleTerminalNodeLeftTuple.java
index 7dda3486c2..48ef10ed39 100644
--- 
a/drools-tms/src/main/java/org/drools/tms/agenda/TruthMaintenanceSystemRuleTerminalNodeLeftTuple.java
+++ 
b/drools-tms/src/main/java/org/drools/tms/agenda/TruthMaintenanceSystemRuleTerminalNodeLeftTuple.java
@@ -105,7 +105,7 @@ public class 
TruthMaintenanceSystemRuleTerminalNodeLeftTuple<T extends ModedAsse
                 removeBlocked(dep);
                 TruthMaintenanceSystemRuleTerminalNodeLeftTuple justified = 
(TruthMaintenanceSystemRuleTerminalNodeLeftTuple) dep.getJustified();
                 if (justified.getBlockers().isEmpty() && justified.isActive()) 
{
-                    activationsManager.stageLeftTuple(ruleAgendaItem, 
justified);
+                    
activationsManager.stageLeftTuple(justified.getRuleAgendaItem(), justified);
                 }
                 dep = tmp;
             }


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to