Пример #1
0
  public static void doUpdatesExistentialReorderLeftMemory(
      BetaMemory bm, TupleSets<LeftTuple> srcLeftTuples) {
    TupleMemory ltm = bm.getLeftTupleMemory();

    // sides must first be re-ordered, to ensure iteration integrity
    for (LeftTuple leftTuple = srcLeftTuples.getUpdateFirst(); leftTuple != null; ) {
      LeftTuple next = leftTuple.getStagedNext();
      if (leftTuple.getMemory() != null) {
        ltm.remove(leftTuple);
      }
      leftTuple = next;
    }

    for (LeftTuple leftTuple = srcLeftTuples.getUpdateFirst(); leftTuple != null; ) {
      LeftTuple next = leftTuple.getStagedNext();
      RightTuple blocker = leftTuple.getBlocker();
      if (blocker == null) {
        ltm.add(leftTuple);
        for (LeftTuple childLeftTuple = leftTuple.getFirstChild(); childLeftTuple != null; ) {
          LeftTuple childNext = childLeftTuple.getHandleNext();
          childLeftTuple.reAddRight();
          childLeftTuple = childNext;
        }
      } else if (blocker.getStagedType() != LeftTuple.NONE) {
        // it's blocker is also being updated, so remove to force it to start from the beginning
        blocker.removeBlocked(leftTuple);
      }
      leftTuple = next;
    }
  }
Пример #2
0
  public void doLeftDeletes(
      BetaMemory bm,
      LeftTupleSets srcLeftTuples,
      LeftTupleSets trgLeftTuples,
      LeftTupleSets stagedLeftTuples) {
    LeftTupleMemory ltm = bm.getLeftTupleMemory();

    for (LeftTuple leftTuple = srcLeftTuples.getDeleteFirst(); leftTuple != null; ) {
      LeftTuple next = leftTuple.getStagedNext();
      RightTuple blocker = leftTuple.getBlocker();
      if (blocker == null) {
        if (leftTuple.getMemory() != null) {
          // it may have been staged and never actually added
          ltm.remove(leftTuple);
        }

        LeftTuple childLeftTuple = leftTuple.getFirstChild();

        if (childLeftTuple != null) { // NotNode only has one child
          childLeftTuple.setPropagationContext(leftTuple.getPropagationContext());
          RuleNetworkEvaluator.deleteLeftChild(
              childLeftTuple,
              trgLeftTuples,
              stagedLeftTuples); // no need to update pctx, as no right available, and pctx will
                                 // exist on a parent LeftTuple anyway
        }
      } else {
        blocker.removeBlocked(leftTuple);
      }
      leftTuple.clearStaged();
      leftTuple = next;
    }
  }
Пример #3
0
  public static void dpUpdatesExistentialReorderLeftMemory(
      BetaMemory bm, LeftTupleSets srcLeftTuples) {
    LeftTupleMemory ltm = bm.getLeftTupleMemory();

    // sides must first be re-ordered, to ensure iteration integrity
    for (LeftTuple leftTuple = srcLeftTuples.getUpdateFirst(); leftTuple != null; ) {
      LeftTuple next = leftTuple.getStagedNext();
      if (leftTuple.getMemory() != null) {
        ltm.remove(leftTuple);
      }
      leftTuple = next;
    }

    for (LeftTuple leftTuple = srcLeftTuples.getUpdateFirst(); leftTuple != null; ) {
      LeftTuple next = leftTuple.getStagedNext();
      if (leftTuple.getBlocker() == null) {
        ltm.add(leftTuple);
        for (LeftTuple childLeftTuple = leftTuple.getFirstChild(); childLeftTuple != null; ) {
          LeftTuple childNext = childLeftTuple.getLeftParentNext();
          childLeftTuple.reAddRight();
          childLeftTuple = childNext;
        }
      }
      leftTuple = next;
    }
  }
Пример #4
0
  public void doLeftInserts(
      NotNode notNode,
      LeftTupleSink sink,
      BetaMemory bm,
      InternalWorkingMemory wm,
      LeftTupleSets srcLeftTuples,
      LeftTupleSets trgLeftTuples) {
    LeftTupleMemory ltm = bm.getLeftTupleMemory();
    RightTupleMemory rtm = bm.getRightTupleMemory();
    ContextEntry[] contextEntry = bm.getContext();
    BetaConstraints constraints = notNode.getRawConstraints();

    for (LeftTuple leftTuple = srcLeftTuples.getInsertFirst(); leftTuple != null; ) {
      LeftTuple next = leftTuple.getStagedNext();

      FastIterator it = notNode.getRightIterator(rtm);

      boolean useLeftMemory = RuleNetworkEvaluator.useLeftMemory(notNode, leftTuple);

      constraints.updateFromTuple(contextEntry, wm, leftTuple);

      // This method will also remove rightTuples that are from subnetwork where no leftmemory use
      // used
      RuleNetworkEvaluator.findLeftTupleBlocker(
          notNode, rtm, contextEntry, constraints, leftTuple, it, useLeftMemory);

      if (leftTuple.getBlocker() == null) {
        // tuple is not blocked, so add to memory so other fact handles can attempt to match
        if (useLeftMemory) {
          ltm.add(leftTuple);
        }

        trgLeftTuples.addInsert(
            sink.createLeftTuple(
                leftTuple,
                sink,
                leftTuple.getPropagationContext(),
                useLeftMemory)); // use leftTuple pctx here, as no right input caused the trigger
                                 // anway
      }
      leftTuple.clearStaged();
      leftTuple = next;
    }
    constraints.resetTuple(contextEntry);
  }
Пример #5
0
  public static void doUpdatesReorderLeftMemory(BetaMemory bm, TupleSets<LeftTuple> srcLeftTuples) {
    TupleMemory ltm = bm.getLeftTupleMemory();

    // sides must first be re-ordered, to ensure iteration integrity
    for (LeftTuple leftTuple = srcLeftTuples.getUpdateFirst(); leftTuple != null; ) {
      LeftTuple next = leftTuple.getStagedNext();
      ltm.remove(leftTuple);
      leftTuple = next;
    }

    for (LeftTuple leftTuple = srcLeftTuples.getUpdateFirst(); leftTuple != null; ) {
      LeftTuple next = leftTuple.getStagedNext();
      ltm.add(leftTuple);
      for (LeftTuple childLeftTuple = leftTuple.getFirstChild(); childLeftTuple != null; ) {
        LeftTuple childNext = childLeftTuple.getHandleNext();
        childLeftTuple.reAddRight();
        childLeftTuple = childNext;
      }
      leftTuple = next;
    }
  }
Пример #6
0
  public void doLeftDeletes(
      FromMemory fm,
      TupleSets<LeftTuple> srcLeftTuples,
      TupleSets<LeftTuple> trgLeftTuples,
      TupleSets<LeftTuple> stagedLeftTuples) {
    BetaMemory bm = fm.getBetaMemory();
    TupleMemory ltm = bm.getLeftTupleMemory();

    for (LeftTuple leftTuple = srcLeftTuples.getDeleteFirst(); leftTuple != null; ) {
      LeftTuple next = leftTuple.getStagedNext();

      ltm.remove(leftTuple);

      Map<Object, RightTuple> matches = (Map<Object, RightTuple>) leftTuple.getContextObject();

      if (leftTuple.getFirstChild() != null) {
        LeftTuple childLeftTuple = leftTuple.getFirstChild();

        while (childLeftTuple != null) {
          childLeftTuple.setPropagationContext(leftTuple.getPropagationContext());
          LeftTuple nextChild = childLeftTuple.getLeftParentNext();
          RuleNetworkEvaluator.unlinkAndDeleteChildLeftTuple(
              childLeftTuple, trgLeftTuples, stagedLeftTuples);
          childLeftTuple = nextChild;
        }
      }

      // if matches == null, the deletion might be happening before the fact was even propagated.
      // See BZ-1019473 for details.
      if (matches != null) {

        // @TODO (mdp) is this really necessary? won't the entire FH and RightTuple chaines just et
        // GC'd?
        unlinkCreatedHandles(leftTuple);
      }

      leftTuple.clearStaged();
      leftTuple = next;
    }
  }
Пример #7
0
  @Test
  public void testPopulatedRuleWithEvals() throws Exception {
    KnowledgeBase kbase1 = buildKnowledgeBase("r1", "   a:A() B() eval(1==1) eval(1==1) C(1;) \n");
    InternalWorkingMemory wm = ((InternalWorkingMemory) kbase1.newStatefulKnowledgeSession());
    List list = new ArrayList();
    wm.setGlobal("list", list);

    wm.insert(new A(1));
    wm.insert(new A(2));
    wm.insert(new A(3));
    wm.insert(new B(1));
    wm.insert(new C(1));
    wm.insert(new C(2));

    wm.fireAllRules();
    assertEquals(3, list.size());

    kbase1.addKnowledgePackages(
        buildKnowledgePackage("r2", "   a:A() B() eval(1==1) eval(1==1) C(2;) \n"));

    ObjectTypeNode aotn = getObjectTypeNode(kbase1, A.class);
    LeftInputAdapterNode liaNode = (LeftInputAdapterNode) aotn.getSinkPropagator().getSinks()[0];
    JoinNode bNode = (JoinNode) liaNode.getSinkPropagator().getFirstLeftTupleSink();

    EvalConditionNode e1 = (EvalConditionNode) bNode.getSinkPropagator().getFirstLeftTupleSink();
    EvalConditionNode e2 = (EvalConditionNode) e1.getSinkPropagator().getFirstLeftTupleSink();

    JoinNode c1Node = (JoinNode) e2.getSinkPropagator().getFirstLeftTupleSink();
    JoinNode c2Node = (JoinNode) e2.getSinkPropagator().getLastLeftTupleSink();

    LiaNodeMemory lm = (LiaNodeMemory) wm.getNodeMemory(liaNode);
    SegmentMemory sm = lm.getSegmentMemory();

    BetaMemory c1Mem = (BetaMemory) wm.getNodeMemory(c1Node);
    assertSame(sm.getFirst(), c1Mem.getSegmentMemory());
    assertEquals(3, c1Mem.getLeftTupleMemory().size());
    assertEquals(1, c1Mem.getRightTupleMemory().size());

    BetaMemory c2Mem = (BetaMemory) wm.getNodeMemory(c2Node);
    SegmentMemory c2Smem = sm.getFirst().getNext();
    assertSame(c2Smem, c2Mem.getSegmentMemory());
    assertEquals(0, c2Mem.getLeftTupleMemory().size());
    assertEquals(0, c2Mem.getRightTupleMemory().size());
    assertNotNull(c2Smem.getStagedLeftTuples().getInsertFirst());
    assertNotNull(c2Smem.getStagedLeftTuples().getInsertFirst().getStagedNext());
    assertNotNull(c2Smem.getStagedLeftTuples().getInsertFirst().getStagedNext().getStagedNext());
    assertNull(
        c2Smem
            .getStagedLeftTuples()
            .getInsertFirst()
            .getStagedNext()
            .getStagedNext()
            .getStagedNext());

    wm.fireAllRules();
    assertEquals(3, c2Mem.getLeftTupleMemory().size());
    assertEquals(1, c2Mem.getRightTupleMemory().size());
    assertNull(c2Smem.getStagedLeftTuples().getInsertFirst());
    assertEquals(6, list.size());

    assertEquals("r1", ((Match) list.get(0)).getRule().getName());
    assertEquals("r1", ((Match) list.get(1)).getRule().getName());
    assertEquals("r1", ((Match) list.get(2)).getRule().getName());
    assertEquals("r2", ((Match) list.get(3)).getRule().getName());
    assertEquals(3, ((A) ((Match) list.get(3)).getDeclarationValue("a")).getObject());
    assertEquals("r2", ((Match) list.get(4)).getRule().getName());
    assertEquals(2, ((A) ((Match) list.get(4)).getDeclarationValue("a")).getObject());
    assertEquals("r2", ((Match) list.get(5)).getRule().getName());
    assertEquals(1, ((A) ((Match) list.get(5)).getDeclarationValue("a")).getObject());
  }
Пример #8
0
  public void doRightDeletes(
      NotNode notNode,
      LeftTupleSink sink,
      BetaMemory bm,
      InternalWorkingMemory wm,
      RightTupleSets srcRightTuples,
      LeftTupleSets trgLeftTuples) {
    LeftTupleMemory ltm = bm.getLeftTupleMemory();
    RightTupleMemory rtm = bm.getRightTupleMemory();
    ContextEntry[] contextEntry = bm.getContext();
    BetaConstraints constraints = notNode.getRawConstraints();

    for (RightTuple rightTuple = srcRightTuples.getDeleteFirst(); rightTuple != null; ) {
      RightTuple next = rightTuple.getStagedNext();

      FastIterator it = notNode.getRightIterator(rtm);

      // assign now, so we can remove from memory before doing any possible propagations
      boolean useComparisonIndex = rtm.getIndexType().isComparison();
      RightTuple rootBlocker = useComparisonIndex ? null : (RightTuple) it.next(rightTuple);

      if (rightTuple.getMemory() != null) {
        // it may have been staged and never actually added
        rtm.remove(rightTuple);
      }

      if (rightTuple.getBlocked() != null) {
        for (LeftTuple leftTuple = rightTuple.getBlocked(); leftTuple != null; ) {
          LeftTuple temp = leftTuple.getBlockedNext();

          leftTuple.clearBlocker();

          if (leftTuple.getStagedType() == LeftTuple.UPDATE) {
            // ignore, as it will get processed via left iteration. Children cannot be processed
            // twice
            leftTuple = temp;
            continue;
          }

          constraints.updateFromTuple(contextEntry, wm, leftTuple);

          if (useComparisonIndex) {
            rootBlocker = rtm.getFirst(leftTuple, null, it);
          }

          // we know that older tuples have been checked so continue next
          for (RightTuple newBlocker = rootBlocker;
              newBlocker != null;
              newBlocker = (RightTuple) it.next(newBlocker)) {
            if (constraints.isAllowedCachedLeft(contextEntry, newBlocker.getFactHandle())) {
              leftTuple.setBlocker(newBlocker);
              newBlocker.addBlocked(leftTuple);

              break;
            }
          }

          if (leftTuple.getBlocker() == null) {
            // was previous blocked and not in memory, so add
            ltm.add(leftTuple);

            trgLeftTuples.addInsert(
                sink.createLeftTuple(leftTuple, sink, rightTuple.getPropagationContext(), true));
          }

          leftTuple = temp;
        }
      }

      rightTuple.nullBlocked();
      rightTuple.clearStaged();
      rightTuple = next;
    }

    constraints.resetTuple(contextEntry);
  }
Пример #9
0
  public void doRightUpdates(
      NotNode notNode,
      LeftTupleSink sink,
      BetaMemory bm,
      InternalWorkingMemory wm,
      RightTupleSets srcRightTuples,
      LeftTupleSets trgLeftTuples,
      LeftTupleSets stagedLeftTuples) {
    LeftTupleMemory ltm = bm.getLeftTupleMemory();
    RightTupleMemory rtm = bm.getRightTupleMemory();
    ContextEntry[] contextEntry = bm.getContext();
    BetaConstraints constraints = notNode.getRawConstraints();

    boolean iterateFromStart =
        notNode.isIndexedUnificationJoin() || rtm.getIndexType().isComparison();

    for (RightTuple rightTuple = srcRightTuples.getUpdateFirst(); rightTuple != null; ) {
      RightTuple next = rightTuple.getStagedNext();
      PropagationContext context = rightTuple.getPropagationContext();

      constraints.updateFromFactHandle(contextEntry, wm, rightTuple.getFactHandle());

      FastIterator leftIt = notNode.getLeftIterator(ltm);
      LeftTuple firstLeftTuple = notNode.getFirstLeftTuple(rightTuple, ltm, context, leftIt);

      LeftTuple firstBlocked = rightTuple.getTempBlocked();

      // first process non-blocked tuples, as we know only those ones are in the left memory.
      for (LeftTuple leftTuple = firstLeftTuple; leftTuple != null; ) {
        // preserve next now, in case we remove this leftTuple
        LeftTuple temp = (LeftTuple) leftIt.next(leftTuple);

        if (leftTuple.getStagedType() == LeftTuple.UPDATE) {
          // ignore, as it will get processed via left iteration. Children cannot be processed twice
          leftTuple = temp;
          continue;
        }

        // we know that only unblocked LeftTuples are  still in the memory
        if (constraints.isAllowedCachedRight(contextEntry, leftTuple)) {
          leftTuple.setBlocker(rightTuple);
          rightTuple.addBlocked(leftTuple);

          // this is now blocked so remove from memory
          ltm.remove(leftTuple);

          LeftTuple childLeftTuple = leftTuple.getFirstChild();
          if (childLeftTuple != null) {
            childLeftTuple.setPropagationContext(rightTuple.getPropagationContext());
            RuleNetworkEvaluator.deleteRightChild(childLeftTuple, trgLeftTuples, stagedLeftTuples);
          }
        }

        leftTuple = temp;
      }

      if (firstBlocked != null) {
        RightTuple rootBlocker = rightTuple.getTempNextRightTuple();
        if (rootBlocker == null) {
          iterateFromStart = true;
        }

        FastIterator rightIt = notNode.getRightIterator(rtm);

        // iterate all the existing previous blocked LeftTuples
        for (LeftTuple leftTuple = firstBlocked; leftTuple != null; ) {
          LeftTuple temp = leftTuple.getBlockedNext();

          leftTuple.clearBlocker();

          if (leftTuple.getStagedType() == LeftTuple.UPDATE) {
            // ignore, as it will get processed via left iteration. Children cannot be processed
            // twice
            // but need to add it back into list first
            leftTuple.setBlocker(rightTuple);
            rightTuple.addBlocked(leftTuple);

            leftTuple = temp;
            continue;
          }

          constraints.updateFromTuple(contextEntry, wm, leftTuple);

          if (iterateFromStart) {
            rootBlocker = notNode.getFirstRightTuple(leftTuple, rtm, null, rightIt);
          }

          // we know that older tuples have been checked so continue next
          for (RightTuple newBlocker = rootBlocker;
              newBlocker != null;
              newBlocker = (RightTuple) rightIt.next(newBlocker)) {
            // cannot select a RightTuple queued in the delete list
            // There may be UPDATE RightTuples too, but that's ok. They've already been re-added to
            // the correct bucket, safe to be reprocessed.
            if (leftTuple.getStagedType() != LeftTuple.DELETE
                && newBlocker.getStagedType() != LeftTuple.DELETE
                && constraints.isAllowedCachedLeft(contextEntry, newBlocker.getFactHandle())) {

              leftTuple.setBlocker(newBlocker);
              newBlocker.addBlocked(leftTuple);

              break;
            }
          }

          if (leftTuple.getBlocker() == null) {
            // was previous blocked and not in memory, so add
            ltm.add(leftTuple);

            // subclasses like ForallNotNode might override this propagation
            trgLeftTuples.addInsert(
                sink.createLeftTuple(leftTuple, sink, rightTuple.getPropagationContext(), true));
          }

          leftTuple = temp;
        }
      }
      rightTuple.clearStaged();
      rightTuple = next;
    }

    constraints.resetFactHandle(contextEntry);
    constraints.resetTuple(contextEntry);
  }
Пример #10
0
  public void doLeftUpdates(
      NotNode notNode,
      LeftTupleSink sink,
      BetaMemory bm,
      InternalWorkingMemory wm,
      LeftTupleSets srcLeftTuples,
      LeftTupleSets trgLeftTuples,
      LeftTupleSets stagedLeftTuples) {
    LeftTupleMemory ltm = bm.getLeftTupleMemory();
    RightTupleMemory rtm = bm.getRightTupleMemory();
    ContextEntry[] contextEntry = bm.getContext();
    BetaConstraints constraints = notNode.getRawConstraints();
    boolean leftUpdateOptimizationAllowed = notNode.isLeftUpdateOptimizationAllowed();

    for (LeftTuple leftTuple = srcLeftTuples.getUpdateFirst(); leftTuple != null; ) {
      LeftTuple next = leftTuple.getStagedNext();

      FastIterator rightIt = notNode.getRightIterator(rtm);
      RightTuple firstRightTuple = notNode.getFirstRightTuple(leftTuple, rtm, null, rightIt);

      // If in memory, remove it, because we'll need to add it anyway if it's not blocked, to ensure
      // iteration order
      RightTuple blocker = leftTuple.getBlocker();
      if (blocker == null) {
        if (leftTuple.getMemory()
            != null) { // memory can be null, if blocker was deleted in same do loop
          ltm.remove(leftTuple);
        }
      } else {
        // check if we changed bucket
        if (rtm.isIndexed() && !rightIt.isFullIterator()) {
          // if newRightTuple is null, we assume there was a bucket change and that bucket is empty
          if (firstRightTuple == null || firstRightTuple.getMemory() != blocker.getMemory()) {
            blocker.removeBlocked(leftTuple);
            blocker = null;
          }
        }
      }

      constraints.updateFromTuple(contextEntry, wm, leftTuple);

      if (!leftUpdateOptimizationAllowed && blocker != null) {
        blocker.removeBlocked(leftTuple);
        blocker = null;
      }

      // if we where not blocked before (or changed buckets), or the previous blocker no longer
      // blocks, then find the next blocker
      if (blocker == null
          || !constraints.isAllowedCachedLeft(contextEntry, blocker.getFactHandle())) {
        if (blocker != null) {
          // remove previous blocker if it exists, as we know it doesn't block any more
          blocker.removeBlocked(leftTuple);
        }

        // find first blocker, because it's a modify, we need to start from the beginning again
        for (RightTuple newBlocker = firstRightTuple;
            newBlocker != null;
            newBlocker = (RightTuple) rightIt.next(newBlocker)) {
          if (constraints.isAllowedCachedLeft(contextEntry, newBlocker.getFactHandle())) {
            leftTuple.setBlocker(newBlocker);
            newBlocker.addBlocked(leftTuple);

            break;
          }
        }

        LeftTuple childLeftTuple = leftTuple.getFirstChild();

        if (leftTuple.getBlocker() != null) {
          // blocked
          if (childLeftTuple != null) {
            // blocked, with previous children, so must have not been previously blocked, so retract
            // no need to remove, as we removed at the start
            // to be matched against, as it's now blocked
            childLeftTuple.setPropagationContext(
                leftTuple
                    .getBlocker()
                    .getPropagationContext()); // we have the righttuple, so use it for the pctx
            RuleNetworkEvaluator.deleteLeftChild(childLeftTuple, trgLeftTuples, stagedLeftTuples);
          } // else: it's blocked now and no children so blocked before, thus do nothing
        } else if (childLeftTuple == null) {
          // not blocked, with no children, must have been previously blocked so assert
          ltm.add(leftTuple); // add to memory so other fact handles can attempt to match
          trgLeftTuples.addInsert(
              sink.createLeftTuple(
                  leftTuple,
                  sink,
                  leftTuple.getPropagationContext(),
                  true)); // use leftTuple for the pctx here, as the right one is not available
          // this won't cause a problem, as the trigger tuple (to the left) will be more recent
          // anwyay
        } else {
          updateChildLeftTuple(childLeftTuple, stagedLeftTuples, trgLeftTuples);

          // not blocked, with children, so wasn't previous blocked and still isn't so modify
          ltm.add(leftTuple); // add to memory so other fact handles can attempt to match
          childLeftTuple.reAddLeft();
        }
      }
      leftTuple.clearStaged();
      leftTuple = next;
    }
    constraints.resetTuple(contextEntry);
  }
Пример #11
0
  public void doRightInserts(
      NotNode notNode,
      BetaMemory bm,
      InternalWorkingMemory wm,
      RightTupleSets srcRightTuples,
      LeftTupleSets trgLeftTuples,
      LeftTupleSets stagedLeftTuples) {

    LeftTupleMemory ltm = bm.getLeftTupleMemory();
    RightTupleMemory rtm = bm.getRightTupleMemory();
    ContextEntry[] contextEntry = bm.getContext();
    BetaConstraints constraints = notNode.getRawConstraints();

    // this must be processed here, rather than initial insert, as we need to link the blocker
    unlinkNotNodeOnRightInsert(notNode, bm, wm);

    for (RightTuple rightTuple = srcRightTuples.getInsertFirst(); rightTuple != null; ) {
      RightTuple next = rightTuple.getStagedNext();

      rtm.add(rightTuple);
      if (ltm == null || ltm.size() == 0) {
        // do nothing here, as no left memory
        rightTuple.clearStaged();
        rightTuple = next;
        continue;
      }

      FastIterator it = notNode.getLeftIterator(ltm);
      PropagationContext context = rightTuple.getPropagationContext();

      constraints.updateFromFactHandle(contextEntry, wm, rightTuple.getFactHandle());
      for (LeftTuple leftTuple = notNode.getFirstLeftTuple(rightTuple, ltm, context, it);
          leftTuple != null; ) {
        // preserve next now, in case we remove this leftTuple
        LeftTuple temp = (LeftTuple) it.next(leftTuple);

        if (leftTuple.getStagedType() == LeftTuple.UPDATE) {
          // ignore, as it will get processed via left iteration. Children cannot be processed twice
          leftTuple = temp;
          continue;
        }

        // we know that only unblocked LeftTuples are  still in the memory
        if (constraints.isAllowedCachedRight(contextEntry, leftTuple)) {
          leftTuple.setBlocker(rightTuple);
          rightTuple.addBlocked(leftTuple);

          // this is now blocked so remove from memory
          ltm.remove(leftTuple);

          // subclasses like ForallNotNode might override this propagation
          // ** @TODO (mdp) need to not break forall
          LeftTuple childLeftTuple = leftTuple.getFirstChild();

          if (childLeftTuple != null) { // NotNode only has one child
            childLeftTuple.setPropagationContext(rightTuple.getPropagationContext());
            RuleNetworkEvaluator.deleteLeftChild(childLeftTuple, trgLeftTuples, stagedLeftTuples);
          }
        }

        leftTuple = temp;
      }
      rightTuple.clearStaged();
      rightTuple = next;
    }
    constraints.resetFactHandle(contextEntry);
  }