@SuppressWarnings("unchecked") public RightTuple createRightTuple( final LeftTuple leftTuple, final PropagationContext context, final InternalWorkingMemory workingMemory, final Object object) { InternalFactHandle handle; ProtobufMessages.FactHandle _handle = null; if (objectTypeConf == null) { // use default entry point and object class. Notice that at this point object is assignable to // resultClass objectTypeConf = new ClassObjectTypeConf( workingMemory.getEntryPoint(), resultClass, workingMemory.getKnowledgeBase()); } if (context.getReaderContext() != null) { Map<ProtobufInputMarshaller.TupleKey, List<FactHandle>> map = (Map<ProtobufInputMarshaller.TupleKey, List<ProtobufMessages.FactHandle>>) context.getReaderContext().nodeMemories.get(getId()); if (map != null) { TupleKey key = PersisterHelper.createTupleKey(leftTuple); List<FactHandle> list = map.get(key); if (list != null && !list.isEmpty()) { // it is a linked list, so the operation is fairly efficient _handle = ((java.util.LinkedList<ProtobufMessages.FactHandle>) list).removeFirst(); if (list.isEmpty()) { map.remove(key); } } } } if (_handle != null) { // create a handle with the given id handle = workingMemory .getFactHandleFactory() .newFactHandle( _handle.getId(), object, _handle.getRecency(), objectTypeConf, workingMemory, null); } else { handle = workingMemory .getFactHandleFactory() .newFactHandle(object, objectTypeConf, workingMemory, null); } return newRightTuple(handle, null); }
public void execute(InternalWorkingMemory workingMemory) { final PropagationContext context = new PropagationContextImpl( workingMemory.getNextPropagationIdCounter(), PropagationContext.INSERTION, this.ruleOrigin, this.leftTuple, this.factHandle); ReteooRuleBase ruleBase = (ReteooRuleBase) workingMemory.getRuleBase(); ruleBase.assertObject(this.factHandle, this.factHandle.getObject(), context, workingMemory); context.evaluateActionQueue(workingMemory); }
public void closeLiveQuery(final InternalFactHandle factHandle) { try { startOperation(); this.ruleBase.readLock(); this.lock.lock(); final PropagationContext pCtx = new PropagationContextImpl( getNextPropagationIdCounter(), PropagationContext.INSERTION, null, null, factHandle, getEntryPoint()); if (this.ruleBase.getConfiguration().isPhreakEnabled()) { LeftInputAdapterNode lian = (LeftInputAdapterNode) factHandle.getFirstLeftTuple().getLeftTupleSink().getLeftTupleSource(); LiaNodeMemory lmem = (LiaNodeMemory) getNodeMemory((MemoryFactory) lian); SegmentMemory lsmem = lmem.getSegmentMemory(); LeftTuple childLeftTuple = factHandle.getFirstLeftTuple(); // there is only one, all other LTs are peers LeftInputAdapterNode.doDeleteObject( childLeftTuple, childLeftTuple.getPropagationContext(), lsmem, this, lian, false, lmem); List<PathMemory> rmems = lmem.getSegmentMemory().getPathMemories(); for (int i = 0, length = rmems.size(); i < length; i++) { PathMemory rm = rmems.get(i); RuleNetworkEvaluatorActivation evaluator = agenda.createRuleNetworkEvaluatorActivation( Integer.MAX_VALUE, rm, (TerminalNode) rm.getNetworkNode()); evaluator.evaluateNetwork(this, 0, -1); } } else { getEntryPointNode().retractQuery(factHandle, pCtx, this); pCtx.evaluateActionQueue(this); } getFactHandleFactory().destroyFactHandle(factHandle); } finally { this.lock.unlock(); this.ruleBase.readUnlock(); endOperation(); } }
/** * Assert a new <code>ReteTuple</code> from the left input. It iterates over the right <code> * FactHandleImpl</code>'s and if any match is found, a copy of the <code>ReteTuple</code> is made * and propagated. * * @param tuple The <code>Tuple</code> being asserted. * @param context The <code>PropagationContext</code> * @param workingMemory The working memory session. */ public void assertLeftTuple( final LeftTuple leftTuple, final PropagationContext context, final InternalWorkingMemory workingMemory) { final BetaMemory memory = (BetaMemory) workingMemory.getNodeMemory(this); RightTupleMemory rightMemory = memory.getRightTupleMemory(); ContextEntry[] contextEntry = memory.getContext(); boolean useLeftMemory = true; if (!this.tupleMemoryEnabled) { // This is a hack, to not add closed DroolsQuery objects Object object = ((InternalFactHandle) context.getFactHandle()).getObject(); if (!(object instanceof DroolsQuery) || !((DroolsQuery) object).isOpen()) { useLeftMemory = false; } } this.constraints.updateFromTuple(contextEntry, workingMemory, leftTuple); FastIterator it = getRightIterator(rightMemory); for (RightTuple rightTuple = getFirstRightTuple( leftTuple, rightMemory, (InternalFactHandle) context.getFactHandle(), it); rightTuple != null; rightTuple = (RightTuple) it.next(rightTuple)) { if (this.constraints.isAllowedCachedLeft(contextEntry, rightTuple.getFactHandle())) { leftTuple.setBlocker(rightTuple); if (useLeftMemory) { rightTuple.addBlocked(leftTuple); } break; } } this.constraints.resetTuple(contextEntry); if (leftTuple.getBlocker() != null) { // tuple is not blocked to propagate this.sink.propagateAssertLeftTuple(leftTuple, context, workingMemory, useLeftMemory); } else if (useLeftMemory) { // LeftTuple is not blocked, so add to memory so other RightTuples can match memory.getLeftTupleMemory().add(leftTuple); } }
public void retractRightTuple( final RightTuple rightTuple, final PropagationContext pctx, final InternalWorkingMemory workingMemory) { final BetaMemory memory = (BetaMemory) workingMemory.getNodeMemory(this); rightTuple.setPropagationContext(pctx); RightTupleSets stagedRightTuples = memory.getStagedRightTuples(); boolean stagedDeleteWasEmpty = false; if (streamMode) { stagedDeleteWasEmpty = memory.getSegmentMemory().getTupleQueue().isEmpty(); memory .getSegmentMemory() .getTupleQueue() .add(new RightTupleEntry(rightTuple, pctx, memory, pctx.getType())); // log.trace( "NotNode delete queue={} size={} lt={}", System.identityHashCode( // memory.getSegmentMemory().getTupleQueue() ), // memory.getSegmentMemory().getTupleQueue().size(), rightTuple ); } else { stagedDeleteWasEmpty = stagedRightTuples.addDelete(rightTuple); } if (memory.getAndDecCounter() == 1 && isEmptyBetaConstraints()) { // NotNodes can only be unlinked, if they have no variable constraints memory.linkNode(workingMemory); } else if (stagedDeleteWasEmpty) { // nothing staged before, notify rule, so it can evaluate network memory.setNodeDirty(workingMemory); } }
public void assertObject( final InternalFactHandle factHandle, final PropagationContext pctx, final InternalWorkingMemory wm) { final BetaMemory memory = (BetaMemory) getBetaMemoryFromRightInput(this, wm); RightTuple rightTuple = createRightTuple(factHandle, this, pctx); rightTuple.setPropagationContext(pctx); // strangely we link here, this is actually just to force a network evaluation // The assert is then processed and the rule unlinks then. // This is because we need the first RightTuple to link with it's blocked boolean stagedInsertWasEmpty = false; if (streamMode) { stagedInsertWasEmpty = memory.getSegmentMemory().getTupleQueue().isEmpty(); memory .getSegmentMemory() .getTupleQueue() .add(new RightTupleEntry(rightTuple, pctx, memory, pctx.getType())); // log.trace( "NotNode insert queue={} size={} lt={}", System.identityHashCode( // memory.getSegmentMemory().getTupleQueue() ), // memory.getSegmentMemory().getTupleQueue().size(), rightTuple ); } else { stagedInsertWasEmpty = memory.getStagedRightTuples().addInsert(rightTuple); } if (memory.getAndIncCounter() == 0 && isEmptyBetaConstraints()) { // NotNodes can only be unlinked, if they have no variable constraints memory.linkNode(wm); } else if (stagedInsertWasEmpty) { // nothing staged before, notify rule, so it can evaluate network memory.setNodeDirty(wm); } }
@SuppressWarnings("unchecked") public InternalFactHandle createFactHandle( final LeftTuple leftTuple, final PropagationContext context, final InternalWorkingMemory workingMemory) { InternalFactHandle handle; ProtobufMessages.FactHandle _handle = null; if (context.getReaderContext() != null) { Map<ProtobufInputMarshaller.TupleKey, ProtobufMessages.FactHandle> map = (Map<ProtobufInputMarshaller.TupleKey, ProtobufMessages.FactHandle>) context.getReaderContext().nodeMemories.get(getId()); if (map != null) { _handle = map.get(PersisterHelper.createTupleKey(leftTuple)); } } if (_handle != null) { // create a handle with the given id handle = workingMemory .getFactHandleFactory() .newFactHandle( _handle.getId(), leftTuple, _handle.getRecency(), workingMemory .getObjectTypeConfigurationRegistry() .getObjectTypeConf(context.getEntryPoint(), leftTuple), workingMemory, null); // so far, result is not an event } else { handle = workingMemory .getFactHandleFactory() .newFactHandle( leftTuple, workingMemory .getObjectTypeConfigurationRegistry() .getObjectTypeConf(context.getEntryPoint(), leftTuple), workingMemory, null); // so far, result is not an event } return handle; }
private static void removeQueuedTupleEntry(TupleEntryQueue tupleQueue) { TupleEntry tupleEntry = tupleQueue.remove(); PropagationContext originalPctx = tupleEntry.getPropagationContext(); while (true) { processStreamTupleEntry(tupleQueue, tupleEntry); if (tupleQueue.isEmpty()) { return; } tupleEntry = tupleQueue.peek(); PropagationContext pctx = tupleEntry.getPropagationContext(); // repeat if either the pctx number is the same, or the event time is the same or before if (pctx.getPropagationNumber() != originalPctx.getPropagationNumber()) { break; } tupleEntry = tupleQueue.remove(); } }
public void cancelActivation( final LeftTuple leftTuple, final PropagationContext context, final InternalWorkingMemory workingMemory, final Activation activation, final TerminalNode rtn) { AgendaItem item = (AgendaItem) activation; item.removeAllBlockersAndBlocked(this); if (isDeclarativeAgenda() && activation.getFactHandle() == null) { // This a control rule activation, nothing to do except update counters. As control rules are // not in agenda-groups etc. return; } else { // we are retracting an actual Activation, so also remove it and it's handle from the WM. removeActivation(item); } if (activation.isQueued()) { // on fact expiration, we don't remove the activation, but let it fire if (context.getType() == PropagationContext.EXPIRATION && context.getFactHandleOrigin() != null) { } else { activation.remove(); if (activation.getActivationGroupNode() != null) { activation.getActivationGroupNode().getActivationGroup().removeActivation(activation); } leftTuple.decreaseActivationCountForEvents(); ((EventSupport) workingMemory) .getAgendaEventSupport() .fireActivationCancelled(activation, workingMemory, MatchCancelledCause.WME_MODIFY); } } if (item.getActivationUnMatchListener() != null) { item.getActivationUnMatchListener().unMatch(workingMemory.getKnowledgeRuntime(), item); } TruthMaintenanceSystemHelper.removeLogicalDependencies(activation, context, rtn.getRule()); }
/** * This is the entry point into the network for all asserted Facts. Iterates a cache of matching * <code>ObjectTypdeNode</code>s asserting the Fact. If the cache does not exist it first iteraes * and builds the cache. * * @param factHandle The FactHandle of the fact to assert * @param context The <code>PropagationContext</code> of the <code>WorkingMemory</code> action * @param workingMemory The working memory session. */ public void assertObject( final InternalFactHandle factHandle, final PropagationContext context, final InternalWorkingMemory workingMemory) { EntryPointId entryPoint = context.getEntryPoint(); EntryPointNode node = this.entryPoints.get(entryPoint); ObjectTypeConf typeConf = ((InternalWorkingMemoryEntryPoint) workingMemory.getWorkingMemoryEntryPoint(entryPoint.getEntryPointId())) .getObjectTypeConfigurationRegistry() .getObjectTypeConf(entryPoint, factHandle.getObject()); node.assertObject(factHandle, context, typeConf, workingMemory); }
public static void doModifyLeftTuple( InternalFactHandle factHandle, ModifyPreviousTuples modifyPreviousTuples, PropagationContext context, InternalWorkingMemory workingMemory, LeftTupleSink sink, ObjectTypeNode.Id leftInputOtnId, BitMask leftInferredMask) { LeftTuple leftTuple = modifyPreviousTuples.peekLeftTuple(); while (leftTuple != null && leftTuple.getLeftTupleSink().getLeftInputOtnId() != null && leftTuple.getLeftTupleSink().getLeftInputOtnId().before(leftInputOtnId)) { modifyPreviousTuples.removeLeftTuple(); // we skipped this node, due to alpha hashing, so retract now ((LeftInputAdapterNode) leftTuple.getLeftTupleSink().getLeftTupleSource()) .retractLeftTuple(leftTuple, context, workingMemory); leftTuple = modifyPreviousTuples.peekLeftTuple(); } if (leftTuple != null && leftTuple.getLeftTupleSink().getLeftInputOtnId() != null && leftTuple.getLeftTupleSink().getLeftInputOtnId().equals(leftInputOtnId)) { modifyPreviousTuples.removeLeftTuple(); leftTuple.reAdd(); if (context.getModificationMask().intersects(leftInferredMask)) { // LeftTuple previously existed, so continue as modify, unless it's currently staged sink.modifyLeftTuple(leftTuple, context, workingMemory); } } else { if (context.getModificationMask().intersects(leftInferredMask)) { // LeftTuple does not exist, so create and continue as assert LeftTuple newLeftTuple = sink.createLeftTuple(factHandle, sink, true); sink.assertLeftTuple(newLeftTuple, context, workingMemory); } } }
public void execute(InternalWorkingMemory workingMemory) { if (this.factHandle.isValid()) { // if the fact is still in the working memory (since it may have been previously retracted // already final PropagationContext context = new PropagationContextImpl( workingMemory.getNextPropagationIdCounter(), PropagationContext.EXPIRATION, null, null, this.factHandle); ((EventFactHandle) factHandle).setExpired(true); this.node.retractObject(factHandle, context, workingMemory); context.evaluateActionQueue(workingMemory); // if no activations for this expired event if (((EventFactHandle) factHandle).getActivationsCount() == 0) { // remove it from the object store and clean up resources ((EventFactHandle) factHandle).getEntryPoint().retract(factHandle); } context.evaluateActionQueue(workingMemory); } }
public void execute(InternalWorkingMemory workingMemory) { leftTuple.setLeftTupleSink(this.node); if (leftTuple.getFirstChild() == null) { this.node.assertLeftTuple(leftTuple, context, workingMemory); } else { if (retract) { this.node .getSinkPropagator() .propagateRetractLeftTuple(leftTuple, context, workingMemory); } else { this.node .getSinkPropagator() .propagateModifyChildLeftTuple(leftTuple, context, workingMemory, true); } } if (leftTuple.getLeftParent() == null) { // It's not an open query, as we aren't recording parent chains, so we need to clear out // right memory Object node = workingMemory.getNodeMemory(this.node); RightTupleMemory rightMemory = null; if (node instanceof BetaMemory) { rightMemory = ((BetaMemory) node).getRightTupleMemory(); } else if (node instanceof AccumulateMemory) { rightMemory = ((AccumulateMemory) node).betaMemory.getRightTupleMemory(); } final TupleStartEqualsConstraint constraint = TupleStartEqualsConstraint.getInstance(); TupleStartEqualsConstraintContextEntry contextEntry = new TupleStartEqualsConstraintContextEntry(); contextEntry.updateFromTuple(workingMemory, leftTuple); FastIterator rightIt = rightMemory.fastIterator(); RightTuple temp = null; for (RightTuple rightTuple = rightMemory.getFirst( leftTuple, (InternalFactHandle) context.getFactHandle(), rightIt); rightTuple != null; ) { temp = (RightTuple) rightIt.next(rightTuple); if (constraint.isAllowedCachedLeft(contextEntry, rightTuple.getFactHandle())) { rightMemory.remove(rightTuple); } rightTuple = temp; } } }
private BaseNode[] evalQuery( String queryName, DroolsQuery queryObject, InternalFactHandle handle, PropagationContext pCtx) { BaseNode[] tnodes = (BaseNode[]) ruleBase.getReteooBuilder().getTerminalNodes(queryName); if (this.ruleBase.getConfiguration().isPhreakEnabled()) { if (tnodes == null) { throw new RuntimeException("Query '" + queryName + "' does not exist"); } QueryTerminalNode tnode = (QueryTerminalNode) tnodes[0]; LeftTupleSource lts = tnode.getLeftTupleSource(); while (lts.getType() != NodeTypeEnums.LeftInputAdapterNode) { lts = lts.getLeftTupleSource(); } LeftInputAdapterNode lian = (LeftInputAdapterNode) lts; LiaNodeMemory lmem = (LiaNodeMemory) getNodeMemory((MemoryFactory) lts); SegmentMemory lsmem = lmem.getSegmentMemory(); if (lsmem == null) { lsmem = SegmentUtilities.createSegmentMemory(lts, this); } LeftInputAdapterNode.doInsertObject( handle, pCtx, lian, this, lmem, false, queryObject.isOpen()); List<PathMemory> rmems = lmem.getSegmentMemory().getPathMemories(); for (int i = 0, length = rmems.size(); i < length; i++) { PathMemory rm = rmems.get(i); RuleNetworkEvaluatorActivation evaluator = agenda.createRuleNetworkEvaluatorActivation( Integer.MAX_VALUE, rm, (TerminalNode) rm.getNetworkNode()); evaluator.evaluateNetwork(this, 0, -1); } } else { // no need to call retract, as no leftmemory used. getEntryPointNode().assertQuery(handle, pCtx, this); pCtx.evaluateActionQueue(this); } return tnodes; }
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; } RightTupleMemory rightTupleMemory = memory.getRightTupleMemory(); if (firstBlocked != null) { boolean useComparisonIndex = rightTupleMemory.getIndexType().isComparison(); // now process existing blocks, we only process existing and not new from above loop FastIterator rightIt = getRightIterator(rightTupleMemory); RightTuple rootBlocker = useComparisonIndex ? null : (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 rightTupleMemory.removeAdd(rightTuple); if (!useComparisonIndex && 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); if (useComparisonIndex) { rootBlocker = getFirstRightTuple( leftTuple, rightTupleMemory, (InternalFactHandle) context.getFactHandle(), rightIt); } // 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 rightTupleMemory.removeAdd(rightTuple); } this.constraints.resetFactHandle(memory.getContext()); this.constraints.resetTuple(memory.getContext()); }
public void modifyLeftTuple( LeftTuple leftTuple, PropagationContext context, InternalWorkingMemory workingMemory) { final BetaMemory memory = (BetaMemory) workingMemory.getNodeMemory(this); RightTupleMemory rightMemory = memory.getRightTupleMemory(); FastIterator rightIt = getRightIterator(rightMemory); RightTuple firstRightTuple = getFirstRightTuple( leftTuple, rightMemory, (InternalFactHandle) context.getFactHandle(), 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) { memory.getLeftTupleMemory().remove(leftTuple); } else { // check if we changed bucket if (rightMemory.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()) { // we changed bucket, so blocker no longer blocks blocker.removeBlocked(leftTuple); blocker = null; } } } this.constraints.updateFromTuple(memory.getContext(), workingMemory, leftTuple); // if we where not blocked before (or changed buckets), or the previous blocker no longer // blocks, then find the next blocker if (blocker == null || !this.constraints.isAllowedCachedLeft(memory.getContext(), blocker.getFactHandle())) { if (blocker != null) { // remove previous blocker if it exists, as we know it doesn't block any more blocker.removeBlocked(leftTuple); } FastIterator it = memory.getRightTupleMemory().fastIterator(); // 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 (this.constraints.isAllowedCachedLeft(memory.getContext(), newBlocker.getFactHandle())) { leftTuple.setBlocker(newBlocker); newBlocker.addBlocked(leftTuple); break; } } } if (leftTuple.getBlocker() == null) { // not blocked memory .getLeftTupleMemory() .add(leftTuple); // add to memory so other fact handles can attempt to match if (leftTuple.getFirstChild() != null) { // with previous children, retract this.sink.propagateRetractLeftTuple(leftTuple, context, workingMemory); } // with no previous children. do nothing. } else if (leftTuple.getFirstChild() == null) { // blocked, with no previous children, assert this.sink.propagateAssertLeftTuple(leftTuple, context, workingMemory, true); } else { // blocked, with previous children, modify this.sink.propagateModifyChildLeftTuple(leftTuple, context, workingMemory, true); } this.constraints.resetTuple(memory.getContext()); }
/** * 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); if (isUnlinkingEnabled()) { doDeleteRightTuple(rightTuple, workingMemory, memory); return; } RightTupleMemory rightTupleMemory = memory.getRightTupleMemory(); boolean useComparisonIndex = rightTupleMemory.getIndexType().isComparison(); FastIterator rightIt = rightTupleMemory.fastIterator(); RightTuple rootBlocker = useComparisonIndex ? null : (RightTuple) rightIt.next(rightTuple); rightTupleMemory.remove(rightTuple); rightTuple.setMemory(null); 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); if (useComparisonIndex) { rootBlocker = getFirstRightTuple( leftTuple, rightTupleMemory, (InternalFactHandle) context.getFactHandle(), rightIt); } // we know that older tuples have been checked so continue previously 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); this.sink.propagateRetractLeftTuple(leftTuple, context, workingMemory); } leftTuple = temp; } rightTuple.nullBlocked(); this.constraints.resetTuple(memory.getContext()); }