Exemple #1
0
  @Test
  public void testPopulatedSingleRuleNoSharing() throws Exception {
    KieBaseConfiguration kconf =
        (KieBaseConfiguration) KnowledgeBaseFactory.newKnowledgeBaseConfiguration();
    kconf.setOption(RuleEngineOption.PHREAK);

    KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase(kconf);
    InternalWorkingMemory wm = ((InternalWorkingMemory) kbase.newStatefulKnowledgeSession());

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

    wm.fireAllRules();

    kbase.addKnowledgePackages(buildKnowledgePackage("r1", "   A() B() C(object == 2) D() E()\n"));
    List list = new ArrayList();
    wm.setGlobal("list", list);

    ObjectTypeNode aotn = getObjectTypeNode(kbase, A.class);
    LeftInputAdapterNode liaNode = (LeftInputAdapterNode) aotn.getSinkPropagator().getSinks()[0];

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

    wm.fireAllRules();
    assertNull(sm.getStagedLeftTuples().getInsertFirst());
    assertEquals(1, list.size());

    assertEquals("r1", ((Match) list.get(0)).getRule().getName());
  }
  private void doRiaNode(
      InternalWorkingMemory wm,
      LeftInputAdapterNode liaNode,
      PathMemory pmem,
      TupleSets<LeftTuple> srcTuples,
      BetaNode betaNode,
      LeftTupleSinkNode sink,
      SegmentMemory[] smems,
      int smemIndex,
      Memory nodeMem,
      BetaMemory bm,
      LinkedList<StackEntry> stack,
      RuleExecutor executor) {
    RiaPathMemory pathMem = bm.getRiaRuleMemory();
    SegmentMemory[] subnetworkSmems = pathMem.getSegmentMemories();
    SegmentMemory subSmem = null;
    for (int i = 0; subSmem == null; i++) {
      // segment positions outside of the subnetwork, in the parent chain, are null
      // so we must iterate to find the first non null segment memory
      subSmem = subnetworkSmems[i];
    }

    // 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,
            smemIndex,
            srcTuples,
            false,
            false);
    stack.add(stackEntry);
    if (log.isTraceEnabled()) {
      int offset = getOffset(betaNode);
      log.trace(
          "{} RiaQueue {} {}", indent(offset), betaNode.toString(), srcTuples.toStringSizes());
    }

    TupleSets<LeftTuple> subLts = subSmem.getStagedLeftTuples().takeAll();
    // node is first in the segment, so bit is 1
    innerEval(
        liaNode,
        pathMem,
        subSmem.getRootNode(),
        1,
        subSmem.getNodeMemories().getFirst(),
        subnetworkSmems,
        subSmem.getPos(),
        subLts,
        wm,
        stack,
        true,
        executor);
  }
Exemple #3
0
  @Test
  public void testSplitTwoBeforeCreatedSegment() throws Exception {
    KnowledgeBase kbase1 =
        buildKnowledgeBase(
            "r1", "   A(1;)  A(2;) B(1;) B(2;) C(1;) C(2;) D(1;) D(2;) E(1;) E(2;)\n");
    kbase1.addKnowledgePackages(
        buildKnowledgePackage(
            "r2", "   A(1;)  A(2;) B(1;) B(2;) C(1;) C(2;) D(1;) D(2;) E(1;) E(2;)\n"));
    kbase1.addKnowledgePackages(
        buildKnowledgePackage("r3", "   A(1;)  A(2;) B(1;) B(2;) C(1;) C(2;) D(1;) D(2;)\n"));
    kbase1.addKnowledgePackages(
        buildKnowledgePackage("r4", "   A(1;)  A(2;) B(1;) B(2;) C(1;) C(2;) \n"));

    InternalWorkingMemory wm = ((InternalWorkingMemory) kbase1.newStatefulKnowledgeSession());
    List list = new ArrayList();
    wm.setGlobal("list", list);

    wm.insert(new E(1));
    wm.insert(new E(2));
    wm.flushPropagations();

    RuleTerminalNode rtn1 = getRtn("org.kie.r1", kbase1);
    RuleTerminalNode rtn2 = getRtn("org.kie.r2", kbase1);
    RuleTerminalNode rtn3 = getRtn("org.kie.r3", kbase1);
    RuleTerminalNode rtn4 = getRtn("org.kie.r4", kbase1);

    PathMemory pm1 = (PathMemory) wm.getNodeMemory(rtn1);
    SegmentMemory[] smems = pm1.getSegmentMemories();
    assertEquals(4, smems.length);
    assertNull(smems[0]);
    assertNull(smems[1]);
    assertNull(smems[3]);
    SegmentMemory sm = smems[2];
    assertEquals(2, sm.getPos());
    assertEquals(4, sm.getSegmentPosMaskBit());
    assertEquals(4, pm1.getLinkedSegmentMask());

    kbase1.addKnowledgePackages(buildKnowledgePackage("r5", "   A(1;)  A(2;) B(1;) B(2;) \n"));

    smems = pm1.getSegmentMemories();
    assertEquals(5, smems.length);
    assertNull(smems[0]);
    assertNull(smems[1]);
    assertNull(smems[2]);

    sm = smems[3];
    assertEquals(3, sm.getPos());
    assertEquals(8, sm.getSegmentPosMaskBit());
    assertEquals(8, pm1.getLinkedSegmentMask());

    RuleTerminalNode rtn5 = getRtn("org.kie.r5", kbase1);
    PathMemory pm5 = (PathMemory) wm.getNodeMemory(rtn5);
    smems = pm5.getSegmentMemories();
    assertEquals(2, smems.length);
    assertNull(smems[0]);
    assertNull(smems[1]);
  }
 private static TupleSets<LeftTuple> getTargetStagedLeftTuples(
     NetworkNode node, InternalWorkingMemory wm, SegmentMemory smem) {
   if (node == smem.getTipNode()) {
     // we are about to process the segment tip, allow it to merge insert/update/delete clashes
     if (smem.isEmpty()) {
       SegmentUtilities.createChildSegments(
           wm, smem, ((LeftTupleSource) node).getSinkPropagator());
     }
     return smem.getFirst().getStagedLeftTuples().takeAll();
   } else {
     return null;
   }
 }
Exemple #5
0
  @Test
  public void testPopulatedSharedLiaNode() throws Exception {
    KnowledgeBase kbase1 = buildKnowledgeBase("r1", "   A() B(1;) C() D() E()\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 B(2));
    wm.insert(new C(1));
    wm.insert(new D(1));
    wm.insert(new E(1));

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

    kbase1.addKnowledgePackages(buildKnowledgePackage("r2", "   a : A() B(2;) C() D() E()\n"));

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

    BetaMemory bm = (BetaMemory) wm.getNodeMemory(bNode2);
    SegmentMemory sm = bm.getSegmentMemory();
    assertNotNull(sm.getStagedLeftTuples().getInsertFirst());
    assertNotNull(sm.getStagedLeftTuples().getInsertFirst().getStagedNext());
    assertNotNull(sm.getStagedLeftTuples().getInsertFirst().getStagedNext().getStagedNext());
    assertNull(
        sm.getStagedLeftTuples().getInsertFirst().getStagedNext().getStagedNext().getStagedNext());

    wm.fireAllRules();
    assertNull(sm.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("r2", ((Match) list.get(4)).getRule().getName());
    assertEquals("r2", ((Match) list.get(5)).getRule().getName());

    List results = new ArrayList();
    results.add(((A) ((Match) list.get(3)).getDeclarationValue("a")).getObject());
    results.add(((A) ((Match) list.get(4)).getDeclarationValue("a")).getObject());
    results.add(((A) ((Match) list.get(5)).getDeclarationValue("a")).getObject());
    assertTrue(results.containsAll(asList(1, 2, 3)));
  }
 private static boolean processStreamTupleEntry(
     TupleEntryQueue tupleQueue, TupleEntry tupleEntry) {
   boolean isNonNormalizedDelete = false;
   if (log.isTraceEnabled()) {
     log.trace(
         "Stream removed entry {} {} size {}",
         System.identityHashCode(tupleQueue),
         tupleEntry,
         tupleQueue.size());
   }
   if (tupleEntry.getLeftTuple() != null) {
     SegmentMemory sm = tupleEntry.getNodeMemory().getSegmentMemory();
     LeftTupleSets tuples = sm.getStagedLeftTuples();
     tupleEntry.getLeftTuple().setPropagationContext(tupleEntry.getPropagationContext());
     switch (tupleEntry.getPropagationType()) {
       case PropagationContext.INSERTION:
       case PropagationContext.RULE_ADDITION:
         tuples.addInsert(tupleEntry.getLeftTuple());
         break;
       case PropagationContext.MODIFICATION:
         tuples.addUpdate(tupleEntry.getLeftTuple());
         break;
       case PropagationContext.DELETION:
       case PropagationContext.EXPIRATION:
       case PropagationContext.RULE_REMOVAL:
         isNonNormalizedDelete = tupleEntry.getLeftTuple().getStagedType() == LeftTuple.NONE;
         tuples.addDelete(tupleEntry.getLeftTuple());
         break;
     }
   } else {
     BetaMemory bm = (BetaMemory) tupleEntry.getNodeMemory();
     tupleEntry.getRightTuple().setPropagationContext(tupleEntry.getPropagationContext());
     switch (tupleEntry.getPropagationType()) {
       case PropagationContext.INSERTION:
       case PropagationContext.RULE_ADDITION:
         bm.getStagedRightTuples().addInsert(tupleEntry.getRightTuple());
         break;
       case PropagationContext.MODIFICATION:
         bm.getStagedRightTuples().addUpdate(tupleEntry.getRightTuple());
         break;
       case PropagationContext.DELETION:
       case PropagationContext.EXPIRATION:
       case PropagationContext.RULE_REMOVAL:
         isNonNormalizedDelete = tupleEntry.getRightTuple().getStagedType() == LeftTuple.NONE;
         bm.getStagedRightTuples().addDelete(tupleEntry.getRightTuple());
         break;
     }
   }
   return isNonNormalizedDelete;
 }
Exemple #7
0
  public void setupJoinNode() {
    buildContext = createContext();

    joinNode =
        (JoinNode)
            BetaNodeBuilder.create(NodeTypeEnums.JoinNode, buildContext)
                .setLeftType(A.class)
                .setBinding("object", "$object")
                .setRightType(B.class)
                .setConstraint("object", "!=", "$object")
                .build();

    sinkNode = new JoinNode();
    sinkNode.setId(1);
    sinkNode.setConstraints(new EmptyBetaConstraints());

    joinNode.addTupleSink(sinkNode);

    wm =
        ((StatefulKnowledgeSessionImpl)
            buildContext.getKnowledgeBase().newStatefulKnowledgeSession());

    bm = (BetaMemory) wm.getNodeMemory(joinNode);

    bm0 = (BetaMemory) wm.getNodeMemory(sinkNode);

    smem = new SegmentMemory(joinNode);
    bm.setSegmentMemory(smem);

    smem0 = new SegmentMemory(sinkNode);
    bm0.setSegmentMemory(smem0);
    smem.add(smem0);
  }
Exemple #8
0
  @Test
  public void testPopulatedSharedToRtn() throws Exception {
    KnowledgeBase kbase1 = buildKnowledgeBase("r1", "   A() B() C() D() E()\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 B(1));
    wm.insert(new C(1));
    wm.insert(new D(1));
    wm.insert(new E(1));

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

    kbase1.addKnowledgePackages(buildKnowledgePackage("r2", "   A() B() C() D() E()\n"));

    ObjectTypeNode eotn = getObjectTypeNode(kbase1, E.class);
    JoinNode eNode = (JoinNode) eotn.getSinkPropagator().getSinks()[0];
    RuleTerminalNode rtn = (RuleTerminalNode) eNode.getSinkPropagator().getLastLeftTupleSink();

    PathMemory pm = (PathMemory) wm.getNodeMemory(rtn);
    SegmentMemory sm = pm.getSegmentMemory();
    assertNotNull(sm.getStagedLeftTuples().getInsertFirst());
    assertNotNull(sm.getStagedLeftTuples().getInsertFirst().getStagedNext());
    assertNull(sm.getStagedLeftTuples().getInsertFirst().getStagedNext().getStagedNext());

    wm.fireAllRules();
    assertNull(sm.getStagedLeftTuples().getInsertFirst());
    assertEquals(4, list.size());

    System.out.println(list);

    assertEquals("r1", ((Match) list.get(0)).getRule().getName());
    assertEquals("r1", ((Match) list.get(1)).getRule().getName());
    assertEquals("r2", ((Match) list.get(2)).getRule().getName());
    assertEquals("r2", ((Match) list.get(3)).getRule().getName());
  }
  public int evaluateNetwork(PathMemory pmem, InternalWorkingMemory wm, RuleExecutor executor) {
    SegmentMemory[] smems = pmem.getSegmentMemories();

    int smemIndex = 0;
    SegmentMemory smem = smems[smemIndex]; // 0
    LeftInputAdapterNode liaNode = (LeftInputAdapterNode) smem.getRootNode();

    NetworkNode node;
    Memory nodeMem;
    if (liaNode == smem.getTipNode()) {
      // segment only has liaNode in it
      // nothing is staged in the liaNode, so skip to next segment
      smem = smems[++smemIndex]; // 1
      node = smem.getRootNode();
      nodeMem = smem.getNodeMemories().getFirst();
    } else {
      // lia is in shared segment, so point to next node
      node = liaNode.getSinkPropagator().getFirstLeftTupleSink();
      nodeMem = smem.getNodeMemories().getFirst().getNext(); // skip the liaNode memory
    }

    LeftTupleSets srcTuples = smem.getStagedLeftTuples();

    if (log.isTraceEnabled()) {
      log.trace(
          "Rule[name={}] segments={} {}",
          ((TerminalNode) pmem.getNetworkNode()).getRule().getName(),
          smems.length,
          srcTuples.toStringSizes());
    }

    Set<String> visitedRules;
    if (((TerminalNode) pmem.getNetworkNode()).getType() == NodeTypeEnums.QueryTerminalNode) {
      visitedRules = new HashSet<String>();
    } else {
      visitedRules = Collections.<String>emptySet();
    }

    LinkedList<StackEntry> stack = new LinkedList<StackEntry>();
    eval1(
        liaNode,
        pmem,
        (LeftTupleSink) node,
        nodeMem,
        smems,
        smemIndex,
        srcTuples,
        wm,
        stack,
        visitedRules,
        true,
        executor);

    return 0;
  }
  public void evaluateNetwork(PathMemory pmem, RuleExecutor executor, InternalWorkingMemory wm) {
    SegmentMemory[] smems = pmem.getSegmentMemories();

    int smemIndex = 0;
    SegmentMemory smem = smems[smemIndex]; // 0
    LeftInputAdapterNode liaNode = (LeftInputAdapterNode) smem.getRootNode();

    LinkedList<StackEntry> stack = new LinkedList<StackEntry>();

    NetworkNode node;
    Memory nodeMem;
    long bit = 1;
    if (liaNode == smem.getTipNode()) {
      // segment only has liaNode in it
      // nothing is staged in the liaNode, so skip to next segment
      smem = smems[++smemIndex]; // 1
      node = smem.getRootNode();
      nodeMem = smem.getNodeMemories().getFirst();
    } else {
      // lia is in shared segment, so point to next node
      bit = 2;
      node = liaNode.getSinkPropagator().getFirstLeftTupleSink();
      nodeMem = smem.getNodeMemories().getFirst().getNext(); // skip the liaNode memory
    }

    TupleSets<LeftTuple> srcTuples = smem.getStagedLeftTuples();
    if (log.isTraceEnabled()) {
      log.trace(
          "Rule[name={}] segments={} {}",
          ((TerminalNode) pmem.getNetworkNode()).getRule().getName(),
          smems.length,
          srcTuples.toStringSizes());
    }
    outerEval(
        liaNode, pmem, node, bit, nodeMem, smems, smemIndex, srcTuples, wm, stack, true, executor);
  }
  public void eval1(
      LeftInputAdapterNode liaNode,
      PathMemory rmem,
      NetworkNode node,
      Memory nodeMem,
      SegmentMemory[] smems,
      int smemIndex,
      LeftTupleSets trgTuples,
      InternalWorkingMemory wm,
      LinkedList<StackEntry> stack,
      Set<String> visitedRules,
      boolean processRian,
      RuleExecutor executor) {
    while (true) {
      eval2(
          liaNode,
          rmem,
          node,
          nodeMem,
          smems,
          smemIndex,
          trgTuples,
          wm,
          stack,
          visitedRules,
          processRian,
          executor);

      // eval
      if (!stack.isEmpty()) {
        StackEntry entry = stack.removeLast();

        node = entry.getNode();
        nodeMem = entry.getNodeMem();
        trgTuples = entry.getTrgTuples();
        if (node.getType() == NodeTypeEnums.QueryElementNode) {
          // copy across the results, if any from the query node memory
          trgTuples.addAll(((QueryElementNodeMemory) nodeMem).getResultLeftTuples());
        }

        LeftTupleSinkNode sink = entry.getSink();
        rmem = entry.getRmem();

        smems = entry.getSmems();
        smemIndex = entry.getSmemIndex();
        visitedRules = entry.getVisitedRules();
        if (NodeTypeEnums.isBetaNode(node)) {
          // queued beta nodes do not want their ria node evaluated, otherwise there is recursion
          processRian = false;
        } else {
          processRian = true;
        }

        if (entry.isResumeFromNextNode()) {
          SegmentMemory smem = smems[smemIndex];
          if (node != smem.getTipNode()) {
            // get next node and node memory in the segment
            LeftTupleSink nextSink = sink.getNextLeftTupleSinkNode();
            if (nextSink == null) {
              node = sink;
            } else {
              // there is a nested subnetwork, take out path
              node = nextSink;
            }

            nodeMem = nodeMem.getNext();
          } else {
            // Reached end of segment, start on new segment.
            SegmentPropagator.propagate(smem, trgTuples, wm);
            smem = smems[++smemIndex];
            trgTuples = smem.getStagedLeftTuples();
            node = (LeftTupleSink) smem.getRootNode();
            nodeMem = smem.getNodeMemories().getFirst();
          }
        }

        if (log.isTraceEnabled()) {
          int offset = getOffset(node);
          log.trace("{} Resume {} {}", indent(offset), node.toString(), trgTuples.toStringSizes());
        }
      } else {
        return; // stack is empty return;
      }
    }
  }
  public void evalStackEntry(
      StackEntry entry,
      LinkedList<StackEntry> stack,
      RuleExecutor executor,
      InternalWorkingMemory wm) {
    NetworkNode node = entry.getNode();
    Memory nodeMem = entry.getNodeMem();
    TupleSets<LeftTuple> trgTuples = entry.getTrgTuples();
    if (node.getType() == NodeTypeEnums.QueryElementNode) {
      // copy across the results, if any from the query node memory
      QueryElementNodeMemory qmem = (QueryElementNodeMemory) nodeMem;
      qmem.setNodeCleanWithoutNotify();
      trgTuples.addAll(qmem.getResultLeftTuples());
    }

    LeftTupleSinkNode sink = entry.getSink();
    PathMemory pmem = entry.getRmem();

    SegmentMemory[] smems = entry.getSmems();
    int smemIndex = entry.getSmemIndex();
    boolean processRian = entry.isProcessRian();

    long bit = entry.getBit();
    if (entry.isResumeFromNextNode()) {
      SegmentMemory smem = smems[smemIndex];
      if (node != smem.getTipNode()) {
        // get next node and node memory in the segment
        LeftTupleSink nextSink = sink.getNextLeftTupleSinkNode();
        if (nextSink == null) {
          node = sink;
        } else {
          // there is a nested subnetwork, take out path
          node = nextSink;
        }

        nodeMem = nodeMem.getNext();
        bit = bit << 1; // update bit to new node
      } else {
        // Reached end of segment, start on new segment.
        SegmentPropagator.propagate(smem, trgTuples, wm);
        smem = smems[++smemIndex];
        trgTuples = smem.getStagedLeftTuples().takeAll();
        node = smem.getRootNode();
        nodeMem = smem.getNodeMemories().getFirst();
        bit = 1; // update bit to start of new segment
      }
    }

    if (log.isTraceEnabled()) {
      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);
  }
  private void doRiaNode(
      InternalWorkingMemory wm,
      LeftInputAdapterNode liaNode,
      PathMemory rmem,
      LeftTupleSets srcTuples,
      BetaNode betaNode,
      LeftTupleSinkNode sink,
      SegmentMemory[] smems,
      int smemIndex,
      Memory nodeMem,
      BetaMemory bm,
      LinkedList<StackEntry> stack,
      Set<String> visitedRules,
      RuleExecutor executor) {
    RiaPathMemory pathMem = bm.getRiaRuleMemory();
    SegmentMemory[] subnetworkSmems = pathMem.getSegmentMemories();
    SegmentMemory subSmem = null;
    for (int i = 0; subSmem == null; i++) {
      // segment positions outside of the subnetwork, in the parent chain, are null
      // so we must iterate to find the first non null segment memory
      subSmem = subnetworkSmems[i];
    }

    //        if (betaNode.getLeftTupleSource().getSinkPropagator().size() == 2) {
    //            // sub network is not part of  share split, so need to handle propagation
    //            // this ensures the first LeftTuple is actually the subnetwork node
    //            // and the main outer network now receives the peer, notice the swap at the end
    // "srcTuples == peerTuples"
    //            LeftTupleSets peerTuples = new LeftTupleSets();
    //            SegmentPropagator.processPeers(srcTuples, peerTuples, betaNode);
    //            // Make sure subnetwork Segment has tuples to process
    //            LeftTupleSets subnetworkStaged = subSmem.getStagedLeftTuples();
    //            subnetworkStaged.addAll(srcTuples);
    //
    //            srcTuples.resetAll();
    //
    //            srcTuples = peerTuples;
    //        }

    // Resume the node after the riaNode segment has been processed and the right input memory
    // populated
    StackEntry stackEntry =
        new StackEntry(
            liaNode,
            betaNode,
            sink,
            rmem,
            nodeMem,
            smems,
            smemIndex,
            srcTuples,
            visitedRules,
            false);
    stack.add(stackEntry);
    if (log.isTraceEnabled()) {
      int offset = getOffset(betaNode);
      log.trace(
          "{} RiaQueue {} {}", indent(offset), betaNode.toString(), srcTuples.toStringSizes());
    }

    //        RightInputAdapterNode riaNode = ( RightInputAdapterNode ) betaNode.getRightInput();
    // RiaNodeMemory riaNodeMemory = (RiaNodeMemory) wm.getNodeMemory((MemoryFactory)
    // betaNode.getRightInput());
    // LeftTupleSets riaStagedTuples =
    eval2(
        liaNode,
        pathMem,
        (LeftTupleSink) subSmem.getRootNode(),
        subSmem.getNodeMemories().getFirst(),
        subnetworkSmems,
        subSmem.getPos(),
        subSmem.getStagedLeftTuples(),
        wm,
        stack,
        visitedRules,
        true,
        executor);
  }
  public void innerEval(
      LeftInputAdapterNode liaNode,
      PathMemory pmem,
      NetworkNode node,
      long bit,
      Memory nodeMem,
      SegmentMemory[] smems,
      int smemIndex,
      TupleSets<LeftTuple> trgTuples,
      InternalWorkingMemory wm,
      LinkedList<StackEntry> stack,
      boolean processRian,
      RuleExecutor executor) {
    TupleSets<LeftTuple> srcTuples;
    SegmentMemory smem = smems[smemIndex];
    TupleSets<LeftTuple> stagedLeftTuples = null;
    while (true) {
      srcTuples = trgTuples; // previous target, is now the source
      if (log.isTraceEnabled()) {
        int offset = getOffset(node);
        log.trace(
            "{} {} {} {}", indent(offset), ++cycle, node.toString(), srcTuples.toStringSizes());
      }

      boolean emptySrcTuples = srcTuples.isEmpty();
      if (!(NodeTypeEnums.isBetaNode(node) && ((BetaNode) node).isRightInputIsRiaNode())) {
        // The engine cannot skip a ria node, as the dirty might be several levels deep
        if (emptySrcTuples && smem.getDirtyNodeMask() == 0) {
          // empty sources and segment is not dirty, skip to non empty src tuples or dirty segment.
          boolean foundDirty = false;
          for (int i = ++smemIndex, length = smems.length; i < length; i++) {
            if (log.isTraceEnabled()) {
              int offset = getOffset(node);
              log.trace("{} Skip Segment {}", indent(offset), i - 1);
            }

            // this is needed for subnetworks that feed into a parent network that has no right
            // inputs,
            // and may not yet be initialized
            if (smem.isEmpty() && !NodeTypeEnums.isTerminalNode(smem.getTipNode())) {
              SegmentUtilities.createChildSegments(
                  wm, smem, ((LeftTupleSource) smem.getTipNode()).getSinkPropagator());
            }

            smem = smems[i];
            bit = 1;
            srcTuples = smem.getStagedLeftTuples().takeAll();
            emptySrcTuples = srcTuples.isEmpty();
            node = smem.getRootNode();
            nodeMem = smem.getNodeMemories().getFirst();
            if (!emptySrcTuples
                || smem.getDirtyNodeMask() != 0
                || (NodeTypeEnums.isBetaNode(node) && ((BetaNode) node).isRightInputIsRiaNode())) {
              // break if dirty or if we reach a subnetwork. It must break for subnetworks, so they
              // can be searched.
              foundDirty = true;
              smemIndex = i;
              break;
            }
          }
          if (!foundDirty) {
            break;
          }
        }
        if (log.isTraceEnabled()) {
          int offset = getOffset(node);
          log.trace("{} Segment {}", indent(offset), smemIndex);
          log.trace(
              "{} {} {} {}", indent(offset), cycle, node.toString(), srcTuples.toStringSizes());
        }
      }

      long dirtyMask = smem.getDirtyNodeMask();
      if (emptySrcTuples) {
        while ((dirtyMask & bit) == 0
            && node != smem.getTipNode()
            && !(NodeTypeEnums.isBetaNode(node) && ((BetaNode) node).isRightInputIsRiaNode())) {
          if (log.isTraceEnabled()) {
            int offset = getOffset(node);
            log.trace("{} Skip Node {}", indent(offset), node);
          }
          bit = bit << 1; // shift to check the next node
          node = ((LeftTupleSource) node).getSinkPropagator().getFirstLeftTupleSink();
          nodeMem = nodeMem.getNext();
        }
      }

      if (NodeTypeEnums.isTerminalNode(node)) {
        TerminalNode rtn = (TerminalNode) node;
        if (node.getType() == NodeTypeEnums.QueryTerminalNode) {
          pQtNode.doNode((QueryTerminalNode) rtn, wm, srcTuples, stack);
        } else {
          pRtNode.doNode(rtn, wm, srcTuples, executor);
        }
        break;
      } else if (NodeTypeEnums.RightInputAdaterNode == node.getType()) {
        doRiaNode2(wm, srcTuples, (RightInputAdapterNode) node);
        break;
      }

      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);
      if (trgTuples == null) {
        break; // Queries exists and has been placed StackEntry, and there are no current trgTuples
        // to process
      }

      if (node != smem.getTipNode()) {
        // get next node and node memory in the segment
        node = sink;
        nodeMem = nodeMem.getNext();
        bit = bit << 1;
      } else {
        // Reached end of segment, start on new segment.
        smem.getFirst().getStagedLeftTuples().addAll(stagedLeftTuples); // must put back all the LTs
        // end of SegmentMemory, so we know that stagedLeftTuples is not null
        SegmentPropagator.propagate(smem, trgTuples, wm);
        bit = 1;
        smem = smems[++smemIndex];
        trgTuples = smem.getStagedLeftTuples().takeAll();

        if (log.isTraceEnabled()) {
          int offset = getOffset(node);
          log.trace("{} Segment {}", indent(offset), smemIndex);
        }
        node = smem.getRootNode();
        nodeMem = smem.getNodeMemories().getFirst();
      }
      processRian = true; //  make sure it's reset, so ria nodes are processed
    }

    if (stagedLeftTuples != null && !stagedLeftTuples.isEmpty()) {
      smem.getFirst().getStagedLeftTuples().addAll(stagedLeftTuples); // must put back all the LTs
    }
  }
Exemple #15
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());
  }
  private boolean evalQueryNode(
      LeftInputAdapterNode liaNode,
      PathMemory pmem,
      NetworkNode node,
      long bit,
      Memory nodeMem,
      SegmentMemory[] smems,
      int smemIndex,
      TupleSets<LeftTuple> trgTuples,
      InternalWorkingMemory wm,
      LinkedList<StackEntry> stack,
      TupleSets<LeftTuple> srcTuples,
      LeftTupleSinkNode sink,
      TupleSets<LeftTuple> stagedLeftTuples) {
    QueryElementNodeMemory qmem = (QueryElementNodeMemory) nodeMem;

    if (srcTuples.isEmpty() && qmem.getResultLeftTuples().isEmpty()) {
      // no point in evaluating query element, and setting up stack, if there is nothing to process
      return false;
    }

    QueryElementNode qnode = (QueryElementNode) node;

    if (log.isTraceEnabled()) {
      int offset = getOffset(node);
      log.trace(
          "{} query result tuples {}", indent(offset), qmem.getResultLeftTuples().toStringSizes());
    }

    // result tuples can happen when reactivity occurs inside of the query, prior to evaluation
    // we will need special behaviour to add the results again, when this query result resumes
    trgTuples.addAll(qmem.getResultLeftTuples());
    qmem.setNodeCleanWithoutNotify();

    if (!srcTuples.isEmpty()) {
      // only process the Query Node if there are src tuples
      StackEntry stackEntry =
          new StackEntry(
              liaNode, node, bit, sink, pmem, nodeMem, smems, smemIndex, trgTuples, true, true);

      stack.add(stackEntry);

      pQueryNode.doNode(
          qnode,
          (QueryElementNodeMemory) nodeMem,
          stackEntry,
          wm,
          srcTuples,
          trgTuples,
          stagedLeftTuples);

      SegmentMemory qsmem = ((QueryElementNodeMemory) nodeMem).getQuerySegmentMemory();
      List<PathMemory> qpmems = qsmem.getPathMemories();

      // Build the evaluation information for each 'or' branch
      for (int i = 0; i < qpmems.size(); i++) {
        PathMemory qpmem = qpmems.get(i);

        pmem = qpmem;
        smems = qpmem.getSegmentMemories();
        smemIndex = 0;
        SegmentMemory smem = smems[smemIndex]; // 0
        liaNode = (LeftInputAdapterNode) smem.getRootNode();

        if (liaNode == smem.getTipNode()) {
          // segment only has liaNode in it
          // nothing is staged in the liaNode, so skip to next segment
          smem = smems[++smemIndex]; // 1
          node = smem.getRootNode();
          nodeMem = smem.getNodeMemories().getFirst();
          bit = 1;
        } else {
          // lia is in shared segment, so point to next node
          node = liaNode.getSinkPropagator().getFirstLeftTupleSink();
          nodeMem = smem.getNodeMemories().getFirst().getNext(); // skip the liaNode memory
          bit = 2;
        }

        trgTuples = smem.getStagedLeftTuples().takeAll();
        stackEntry =
            new StackEntry(
                liaNode, node, bit, null, pmem, nodeMem, smems, smemIndex, trgTuples, false, true);
        if (log.isTraceEnabled()) {
          int offset = getOffset(stackEntry.getNode());
          log.trace(
              "{} ORQueue branch={} {} {}",
              indent(offset),
              i,
              stackEntry.getNode().toString(),
              trgTuples.toStringSizes());
        }
        stack.add(stackEntry);
      }
      return true;
    } else {
      return false;
    }
  }
    @Override
    public void run() {
      System.out.println("Sync point");
      if (pathMemories == null) {
        initPathMemories();
      }

      String s = "";
      for (int i = 0; i < epManipulators.length; i++) {
        if (epManipulators[i].isInserted()) {
          s = "1" + s;
        } else {
          s = "0" + s;
        }
      }
      System.out.println("Inserted facts mask = " + s);

      // P0 = s0 + s1
      SegmentMemory s0 = pathMemories[0].getSegmentMemories()[0];
      SegmentMemory s1 = pathMemories[0].getSegmentMemories()[1];

      // P1 = s0 + s2 + s3
      SegmentMemory s2 = pathMemories[1].getSegmentMemories()[1];
      SegmentMemory s3 = pathMemories[1].getSegmentMemories()[2];

      // P2 = s0 + s2 + s4
      SegmentMemory s4 = pathMemories[2].getSegmentMemories()[2];

      long s0Mask = 1; // InitialFact is always present
      long s1Mask = 0;
      long s2Mask = 0;
      long s3Mask = 0;
      long s4Mask = 0;

      if (epManipulators[0].isInserted()) {
        s0Mask |= 2;
      }
      if (epManipulators[1].isInserted()) {
        s0Mask |= 4;
      }
      if (epManipulators[2].isInserted()) {
        s0Mask |= 8;
      }
      if (epManipulators[3].isInserted()) {
        s1Mask |= 1;
        s2Mask |= 2;
      }
      if (epManipulators[4].isInserted()) {
        s1Mask |= 2;
        s2Mask |= 4;
      }
      if (epManipulators[5].isInserted()) {
        s1Mask |= 4;
        s2Mask |= 8;
      }
      if (epManipulators[6].isInserted()) {
        s1Mask |= 8;
        s3Mask |= 1;
        s4Mask |= 2;
      }
      if (epManipulators[7].isInserted()) {
        s1Mask |= 16;
        s3Mask |= 2;
        s4Mask |= 4;
      }
      if (epManipulators[8].isInserted()) {
        s1Mask |= 32;
        s3Mask |= 4;
        s4Mask |= 8;
      }

      assertEquals(s0Mask, s0.getLinkedNodeMask());
      assertEquals(s1Mask, s1.getLinkedNodeMask());
      assertEquals(s2Mask, s2.getLinkedNodeMask());
      assertEquals(s3Mask, s3.getLinkedNodeMask());
      assertEquals(s4Mask, s4.getLinkedNodeMask());

      long p0Mask = 0;
      long p1Mask = 0;
      long p2Mask = 0;

      if ((s0Mask & 15) == 15) {
        assertTrue(s0.isSegmentLinked());
        p0Mask |= 1;
        p1Mask |= 1;
        p2Mask |= 1;
      } else {
        assertFalse(s0.isSegmentLinked());
      }

      if ((s1Mask & 63) == 63) {
        assertTrue(s1.isSegmentLinked());
        p0Mask |= 2;
      } else {
        assertFalse(s1.isSegmentLinked());
      }

      if ((s2Mask & 14) == 14) {
        assertTrue(s2.isSegmentLinked());
        p1Mask |= 2;
        p2Mask |= 2;
      } else {
        assertFalse(s2.isSegmentLinked());
      }

      if ((s3Mask & 7) == 7) {
        assertTrue(s3.isSegmentLinked());
        p1Mask |= 4;
      } else {
        assertFalse(s3.isSegmentLinked());
      }

      if ((s4Mask & 14) == 14) {
        assertTrue(s4.isSegmentLinked());
        p2Mask |= 4;
      } else {
        assertFalse(s4.isSegmentLinked());
      }

      assertEquals(p0Mask == 3, pathMemories[0].isRuleLinked());
      assertEquals(p1Mask == 7, pathMemories[1].isRuleLinked());
      assertEquals(p2Mask == 7, pathMemories[2].isRuleLinked());
    }
  public void eval2(
      LeftInputAdapterNode liaNode,
      PathMemory rmem,
      NetworkNode node,
      Memory nodeMem,
      SegmentMemory[] smems,
      int smemIndex,
      LeftTupleSets trgTuples,
      InternalWorkingMemory wm,
      LinkedList<StackEntry> stack,
      Set<String> visitedRules,
      boolean processRian,
      RuleExecutor executor) {
    LeftTupleSets srcTuples;
    SegmentMemory smem = smems[smemIndex];
    while (true) {
      srcTuples = trgTuples; // previous target, is now the source
      if (log.isTraceEnabled()) {
        int offset = getOffset(node);
        log.trace(
            "{} {} {} {}", indent(offset), ++cycle, node.toString(), srcTuples.toStringSizes());
      }

      if (NodeTypeEnums.isTerminalNode(node)) {
        TerminalNode rtn = (TerminalNode) node;
        if (node.getType() == NodeTypeEnums.QueryTerminalNode) {
          pQtNode.doNode((QueryTerminalNode) rtn, wm, srcTuples, stack);
        } else {
          pRtNode.doNode(rtn, wm, srcTuples, executor);
        }
        return;
      } else if (NodeTypeEnums.RightInputAdaterNode == node.getType()) {
        doRiaNode2(wm, srcTuples, (RightInputAdapterNode) node, stack);
        return;
      }

      LeftTupleSets stagedLeftTuples;
      if (node == smem.getTipNode() && smem.getFirst() != null) {
        // we are about to process the segment tip, allow it to merge insert/update/delete clashes
        // Can happen if the next segments have not yet been initialized
        stagedLeftTuples = smem.getFirst().getStagedLeftTuples();
      } else {
        stagedLeftTuples = null;
      }

      LeftTupleSinkNode sink = ((LeftTupleSource) node).getSinkPropagator().getFirstLeftTupleSink();

      trgTuples = new LeftTupleSets();

      if (NodeTypeEnums.isBetaNode(node)) {
        BetaNode betaNode = (BetaNode) node;

        BetaMemory bm = null;
        AccumulateMemory am = null;
        if (NodeTypeEnums.AccumulateNode == node.getType()) {
          am = (AccumulateMemory) nodeMem;
          bm = am.getBetaMemory();
        } else {
          bm = (BetaMemory) nodeMem;
        }

        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,
              rmem,
              srcTuples,
              betaNode,
              sink,
              smems,
              smemIndex,
              nodeMem,
              bm,
              stack,
              visitedRules,
              executor);
          return; // return here is doRiaNode queues the evaluation on the stack, which is necessary
          // to handled nested query nodes
        }

        if (!bm.getDequeu().isEmpty()) {
          // If there are no staged RightTuples, then process the Dequeue, popping entries, until
          // another insert/expiration clash
          RightTupleSets rightTuples = bm.getStagedRightTuples();
          if (rightTuples.isEmpty()) {
            // nothing staged, so now process the Dequeu
            Deque<RightTuple> que = bm.getDequeu();
            while (!que.isEmpty()) {
              RightTuple rightTuple = que.peekFirst();
              if (rightTuple.getPropagationContext().getType() == PropagationContext.EXPIRATION
                  &&
                  // Cannot pop an expired fact, if the insert/update has not yet been evaluated.
                  rightTuple.getStagedType() != LeftTuple.NONE) {
                break;
              }

              switch (rightTuple.getPropagationContext().getType()) {
                case PropagationContext.INSERTION:
                case PropagationContext.RULE_ADDITION:
                  rightTuples.addInsert(rightTuple);
                  break;
                case PropagationContext.MODIFICATION:
                  rightTuples.addUpdate(rightTuple);
                  break;
                case PropagationContext.DELETION:
                case PropagationContext.EXPIRATION:
                case PropagationContext.RULE_REMOVAL:
                  rightTuples.addDelete(rightTuple);
                  break;
              }
              que.removeFirst();
            }
          }

          if (!bm.getDequeu().isEmpty()) {
            // The DeQue is not empty, add StackEntry for reprocessing.
            StackEntry stackEntry =
                new StackEntry(
                    liaNode,
                    node,
                    sink,
                    rmem,
                    nodeMem,
                    smems,
                    smemIndex,
                    trgTuples,
                    visitedRules,
                    false);
            stack.add(stackEntry);
          }
        }

        switch (node.getType()) {
          case NodeTypeEnums.JoinNode:
            {
              pJoinNode.doNode(
                  (JoinNode) node, sink, bm, wm, srcTuples, trgTuples, stagedLeftTuples);
              break;
            }
          case NodeTypeEnums.NotNode:
            {
              pNotNode.doNode((NotNode) node, sink, bm, wm, srcTuples, trgTuples, stagedLeftTuples);
              break;
            }
          case NodeTypeEnums.ExistsNode:
            {
              pExistsNode.doNode(
                  (ExistsNode) node, sink, bm, wm, srcTuples, trgTuples, stagedLeftTuples);
              break;
            }
          case NodeTypeEnums.AccumulateNode:
            {
              pAccNode.doNode(
                  (AccumulateNode) node, sink, am, wm, srcTuples, trgTuples, stagedLeftTuples);
              break;
            }
        }
      } else {
        switch (node.getType()) {
          case NodeTypeEnums.EvalConditionNode:
            {
              pEvalNode.doNode(
                  (EvalConditionNode) node,
                  (EvalMemory) nodeMem,
                  sink,
                  wm,
                  srcTuples,
                  trgTuples,
                  stagedLeftTuples);
              break;
            }
          case NodeTypeEnums.FromNode:
            {
              pFromNode.doNode(
                  (FromNode) node,
                  (FromMemory) nodeMem,
                  sink,
                  wm,
                  srcTuples,
                  trgTuples,
                  stagedLeftTuples);
              break;
            }
          case NodeTypeEnums.QueryElementNode:
            {
              QueryElementNodeMemory qmem = (QueryElementNodeMemory) nodeMem;

              if (srcTuples.isEmpty() && qmem.getResultLeftTuples().isEmpty()) {
                // no point in evaluating query element, and setting up stack, if there is nothing
                // to process
                break;
              }

              QueryElementNode qnode = (QueryElementNode) node;
              if (visitedRules == Collections.<String>emptySet()) {
                visitedRules = new HashSet<String>();
              }
              visitedRules.add(qnode.getQueryElement().getQueryName());

              // result tuples can happen when reactivity occurs inside of the query, prior to
              // evaluation
              // we will need special behaviour to add the results again, when this query result
              // resumes
              trgTuples.addAll(qmem.getResultLeftTuples());

              if (!srcTuples.isEmpty()) {
                // only process the Query Node if there are src tuples
                StackEntry stackEntry =
                    new StackEntry(
                        liaNode,
                        node,
                        sink,
                        rmem,
                        nodeMem,
                        smems,
                        smemIndex,
                        trgTuples,
                        visitedRules,
                        true);

                stack.add(stackEntry);

                pQueryNode.doNode(
                    qnode, (QueryElementNodeMemory) nodeMem, stackEntry, sink, wm, srcTuples);

                SegmentMemory qsmem = ((QueryElementNodeMemory) nodeMem).getQuerySegmentMemory();
                List<PathMemory> qrmems = qsmem.getPathMemories();

                // Build the evaluation information for each 'or' branch
                // Exception fo the last, place each entry on the stack, the last one evaluate now.
                for (int i = qrmems.size() - 1; i >= 0; i--) {
                  PathMemory qrmem = qrmems.get(i);

                  rmem = qrmem;
                  smems = qrmem.getSegmentMemories();
                  smemIndex = 0;
                  smem = smems[smemIndex]; // 0
                  liaNode = (LeftInputAdapterNode) smem.getRootNode();

                  if (liaNode == smem.getTipNode()) {
                    // segment only has liaNode in it
                    // nothing is staged in the liaNode, so skip to next segment
                    smem = smems[++smemIndex]; // 1
                    node = smem.getRootNode();
                    nodeMem = smem.getNodeMemories().getFirst();
                  } else {
                    // lia is in shared segment, so point to next node
                    node = liaNode.getSinkPropagator().getFirstLeftTupleSink();
                    nodeMem =
                        smem.getNodeMemories().getFirst().getNext(); // skip the liaNode memory
                  }

                  trgTuples = smem.getStagedLeftTuples();

                  if (i != 0 && !trgTuples.isEmpty()) {
                    // All entries except the last should be placed on the stack for evaluation
                    // later.
                    stackEntry =
                        new StackEntry(
                            liaNode,
                            node,
                            null,
                            rmem,
                            nodeMem,
                            smems,
                            smemIndex,
                            trgTuples,
                            visitedRules,
                            false);
                    if (log.isTraceEnabled()) {
                      int offset = getOffset(stackEntry.getNode());
                      log.trace(
                          "{} ORQueue branch={} {} {}",
                          indent(offset),
                          i,
                          stackEntry.getNode().toString(),
                          trgTuples.toStringSizes());
                    }
                    stack.add(stackEntry);
                  }
                }
                processRian = true; //  make sure it's reset, so ria nodes are processed
                continue;
              }
              break;
            }
          case NodeTypeEnums.ConditionalBranchNode:
            {
              pBranchNode.doNode(
                  (ConditionalBranchNode) node,
                  (ConditionalBranchMemory) nodeMem,
                  sink,
                  wm,
                  srcTuples,
                  trgTuples,
                  stagedLeftTuples,
                  executor);
              break;
            }
        }
      }

      if (node != smem.getTipNode()) {
        // get next node and node memory in the segment
        node = sink;
        nodeMem = nodeMem.getNext();
      } else {
        // Reached end of segment, start on new segment.
        SegmentPropagator.propagate(smem, trgTuples, wm);
        smem = smems[++smemIndex];
        trgTuples = smem.getStagedLeftTuples();
        if (log.isTraceEnabled()) {
          log.trace("Segment {}", smemIndex);
        }
        node = (LeftTupleSink) smem.getRootNode();
        nodeMem = smem.getNodeMemories().getFirst();
      }
      processRian = true; //  make sure it's reset, so ria nodes are processed
    }
  }