use of org.drools.core.reteoo.LeftTupleSinkNode in project drools by kiegroup.
the class RuleNetworkEvaluator method innerEval.
public void innerEval(PathMemory pmem, NetworkNode node, long bit, Memory nodeMem, SegmentMemory[] smems, int smemIndex, TupleSets<LeftTuple> trgTuples, InternalAgenda agenda, LinkedList<StackEntry> stack, boolean processRian, RuleExecutor executor) {
TupleSets<LeftTuple> srcTuples;
SegmentMemory smem = smems[smemIndex];
TupleSets<LeftTuple> stagedLeftTuples = null;
while (true) {
// previous target, is now the source
srcTuples = trgTuples;
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);
}
// and may not yet be initialized
if (smem.isEmpty() && !NodeTypeEnums.isTerminalNode(smem.getTipNode())) {
SegmentUtilities.createChildSegments(agenda.getWorkingMemory(), 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);
}
// shift to check the next node
bit = bit << 1;
node = ((LeftTupleSource) node).getSinkPropagator().getFirstLeftTupleSink();
nodeMem = nodeMem.getNext();
}
}
boolean terminalNode = true;
switch(node.getType()) {
case NodeTypeEnums.RuleTerminalNode:
pRtNode.doNode((TerminalNode) node, agenda, srcTuples, executor);
break;
case NodeTypeEnums.QueryTerminalNode:
pQtNode.doNode((QueryTerminalNode) node, agenda, srcTuples, stack);
break;
case NodeTypeEnums.RightInputAdaterNode:
doRiaNode2(agenda.getWorkingMemory(), srcTuples, (RightInputAdapterNode) node);
break;
default:
terminalNode = false;
}
if (terminalNode) {
break;
}
stagedLeftTuples = getTargetStagedLeftTuples(node, agenda.getWorkingMemory(), smem);
LeftTupleSinkNode sink = ((LeftTupleSource) node).getSinkPropagator().getFirstLeftTupleSink();
trgTuples = evalNode(pmem, node, bit, nodeMem, smems, smemIndex, agenda, stack, processRian, executor, srcTuples, smem, stagedLeftTuples, sink);
if (trgTuples == null) {
// Queries exists and has been placed StackEntry, and there are no current trgTuples to process
break;
}
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.
// must put back all the LTs
smem.getFirst().getStagedLeftTuples().addAll(stagedLeftTuples);
// end of SegmentMemory, so we know that stagedLeftTuples is not null
SegmentPropagator.propagate(smem, trgTuples, agenda.getWorkingMemory());
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();
}
// make sure it's reset, so ria nodes are processed
processRian = true;
}
if (stagedLeftTuples != null && !stagedLeftTuples.isEmpty()) {
// must put back all the LTs
smem.getFirst().getStagedLeftTuples().addAll(stagedLeftTuples);
}
}
use of org.drools.core.reteoo.LeftTupleSinkNode in project drools by kiegroup.
the class SegmentUtilities method isNonTerminalTipNode.
public static boolean isNonTerminalTipNode(LeftTupleNode node, TerminalNode removingTN) {
LeftTupleSinkPropagator sinkPropagator = node.getSinkPropagator();
if (removingTN == null) {
return sinkPropagator.size() > 1;
}
if (sinkPropagator.size() == 1) {
return false;
}
// we know the sink size is creater than 1 and that there is a removingRule that needs to be ignored.
int count = 0;
for (LeftTupleSinkNode sink = sinkPropagator.getFirstLeftTupleSink(); sink != null; sink = sink.getNextLeftTupleSinkNode()) {
if (sinkNotExclusivelyAssociatedWithTerminal(removingTN, sink)) {
count++;
if (count > 1) {
// There is more than one sink that is not for the removing rule
return true;
}
}
}
return false;
}
use of org.drools.core.reteoo.LeftTupleSinkNode in project drools by kiegroup.
the class SegmentUtilities method createSegmentMemory.
public static SegmentMemory createSegmentMemory(LeftTupleSource tupleSource, Memory mem, InternalWorkingMemory wm) {
// find segment root
while (!SegmentUtilities.isRootNode(tupleSource, null)) {
tupleSource = tupleSource.getLeftTupleSource();
}
LeftTupleSource segmentRoot = tupleSource;
int nodeTypesInSegment = 0;
SegmentMemory smem = restoreSegmentFromPrototype(wm, segmentRoot, nodeTypesInSegment);
if (smem != null) {
if (NodeTypeEnums.isBetaNode(segmentRoot) && ((BetaNode) segmentRoot).isRightInputIsRiaNode()) {
createRiaSegmentMemory((BetaNode) segmentRoot, wm);
}
return smem;
}
smem = new SegmentMemory(segmentRoot);
// Iterate all nodes on the same segment, assigning their position as a bit mask value
// allLinkedTestMask is the resulting mask used to test if all nodes are linked in
long nodePosMask = 1;
long allLinkedTestMask = 0;
// nodes after a branch CE can notify, but they cannot impact linking
boolean updateNodeBit = true;
while (true) {
nodeTypesInSegment = updateNodeTypesMask(tupleSource, nodeTypesInSegment);
if (NodeTypeEnums.isBetaNode(tupleSource)) {
allLinkedTestMask = processBetaNode((BetaNode) tupleSource, wm, smem, nodePosMask, allLinkedTestMask, updateNodeBit);
} else {
switch(tupleSource.getType()) {
case NodeTypeEnums.LeftInputAdapterNode:
allLinkedTestMask = processLiaNode((LeftInputAdapterNode) tupleSource, wm, smem, nodePosMask, allLinkedTestMask);
break;
case NodeTypeEnums.EvalConditionNode:
processEvalNode((EvalConditionNode) tupleSource, wm, smem);
break;
case NodeTypeEnums.ConditionalBranchNode:
updateNodeBit = processBranchNode((ConditionalBranchNode) tupleSource, wm, smem);
break;
case NodeTypeEnums.FromNode:
processFromNode((FromNode) tupleSource, wm, smem);
break;
case NodeTypeEnums.ReactiveFromNode:
processReactiveFromNode((MemoryFactory) tupleSource, wm, smem, nodePosMask);
break;
case NodeTypeEnums.TimerConditionNode:
processTimerNode((TimerNode) tupleSource, wm, smem, nodePosMask);
break;
case NodeTypeEnums.QueryElementNode:
updateNodeBit = processQueryNode((QueryElementNode) tupleSource, wm, segmentRoot, smem, nodePosMask);
break;
}
}
nodePosMask = nodePosMask << 1;
if (tupleSource.getSinkPropagator().size() == 1) {
LeftTupleSinkNode sink = tupleSource.getSinkPropagator().getFirstLeftTupleSink();
if (NodeTypeEnums.isLeftTupleSource(sink)) {
tupleSource = (LeftTupleSource) sink;
} else {
// rtn or rian
// While not technically in a segment, we want to be able to iterate easily from the last node memory to the ria/rtn memory
// we don't use createNodeMemory, as these may already have been created by, but not added, by the method updateRiaAndTerminalMemory
Memory memory = wm.getNodeMemory((MemoryFactory) sink);
if (sink.getType() == NodeTypeEnums.RightInputAdaterNode) {
PathMemory riaPmem = ((RiaNodeMemory) memory).getRiaPathMemory();
smem.getNodeMemories().add(riaPmem);
RightInputAdapterNode rian = (RightInputAdapterNode) sink;
ObjectSink[] nodes = rian.getObjectSinkPropagator().getSinks();
for (ObjectSink node : nodes) {
if (NodeTypeEnums.isLeftTupleSource(node)) {
createSegmentMemory((LeftTupleSource) node, wm);
}
}
} else if (NodeTypeEnums.isTerminalNode(sink)) {
smem.getNodeMemories().add(memory);
}
memory.setSegmentMemory(smem);
smem.setTipNode(sink);
break;
}
} else {
// not in same segment
smem.setTipNode(tupleSource);
break;
}
}
smem.setAllLinkedMaskTest(allLinkedTestMask);
// iterate to find root and determine the SegmentNodes position in the RuleSegment
LeftTupleSource pathRoot = segmentRoot;
int ruleSegmentPosMask = 1;
int counter = 0;
while (pathRoot.getType() != NodeTypeEnums.LeftInputAdapterNode) {
LeftTupleSource leftTupleSource = pathRoot.getLeftTupleSource();
if (SegmentUtilities.isNonTerminalTipNode(leftTupleSource, null)) {
// for each new found segment, increase the mask bit position
ruleSegmentPosMask = ruleSegmentPosMask << 1;
counter++;
}
pathRoot = leftTupleSource;
}
smem.setSegmentPosMaskBit(ruleSegmentPosMask);
smem.setPos(counter);
nodeTypesInSegment = updateRiaAndTerminalMemory(tupleSource, tupleSource, smem, wm, false, nodeTypesInSegment);
((KnowledgeBaseImpl) wm.getKnowledgeBase()).registerSegmentPrototype(segmentRoot, smem);
return smem;
}
use of org.drools.core.reteoo.LeftTupleSinkNode in project drools by kiegroup.
the class SegmentUtilities method createChildSegments.
public static void createChildSegments(final InternalWorkingMemory wm, SegmentMemory smem, LeftTupleSinkPropagator sinkProp) {
if (!smem.isEmpty()) {
// this can happen when multiple threads are trying to initialize the segment
return;
}
for (LeftTupleSinkNode sink = sinkProp.getFirstLeftTupleSink(); sink != null; sink = sink.getNextLeftTupleSinkNode()) {
SegmentMemory childSmem = createChildSegment(wm, sink);
childSmem.setPos(smem.getPos() + 1);
smem.add(childSmem);
}
}
use of org.drools.core.reteoo.LeftTupleSinkNode in project drools by kiegroup.
the class AddRemoveRule method visitChild.
private static void visitChild(LeftTuple lt, boolean insert, InternalWorkingMemory wm, Rule rule) {
LeftTuple prevLt = null;
LeftTupleSinkNode sink = lt.getTupleSink();
for (; sink != null; sink = sink.getNextLeftTupleSinkNode()) {
if (lt != null) {
if (lt.getTupleSink().isAssociatedWith(rule)) {
if (lt.getTupleSink().getAssociationsSize() > 1) {
if (lt.getFirstChild() != null) {
for (LeftTuple child = lt.getFirstChild(); child != null; child = child.getHandleNext()) {
visitChild(child, insert, wm, rule);
}
} else if (lt.getTupleSink().getType() == NodeTypeEnums.RightInputAdaterNode) {
insertPeerRightTuple(lt, wm, rule, insert);
}
} else if (!insert) {
iterateLeftTuple(lt, wm);
LeftTuple lt2 = null;
for (LeftTuple peerLt = lt.getPeer(); peerLt != null && peerLt.getTupleSink().isAssociatedWith(rule) && peerLt.getTupleSink().getAssociationsSize() == 1; peerLt = peerLt.getPeer()) {
iterateLeftTuple(peerLt, wm);
lt2 = peerLt;
}
// this sink is not shared and is associated with the rule being removed delete it's children
deleteLeftTuple(lt, lt2, prevLt);
// only one rule is deleted at a time, we know there are no more peers to delete so break.
break;
}
}
prevLt = lt;
lt = lt.getPeer();
} else {
// there is a sink without a peer LT, so create the peer LT
prevLt = insertPeerLeftTuple(prevLt, sink, wm);
}
}
}
Aggregations