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 = (InternalWorkingMemory) buildContext.getRuleBase().newStatefulSession(true); 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); }
/** * When L&R Unlinking is enabled, updateSink() is used to populate a node's memory, but it has to * take into account if it's propagating. */ private void updateLRUnlinking( final ObjectSink sink, final PropagationContext context, final InternalWorkingMemory workingMemory) { final ObjectHashSet memory = (ObjectHashSet) workingMemory.getNodeMemory(this); Iterator it = memory.iterator(); InternalFactHandle ctxHandle = (InternalFactHandle) context.getFactHandle(); if (!context.isPropagating(this) || (context.isPropagating(this) && context.shouldPropagateAll())) { for (ObjectEntry entry = (ObjectEntry) it.next(); entry != null; entry = (ObjectEntry) it.next()) { // Assert everything sink.assertObject((InternalFactHandle) entry.getValue(), context, workingMemory); } } else { for (ObjectEntry entry = (ObjectEntry) it.next(); entry != null; entry = (ObjectEntry) it.next()) { InternalFactHandle handle = (InternalFactHandle) entry.getValue(); // Exclude the current fact propagation if (handle.getId() != ctxHandle.getId()) { sink.assertObject(handle, context, workingMemory); } } } }
/** * Takes the asserted <code>ReteTuple</code> received from the <code>TupleSource</code> and * adapts it into a FactHandleImpl * * @param tuple * The asserted <code>ReteTuple</code>. * @param context * The <code>PropagationContext</code> of the <code>WorkingMemory<code> action. * @param workingMemory * the <code>WorkingMemory</code> session. */ public void assertLeftTuple( final LeftTuple leftTuple, final PropagationContext context, final InternalWorkingMemory workingMemory) { // creating a dummy fact handle to wrap the tuple final InternalFactHandle handle = workingMemory .getFactHandleFactory() .newFactHandle( leftTuple, workingMemory .getObjectTypeConfigurationRegistry() .getObjectTypeConf(context.getEntryPoint(), leftTuple), workingMemory, null); boolean useLeftMemory = true; if (!this.tupleMemoryEnabled) { // This is a hack, to not add closed DroolsQuery objects Object object = ((InternalFactHandle) leftTuple.get(0)).getObject(); if (!(object instanceof DroolsQuery) || !((DroolsQuery) object).isOpen()) { useLeftMemory = false; } } if (useLeftMemory) { final ObjectHashMap memory = (ObjectHashMap) workingMemory.getNodeMemory(this); // add it to a memory mapping memory.put(leftTuple, handle); } // propagate it this.sink.propagateAssertObject(handle, context, workingMemory); }
/** * @inheritDoc As the accumulate node will always generate a resulting tuple, we must always * destroy it */ public void retractLeftTuple( final LeftTuple leftTuple, final PropagationContext context, final InternalWorkingMemory workingMemory) { final AccumulateMemory memory = (AccumulateMemory) workingMemory.getNodeMemory(this); if (leftTuple.getMemory().isStagingMemory()) { leftTuple.getMemory().remove(leftTuple); } else { ((BetaMemory) memory.getBetaMemory()).getLeftTupleMemory().remove(leftTuple); } leftTuple.setMemory(null); final AccumulateContext accctx = (AccumulateContext) leftTuple.getObject(); if (accctx.getAction() != null) { // there is a scheduled activation, we must cancel it context.removeInsertAction(accctx.getAction()); } leftTuple.setObject(null); removePreviousMatchesForLeftTuple(leftTuple, workingMemory, memory, accctx); if (accctx.propagated) { // if tuple was previously propagated, retract it and destroy result fact handle this.sink.propagateRetractLeftTupleDestroyRightTuple(leftTuple, context, workingMemory); } else { // if not propagated, just destroy the result fact handle // workingMemory.getFactHandleFactory().destroyFactHandle( accctx.result.getFactHandle() ); } }
/** * Propagate the <code>FactHandleimpl</code> through the <code>Rete</code> network. All <code> * FactHandleImpl</code> should be remembered in the node memory, so that later runtime rule * attachmnents can have the matched facts propagated to them. * * @param factHandle The fact handle. * @param object The object to assert. * @param workingMemory The working memory session. */ public void assertObject( final InternalFactHandle factHandle, final PropagationContext context, final InternalWorkingMemory workingMemory) { if (objectMemoryEnabled && !(queryNode && !((DroolsQuery) factHandle.getObject()).isOpen())) { final ObjectHashSet memory = (ObjectHashSet) workingMemory.getNodeMemory(this); memory.add(factHandle, false); } if (compiledNetwork != null) { compiledNetwork.assertObject(factHandle, context, workingMemory); } else { context.setCurrentPropagatingOTN(this); this.sink.propagateAssertObject(factHandle, context, workingMemory); } if (this.objectType.isEvent() && this.expirationOffset >= 0 && this.expirationOffset != Long.MAX_VALUE) { // schedule expiration WorkingMemoryReteExpireAction expire = new WorkingMemoryReteExpireAction(factHandle, this); TimerService clock = workingMemory.getTimerService(); long nextTimestamp = Math.max( clock.getCurrentTime() + this.expirationOffset, ((EventFactHandle) factHandle).getStartTimestamp() + this.expirationOffset); JobContext jobctx = new ExpireJobContext(expire, workingMemory); JobHandle handle = clock.scheduleJob(job, jobctx, new PointInTimeTrigger(nextTimestamp, null, null)); jobctx.setJobHandle(handle); } }
/** * Propagate the <code>FactHandleimpl</code> through the <code>Rete</code> network. All <code> * FactHandleImpl</code> should be remembered in the node memory, so that later runtime rule * attachmnents can have the matched facts propagated to them. * * @param factHandle The fact handle. * @param object The object to assert. * @param workingMemory The working memory session. */ public void assertObject( final InternalFactHandle factHandle, final PropagationContext context, final InternalWorkingMemory workingMemory) { if (context.getType() == PropagationContext.MODIFICATION && this.skipOnModify && context.getDormantActivations() == 0) { // we do this after the shadowproxy update, just so that its up to date for the future return; } if (this.objectMemoryEnabled) { final ObjectHashSet memory = (ObjectHashSet) workingMemory.getNodeMemory(this); memory.add(factHandle, false); } this.sink.propagateAssertObject(factHandle, context, workingMemory); if (this.expirationOffset >= 0) { // schedule expiration WorkingMemoryReteExpireAction expire = new WorkingMemoryReteExpireAction(factHandle, this); TimerService clock = workingMemory.getTimerService(); long nextTimestamp = clock.getCurrentTime() + this.expirationOffset; JobContext jobctx = new ExpireJobContext(expire, workingMemory); JobHandle handle = clock.scheduleJob(job, jobctx, new PointInTimeTrigger(nextTimestamp)); jobctx.setJobHandle(handle); } }
/** * Retract the <code>FactHandleimpl</code> from the <code>Rete</code> network. Also remove the * <code>FactHandleImpl</code> from the node memory. * * @param rightTuple The fact handle. * @param object The object to assert. * @param workingMemory The working memory session. */ public void retractObject( final InternalFactHandle factHandle, final PropagationContext context, final InternalWorkingMemory workingMemory) { if (context.getType() == PropagationContext.MODIFICATION && this.skipOnModify && context.getDormantActivations() == 0) { return; } if (this.objectMemoryEnabled) { final ObjectHashSet memory = (ObjectHashSet) workingMemory.getNodeMemory(this); memory.remove(factHandle); } for (RightTuple rightTuple = factHandle.getRightTuple(); rightTuple != null; rightTuple = (RightTuple) rightTuple.getHandleNext()) { rightTuple.getRightTupleSink().retractRightTuple(rightTuple, context, workingMemory); } factHandle.setRightTuple(null); for (LeftTuple leftTuple = factHandle.getLeftTuple(); leftTuple != null; leftTuple = (LeftTuple) leftTuple.getLeftParentNext()) { leftTuple.getLeftTupleSink().retractLeftTuple(leftTuple, context, workingMemory); } factHandle.setLeftTuple(null); }
protected void doRemove( final RuleRemovalContext context, final ReteooBuilder builder, final BaseNode node, final InternalWorkingMemory[] workingMemories) { if (!node.isInUse()) { removeObjectSink((ObjectSink) node); } if (!this.isInUse()) { for (InternalWorkingMemory workingMemory : workingMemories) { ObjectHashMap memory = (ObjectHashMap) workingMemory.getNodeMemory(this); Iterator it = memory.iterator(); for (ObjectEntry entry = (ObjectEntry) it.next(); entry != null; entry = (ObjectEntry) it.next()) { LeftTuple leftTuple = (LeftTuple) entry.getKey(); leftTuple.unlinkFromLeftParent(); leftTuple.unlinkFromRightParent(); } workingMemory.clearNodeMemory(this); } } this.tupleSource.remove(context, builder, this, workingMemories); }
/** * OTN needs to override remove to avoid releasing the node ID, since OTN are never removed from * the rulebase in the current implementation */ protected void doRemove( final RuleRemovalContext context, final ReteooBuilder builder, final BaseNode node, final InternalWorkingMemory[] workingMemories) { if (context.getCleanupAdapter() != null) { for (InternalWorkingMemory workingMemory : workingMemories) { CleanupAdapter adapter = context.getCleanupAdapter(); final ObjectHashSet memory = (ObjectHashSet) workingMemory.getNodeMemory(this); Iterator it = memory.iterator(); for (ObjectEntry entry = (ObjectEntry) it.next(); entry != null; entry = (ObjectEntry) it.next()) { InternalFactHandle handle = (InternalFactHandle) entry.getValue(); for (LeftTuple leftTuple = handle.getFirstLeftTuple(); leftTuple != null; leftTuple = leftTuple.getLeftParentNext()) { adapter.cleanUp(leftTuple, workingMemory); } } } context.setCleanupAdapter(null); } if (!node.isInUse()) { removeObjectSink((ObjectSink) node); } }
public void updateSink( final ObjectSink sink, final PropagationContext context, final InternalWorkingMemory workingMemory) { // @todo // JBRULES-612: the cache MUST be invalidated when a new node type is added to the network, so // iterate and reset all caches. final ObjectTypeNode node = (ObjectTypeNode) sink; final ObjectType newObjectType = node.getObjectType(); InternalWorkingMemoryEntryPoint wmEntryPoint = (InternalWorkingMemoryEntryPoint) workingMemory.getWorkingMemoryEntryPoint(this.entryPoint.getEntryPointId()); for (ObjectTypeConf objectTypeConf : wmEntryPoint.getObjectTypeConfigurationRegistry().values()) { if (newObjectType.isAssignableFrom( objectTypeConf.getConcreteObjectTypeNode().getObjectType())) { objectTypeConf.resetCache(); ObjectTypeNode sourceNode = objectTypeConf.getConcreteObjectTypeNode(); Iterator it = ((ObjectTypeNodeMemory) workingMemory.getNodeMemory(sourceNode)).memory.iterator(); for (ObjectEntry entry = (ObjectEntry) it.next(); entry != null; entry = (ObjectEntry) it.next()) { sink.assertObject((InternalFactHandle) entry.getValue(), context, workingMemory); } } } }
public void updateSink( final ObjectSink sink, final PropagationContext context, final InternalWorkingMemory workingMemory) { final ObjectHashSet memory = (ObjectHashSet) workingMemory.getNodeMemory(this); Iterator it = memory.iterator(); for (ObjectEntry entry = (ObjectEntry) it.next(); entry != null; entry = (ObjectEntry) it.next()) { sink.assertObject((InternalFactHandle) entry.getValue(), context, workingMemory); } }
public void modifyLeftTuple( LeftTuple leftTuple, PropagationContext context, InternalWorkingMemory workingMemory) { final ObjectHashMap memory = (ObjectHashMap) workingMemory.getNodeMemory(this); // add it to a memory mapping InternalFactHandle handle = (InternalFactHandle) memory.get(leftTuple); // propagate it for (RightTuple rightTuple = handle.getFirstRightTuple(); rightTuple != null; rightTuple = (RightTuple) rightTuple.getHandleNext()) { rightTuple.getRightTupleSink().modifyRightTuple(rightTuple, context, workingMemory); } }
/** * @inheritDoc When a new object is asserted into an AccumulateNode, do this: * <p>1. Select all matching tuples from left memory 2. For each matching tuple, call a modify * tuple */ public void assertRightTuple( final RightTuple rightTuple, final PropagationContext context, final InternalWorkingMemory workingMemory) { final AccumulateMemory memory = (AccumulateMemory) workingMemory.getNodeMemory(this); memory.betaMemory.getRightTupleMemory().add(rightTuple); if (memory.betaMemory.getLeftTupleMemory() == null || memory.betaMemory.getLeftTupleMemory().size() == 0) { // do nothing here, as we know there are no left tuples at this stage in sequential mode or // for a query. // unless it's an "Open Query" and thus that will have left memory, so continue as normal return; } this.constraints.updateFromFactHandle( memory.betaMemory.getContext(), workingMemory, rightTuple.getFactHandle()); LeftTupleMemory leftMemory = memory.betaMemory.getLeftTupleMemory(); FastIterator leftIt = getLeftIterator(leftMemory); for (LeftTuple leftTuple = getFirstLeftTuple(rightTuple, leftMemory, context, leftIt); leftTuple != null; leftTuple = (LeftTuple) leftIt.next(leftTuple)) { if (this.constraints.isAllowedCachedRight(memory.betaMemory.getContext(), leftTuple)) { final AccumulateContext accctx = (AccumulateContext) leftTuple.getObject(); addMatch(leftTuple, rightTuple, null, null, workingMemory, memory, accctx, true); if (accctx.getAction() == null) { // schedule a test to evaluate the constraints, this is an optimisation for sub networks // We set Source to LEFT, even though this is a right propagation, because it might end up // doing multiple right propagations anyway EvaluateResultConstraints action = new EvaluateResultConstraints( ActivitySource.LEFT, leftTuple, context, workingMemory, memory, accctx, true, this); accctx.setAction(action); context.addInsertAction(action); } } } this.constraints.resetFactHandle(memory.betaMemory.getContext()); }
/** * @inheritDoc When a new tuple is asserted into an AccumulateNode, do this: * <p>1. Select all matching objects from right memory 2. Execute the initialization code * using the tuple + matching objects 3. Execute the accumulation code for each combination of * tuple+object 4. Execute the return code 5. Create a new CalculatedObjectHandle for the * resulting object and add it to the tuple 6. Propagate the tuple * <p>The initialization, accumulation and return codes, in JBRules, are assembled into a * generated method code and called once for the whole match, as you can see below: * <p>Object result = this.accumulator.accumulate( ... ); */ public void assertLeftTuple( final LeftTuple leftTuple, final PropagationContext context, final InternalWorkingMemory workingMemory) { final AccumulateMemory memory = (AccumulateMemory) workingMemory.getNodeMemory(this); AccumulateContext accresult = new AccumulateContext(); boolean useLeftMemory = true; if (!this.tupleMemoryEnabled) { // This is a hack, to not add closed DroolsQuery objects Object object = ((InternalFactHandle) leftTuple.get(0)).getObject(); if (!(object instanceof DroolsQuery) || !((DroolsQuery) object).isOpen()) { useLeftMemory = false; } } if (useLeftMemory) { memory.betaMemory.getLeftTupleMemory().add(leftTuple); leftTuple.setObject(accresult); } accresult.context = this.accumulate.createContext(); this.accumulate.init(memory.workingMemoryContext, accresult.context, leftTuple, workingMemory); this.constraints.updateFromTuple(memory.betaMemory.getContext(), workingMemory, leftTuple); RightTupleMemory rightMemory = memory.betaMemory.getRightTupleMemory(); FastIterator rightIt = getRightIterator(rightMemory); for (RightTuple rightTuple = getFirstRightTuple(leftTuple, rightMemory, context, rightIt); rightTuple != null; rightTuple = (RightTuple) rightIt.next(rightTuple)) { InternalFactHandle handle = rightTuple.getFactHandle(); if (this.constraints.isAllowedCachedLeft(memory.betaMemory.getContext(), handle)) { // add a match addMatch( leftTuple, rightTuple, null, null, workingMemory, memory, accresult, useLeftMemory); } } this.constraints.resetTuple(memory.betaMemory.getContext()); if (accresult.getAction() == null) { evaluateResultConstraints( ActivitySource.LEFT, leftTuple, context, workingMemory, memory, accresult, useLeftMemory); } // else evaluation is already scheduled, so do nothing }
/** * Retract the * <code>ReteTuple<code>, any resulting propagated joins are also retracted. * * @param leftTuple * The tuple being retracted * @param context * The <code>PropagationContext</code> * @param workingMemory * The working memory session. */ public void retractLeftTuple( final LeftTuple leftTuple, final PropagationContext context, final InternalWorkingMemory workingMemory) { RightTuple blocker = leftTuple.getBlocker(); final BetaMemory memory = (BetaMemory) workingMemory.getNodeMemory(this); if (blocker != null) { this.sink.propagateRetractLeftTuple(leftTuple, context, workingMemory); blocker.removeBlocked(leftTuple); } else { memory.getLeftTupleMemory().remove(leftTuple); } }
/** * 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()); }
public void updateSink( final ObjectSink sink, final PropagationContext context, final InternalWorkingMemory workingMemory) { final ObjectHashMap memory = (ObjectHashMap) workingMemory.getNodeMemory(this); final Iterator it = memory.iterator(); // iterates over all propagated handles and assert them to the new sink for (ObjectEntry entry = (ObjectEntry) it.next(); entry != null; entry = (ObjectEntry) it.next()) { sink.assertObject((InternalFactHandle) entry.getValue(), context, workingMemory); } }
/** * 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, context, 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 assertLeftTuple( LeftTuple leftTuple, PropagationContext context, InternalWorkingMemory workingMemory) { // the next call makes sure this node's memory is initialised workingMemory.getNodeMemory(this); InternalFactHandle handle = createFactHandle(context, workingMemory, leftTuple); DroolsQuery queryObject = createDroolsQuery(leftTuple, handle, workingMemory); QueryInsertAction action = new QueryInsertAction(context, handle, leftTuple, this); queryObject.setAction( action); // this is necessary as queries can be re-entrant, so we can check this before // re-sheduling // another action in the modify section. Make sure it's nulled after the action is done // i.e. scheduling an insert and then an update, before the insert is executed context.getQueue1().addFirst(action); }
public static void readFactHandles(MarshallerReaderContext context, ObjectStore objectStore) throws IOException, ClassNotFoundException { ObjectInputStream stream = context.stream; InternalWorkingMemory wm = context.wm; int size = stream.readInt(); // load the handles InternalFactHandle[] handles = new InternalFactHandle[size]; for (int i = 0; i < size; i++) { InternalFactHandle handle = readFactHandle(context); context.handles.put(handle.getId(), handle); handles[i] = handle; if (handle.getObject() != null) { objectStore.addHandle(handle, handle.getObject()); } readRightTuples(handle, context); } readLeftTuples(context); // object store if (stream.readBoolean()) { readLeftTuples(context); // activation fact handles } // add handles to object type nodes for (InternalFactHandle factHandle : handles) { Object object = factHandle.getObject(); EntryPoint ep = ((InternalWorkingMemoryEntryPoint) factHandle.getEntryPoint()).getEntryPoint(); ObjectTypeConf typeConf = ((InternalWorkingMemoryEntryPoint) factHandle.getEntryPoint()) .getObjectTypeConfigurationRegistry() .getObjectTypeConf(ep, object); ObjectTypeNode[] cachedNodes = typeConf.getObjectTypeNodes(); for (int i = 0, length = cachedNodes.length; i < length; i++) { ObjectHashSet set = (ObjectHashSet) wm.getNodeMemory(cachedNodes[i]); set.add(factHandle, false); } } }
/** 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(); } } }
public void updateSink( final ObjectSink sink, final PropagationContext context, final InternalWorkingMemory workingMemory) { if (lrUnlinkingEnabled) { // Update sink taking into account L&R unlinking peculiarities updateLRUnlinking(sink, context, workingMemory); } else { // Regular updateSink final ObjectHashSet memory = (ObjectHashSet) workingMemory.getNodeMemory(this); Iterator it = memory.iterator(); for (ObjectEntry entry = (ObjectEntry) it.next(); entry != null; entry = (ObjectEntry) it.next()) { sink.assertObject((InternalFactHandle) entry.getValue(), context, workingMemory); } } }
/** @inheritDoc If an object is retract, call modify tuple for each tuple match. */ public void retractRightTuple( final RightTuple rightTuple, final PropagationContext context, final InternalWorkingMemory workingMemory) { final AccumulateMemory memory = (AccumulateMemory) workingMemory.getNodeMemory(this); final InternalFactHandle origin = (InternalFactHandle) context.getFactHandleOrigin(); if (context.getType() == PropagationContext.EXPIRATION) { ((PropagationContextImpl) context).setFactHandle(null); } BetaMemory bm = memory.getBetaMemory(); if (isUnlinkingEnabled()) { StagedRightTuples stagedRightTuples = bm.getStagedRightTuples(); switch (rightTuple.getStagedType()) { // handle clash with already staged entries case LeftTuple.INSERT: stagedRightTuples.removeInsert(rightTuple); break; case LeftTuple.UPDATE: stagedRightTuples.removeUpdate(rightTuple); break; } stagedRightTuples.addDelete(rightTuple); if (bm.getDecAndGetCounter() == 0 && !isRightInputIsRiaNode()) { bm.unlinkNode(workingMemory); } return; } bm.getRightTupleMemory().remove(rightTuple); removePreviousMatchesForRightTuple( rightTuple, context, workingMemory, memory, rightTuple.firstChild); if (context.getType() == PropagationContext.EXPIRATION) { ((PropagationContextImpl) context).setFactHandle(origin); } }
/** Retracts the corresponding tuple by retrieving and retracting the fact created for it */ public void retractLeftTuple( final LeftTuple tuple, final PropagationContext context, final InternalWorkingMemory workingMemory) { final ObjectHashMap memory = (ObjectHashMap) workingMemory.getNodeMemory(this); // retrieve handle from memory final InternalFactHandle factHandle = (InternalFactHandle) memory.remove(tuple); for (RightTuple rightTuple = factHandle.getFirstRightTuple(); rightTuple != null; rightTuple = (RightTuple) rightTuple.getHandleNext()) { rightTuple.getRightTupleSink().retractRightTuple(rightTuple, context, workingMemory); } factHandle.clearRightTuples(); for (LeftTuple leftTuple = factHandle.getLastLeftTuple(); leftTuple != null; leftTuple = (LeftTuple) leftTuple.getLeftParentNext()) { leftTuple.getLeftTupleSink().retractLeftTuple(leftTuple, context, workingMemory); } factHandle.clearLeftTuples(); }
/** * Assert a new <code>FactHandleImpl</code> from the right input. If it matches any left * ReteTuple's that had no matches before, propagate tuple as an assertion. * * @param factHandle The <code>FactHandleImpl</code> being asserted. * @param context The <code>PropagationContext</code> * @param workingMemory The working memory session. */ public void assertObject( final InternalFactHandle factHandle, final PropagationContext context, final InternalWorkingMemory workingMemory) { final RightTuple rightTuple = createRightTuple(factHandle, this, context); final BetaMemory memory = (BetaMemory) workingMemory.getNodeMemory(this); memory.getRightTupleMemory().add(rightTuple); if (memory.getLeftTupleMemory() == null || memory.getLeftTupleMemory().size() == 0) { // do nothing here, as no left memory return; } this.constraints.updateFromFactHandle(memory.getContext(), workingMemory, factHandle); LeftTupleMemory leftMemory = memory.getLeftTupleMemory(); FastIterator it = getLeftIterator(leftMemory); for (LeftTuple leftTuple = getFirstLeftTuple(rightTuple, leftMemory, context, it); leftTuple != null; ) { // preserve next now, in case we remove this leftTuple LeftTuple temp = (LeftTuple) it.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); memory.getLeftTupleMemory().remove(leftTuple); this.sink.propagateAssertLeftTuple(leftTuple, context, workingMemory, true); } leftTuple = temp; } this.constraints.resetFactHandle(memory.getContext()); }
public void updateSink( final LeftTupleSink sink, final PropagationContext context, final InternalWorkingMemory workingMemory) { final AccumulateMemory memory = (AccumulateMemory) workingMemory.getNodeMemory(this); final Iterator tupleIter = memory.betaMemory.getLeftTupleMemory().iterator(); for (LeftTuple leftTuple = (LeftTuple) tupleIter.next(); leftTuple != null; leftTuple = (LeftTuple) tupleIter.next()) { AccumulateContext accctx = (AccumulateContext) leftTuple.getObject(); if (accctx.propagated) { // temporarily break the linked list to avoid wrong interactions LeftTuple[] matchings = splitList(leftTuple, accctx, true); sink.assertLeftTuple( sink.createLeftTuple(leftTuple, accctx.result, null, null, sink, true), context, workingMemory); restoreList(leftTuple, matchings); } } }
/** * Retract the <code>FactHandleimpl</code> from the <code>Rete</code> network. Also remove the * <code>FactHandleImpl</code> from the node memory. * * @param rightTuple The fact handle. * @param object The object to assert. * @param workingMemory The working memory session. */ public void retractObject( final InternalFactHandle factHandle, final PropagationContext context, final InternalWorkingMemory workingMemory) { if (objectMemoryEnabled && !(queryNode && !((DroolsQuery) factHandle.getObject()).isOpen())) { final ObjectHashSet memory = (ObjectHashSet) workingMemory.getNodeMemory(this); memory.remove(factHandle); } for (RightTuple rightTuple = factHandle.getFirstRightTuple(); rightTuple != null; rightTuple = (RightTuple) rightTuple.getHandleNext()) { rightTuple.getRightTupleSink().retractRightTuple(rightTuple, context, workingMemory); } factHandle.clearRightTuples(); for (LeftTuple leftTuple = factHandle.getFirstLeftTuple(); leftTuple != null; leftTuple = (LeftTuple) leftTuple.getLeftParentNext()) { leftTuple.getLeftTupleSink().retractLeftTuple(leftTuple, context, workingMemory); } factHandle.clearLeftTuples(); }
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()); }
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, context, 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); leftTuple.setBlocker(null); leftTuple.setBlockedPrevious(null); leftTuple.setBlockedNext(null); 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); leftTuple.setBlocker(null); leftTuple.setBlockedPrevious(null); leftTuple.setBlockedNext(null); } 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()); }