public void doLeftUpdates( NotNode notNode, LeftTupleSink sink, BetaMemory bm, InternalWorkingMemory wm, LeftTupleSets srcLeftTuples, LeftTupleSets trgLeftTuples, LeftTupleSets stagedLeftTuples) { LeftTupleMemory ltm = bm.getLeftTupleMemory(); RightTupleMemory rtm = bm.getRightTupleMemory(); ContextEntry[] contextEntry = bm.getContext(); BetaConstraints constraints = notNode.getRawConstraints(); boolean leftUpdateOptimizationAllowed = notNode.isLeftUpdateOptimizationAllowed(); for (LeftTuple leftTuple = srcLeftTuples.getUpdateFirst(); leftTuple != null; ) { LeftTuple next = leftTuple.getStagedNext(); FastIterator rightIt = notNode.getRightIterator(rtm); RightTuple firstRightTuple = notNode.getFirstRightTuple(leftTuple, rtm, null, rightIt); // If in memory, remove it, because we'll need to add it anyway if it's not blocked, to ensure // iteration order RightTuple blocker = leftTuple.getBlocker(); if (blocker == null) { if (leftTuple.getMemory() != null) { // memory can be null, if blocker was deleted in same do loop ltm.remove(leftTuple); } } else { // check if we changed bucket if (rtm.isIndexed() && !rightIt.isFullIterator()) { // if newRightTuple is null, we assume there was a bucket change and that bucket is empty if (firstRightTuple == null || firstRightTuple.getMemory() != blocker.getMemory()) { blocker.removeBlocked(leftTuple); blocker = null; } } } constraints.updateFromTuple(contextEntry, wm, leftTuple); if (!leftUpdateOptimizationAllowed && blocker != null) { blocker.removeBlocked(leftTuple); blocker = null; } // if we where not blocked before (or changed buckets), or the previous blocker no longer // blocks, then find the next blocker if (blocker == null || !constraints.isAllowedCachedLeft(contextEntry, blocker.getFactHandle())) { if (blocker != null) { // remove previous blocker if it exists, as we know it doesn't block any more blocker.removeBlocked(leftTuple); } // find first blocker, because it's a modify, we need to start from the beginning again for (RightTuple newBlocker = firstRightTuple; newBlocker != null; newBlocker = (RightTuple) rightIt.next(newBlocker)) { if (constraints.isAllowedCachedLeft(contextEntry, newBlocker.getFactHandle())) { leftTuple.setBlocker(newBlocker); newBlocker.addBlocked(leftTuple); break; } } LeftTuple childLeftTuple = leftTuple.getFirstChild(); if (leftTuple.getBlocker() != null) { // blocked if (childLeftTuple != null) { // blocked, with previous children, so must have not been previously blocked, so retract // no need to remove, as we removed at the start // to be matched against, as it's now blocked childLeftTuple.setPropagationContext( leftTuple .getBlocker() .getPropagationContext()); // we have the righttuple, so use it for the pctx RuleNetworkEvaluator.deleteLeftChild(childLeftTuple, trgLeftTuples, stagedLeftTuples); } // else: it's blocked now and no children so blocked before, thus do nothing } else if (childLeftTuple == null) { // not blocked, with no children, must have been previously blocked so assert ltm.add(leftTuple); // add to memory so other fact handles can attempt to match trgLeftTuples.addInsert( sink.createLeftTuple( leftTuple, sink, leftTuple.getPropagationContext(), true)); // use leftTuple for the pctx here, as the right one is not available // this won't cause a problem, as the trigger tuple (to the left) will be more recent // anwyay } else { updateChildLeftTuple(childLeftTuple, stagedLeftTuples, trgLeftTuples); // not blocked, with children, so wasn't previous blocked and still isn't so modify ltm.add(leftTuple); // add to memory so other fact handles can attempt to match childLeftTuple.reAddLeft(); } } leftTuple.clearStaged(); leftTuple = next; } constraints.resetTuple(contextEntry); }