@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); }
@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; } }
@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; }
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); }
@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 } }
@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 } }