/** * Retract the <code>FactHandleImpl</code>. If the handle has any <code>ReteTuple</code> matches * and those tuples now have no other match, retract tuple * * @param handle the <codeFactHandleImpl</code> being retracted * @param context The <code>PropagationContext</code> * @param workingMemory The working memory session. */ public void retractRightTuple( final RightTuple rightTuple, final PropagationContext context, final InternalWorkingMemory workingMemory) { final BetaMemory memory = (BetaMemory) workingMemory.getNodeMemory(this); FastIterator it = memory.getRightTupleMemory().fastIterator(); final RightTuple rootBlocker = (RightTuple) it.next(rightTuple); memory.getRightTupleMemory().remove(rightTuple); if (rightTuple.getBlocked() == null) { return; } for (LeftTuple leftTuple = (LeftTuple) rightTuple.getBlocked(); leftTuple != null; ) { LeftTuple temp = leftTuple.getBlockedNext(); leftTuple.setBlocker(null); leftTuple.setBlockedPrevious(null); leftTuple.setBlockedNext(null); this.constraints.updateFromTuple(memory.getContext(), workingMemory, leftTuple); // we know that older tuples have been checked so continue previously for (RightTuple newBlocker = rootBlocker; newBlocker != null; newBlocker = (RightTuple) it.next(newBlocker)) { if (this.constraints.isAllowedCachedLeft(memory.getContext(), newBlocker.getFactHandle())) { leftTuple.setBlocker(newBlocker); newBlocker.addBlocked(leftTuple); break; } } if (leftTuple.getBlocker() == null) { // was previous blocked and not in memory, so add memory.getLeftTupleMemory().add(leftTuple); this.sink.propagateRetractLeftTuple(leftTuple, context, workingMemory); } leftTuple = temp; } rightTuple.nullBlocked(); this.constraints.resetTuple(memory.getContext()); }
/** Updates the given sink propagating all previously propagated tuples to it */ public void updateSink( final LeftTupleSink sink, final PropagationContext context, final InternalWorkingMemory workingMemory) { final BetaMemory memory = (BetaMemory) workingMemory.getNodeMemory(this); Iterator it = memory.getRightTupleMemory().iterator(); // Relies on the fact that any propagated LeftTuples are blocked, but due to lazy blocking // they will only be blocked once. So we can iterate the right memory to find the left tuples to // propagate for (RightTuple rightTuple = (RightTuple) it.next(); rightTuple != null; rightTuple = (RightTuple) it.next()) { LeftTuple leftTuple = rightTuple.getBlocked(); while (leftTuple != null) { sink.assertLeftTuple(sink.createLeftTuple(leftTuple, sink, true), context, workingMemory); leftTuple = leftTuple.getBlockedNext(); } } }
protected void doRemove( final RuleRemovalContext context, final ReteooBuilder builder, final BaseNode node, final InternalWorkingMemory[] workingMemories) { if (!node.isInUse()) { removeTupleSink((LeftTupleSink) node); } if (!this.isInUse() || context.getCleanupAdapter() != null) { for (InternalWorkingMemory workingMemory : workingMemories) { BetaMemory memory; Object object = workingMemory.getNodeMemory(this); // handle special cases for Accumulate to make sure they tidy up their specific data // like destroying the local FactHandles if (object instanceof AccumulateMemory) { memory = ((AccumulateMemory) object).betaMemory; } else { memory = (BetaMemory) object; } FastIterator it = memory.getLeftTupleMemory().fullFastIterator(); for (LeftTuple leftTuple = getFirstLeftTuple(memory.getLeftTupleMemory(), it); leftTuple != null; ) { LeftTuple tmp = (LeftTuple) it.next(leftTuple); if (context.getCleanupAdapter() != null) { LeftTuple child; while ((child = leftTuple.getFirstChild()) != null) { if (child.getLeftTupleSink() == this) { // this is a match tuple on collect and accumulate nodes, so just unlink it child.unlinkFromLeftParent(); child.unlinkFromRightParent(); } else { // the cleanupAdapter will take care of the unlinking context.getCleanupAdapter().cleanUp(child, workingMemory); } } } memory.getLeftTupleMemory().remove(leftTuple); leftTuple.unlinkFromLeftParent(); leftTuple.unlinkFromRightParent(); leftTuple = tmp; } // handle special cases for Accumulate to make sure they tidy up their specific data // like destroying the local FactHandles if (object instanceof AccumulateMemory) { ((AccumulateNode) this).doRemove(workingMemory, (AccumulateMemory) object); } if (!this.isInUse()) { it = memory.getRightTupleMemory().fullFastIterator(); for (RightTuple rightTuple = getFirstRightTuple(memory.getRightTupleMemory(), it); rightTuple != null; ) { RightTuple tmp = (RightTuple) it.next(rightTuple); if (rightTuple.getBlocked() != null) { // special case for a not, so unlink left tuple from here, as they aren't in the left // memory for (LeftTuple leftTuple = rightTuple.getBlocked(); leftTuple != null; ) { LeftTuple temp = leftTuple.getBlockedNext(); leftTuple.setBlocker(null); leftTuple.setBlockedPrevious(null); leftTuple.setBlockedNext(null); leftTuple.unlinkFromLeftParent(); leftTuple = temp; } } memory.getRightTupleMemory().remove(rightTuple); rightTuple.unlinkFromRightParent(); rightTuple = tmp; } workingMemory.clearNodeMemory(this); } } context.setCleanupAdapter(null); } this.rightInput.remove(context, builder, this, workingMemories); this.leftInput.remove(context, builder, this, workingMemories); }
public void modifyRightTuple( RightTuple rightTuple, PropagationContext context, InternalWorkingMemory workingMemory) { final BetaMemory memory = (BetaMemory) workingMemory.getNodeMemory(this); if (memory.getLeftTupleMemory() == null || (memory.getLeftTupleMemory().size() == 0 && rightTuple.getBlocked() == null)) { // do nothing here, as we know there are no left tuples // normally do this at the end, but as we are exiting early, make sure the buckets are still // correct. memory.getRightTupleMemory().removeAdd(rightTuple); return; } // TODO: wtd with behaviours? // if ( !behavior.assertRightTuple( memory.getBehaviorContext(), // rightTuple, // workingMemory ) ) { // // destroy right tuple // rightTuple.unlinkFromRightParent(); // return; // } this.constraints.updateFromFactHandle( memory.getContext(), workingMemory, rightTuple.getFactHandle()); LeftTupleMemory leftMemory = memory.getLeftTupleMemory(); FastIterator leftIt = getLeftIterator(leftMemory); LeftTuple firstLeftTuple = getFirstLeftTuple(rightTuple, leftMemory, context, leftIt); LeftTuple firstBlocked = rightTuple.getBlocked(); // we now have reference to the first Blocked, so null it in the rightTuple itself, so we can // rebuild rightTuple.nullBlocked(); // first process non-blocked tuples, as we know only those ones are in the left memory. for (LeftTuple leftTuple = firstLeftTuple; leftTuple != null; ) { // preserve next now, in case we remove this leftTuple LeftTuple temp = (LeftTuple) leftIt.next(leftTuple); // we know that only unblocked LeftTuples are still in the memory if (this.constraints.isAllowedCachedRight(memory.getContext(), leftTuple)) { leftTuple.setBlocker(rightTuple); rightTuple.addBlocked(leftTuple); // this is now blocked so remove from memory leftMemory.remove(leftTuple); // subclasses like ForallNotNode might override this propagation this.sink.propagateAssertLeftTuple(leftTuple, context, workingMemory, true); } leftTuple = temp; } if (firstBlocked != null) { // now process existing blocks, we only process existing and not new from above loop FastIterator rightIt = getRightIterator(memory.getRightTupleMemory()); RightTuple rootBlocker = (RightTuple) rightIt.next(rightTuple); RightTupleList list = rightTuple.getMemory(); // we must do this after we have the next in memory // We add to the end to give an opportunity to re-match if in same bucket memory.getRightTupleMemory().removeAdd(rightTuple); if (rootBlocker == null && list == rightTuple.getMemory()) { // we are at the end of the list, but still in same bucket, so set to self, to give self a // chance to rematch rootBlocker = rightTuple; } // iterate all the existing previous blocked LeftTuples for (LeftTuple leftTuple = (LeftTuple) firstBlocked; leftTuple != null; ) { LeftTuple temp = leftTuple.getBlockedNext(); leftTuple.setBlockedPrevious(null); // must null these as we are re-adding them to the list leftTuple.setBlockedNext(null); leftTuple.setBlocker(null); this.constraints.updateFromTuple(memory.getContext(), workingMemory, leftTuple); // we know that older tuples have been checked so continue next for (RightTuple newBlocker = rootBlocker; newBlocker != null; newBlocker = (RightTuple) rightIt.next(newBlocker)) { if (this.constraints.isAllowedCachedLeft( memory.getContext(), newBlocker.getFactHandle())) { leftTuple.setBlocker(newBlocker); newBlocker.addBlocked(leftTuple); break; } } if (leftTuple.getBlocker() == null) { // was previous blocked and not in memory, so add memory.getLeftTupleMemory().add(leftTuple); // subclasses like ForallNotNode might override this propagation this.sink.propagateRetractLeftTuple(leftTuple, context, workingMemory); } leftTuple = temp; } } else { // we had to do this at the end, rather than beginning as this 'if' block needs the next // memory tuple memory.getRightTupleMemory().removeAdd(rightTuple); } this.constraints.resetFactHandle(memory.getContext()); this.constraints.resetTuple(memory.getContext()); }