public static LeftTuple getFirstLeftTuple(final LeftTupleMemory memory, final FastIterator it) { if (!memory.isIndexed()) { return memory.getFirst(null); } else { return (LeftTuple) it.next(null); } }
public FastIterator getLeftIterator(LeftTupleMemory memory) { if (!this.indexedUnificationJoin) { return memory.fastIterator(); } else { return memory.fullFastIterator(); } }
public static void dpUpdatesExistentialReorderLeftMemory( BetaMemory bm, LeftTupleSets srcLeftTuples) { LeftTupleMemory ltm = bm.getLeftTupleMemory(); // sides must first be re-ordered, to ensure iteration integrity for (LeftTuple leftTuple = srcLeftTuples.getUpdateFirst(); leftTuple != null; ) { LeftTuple next = leftTuple.getStagedNext(); if (leftTuple.getMemory() != null) { ltm.remove(leftTuple); } leftTuple = next; } for (LeftTuple leftTuple = srcLeftTuples.getUpdateFirst(); leftTuple != null; ) { LeftTuple next = leftTuple.getStagedNext(); if (leftTuple.getBlocker() == null) { ltm.add(leftTuple); for (LeftTuple childLeftTuple = leftTuple.getFirstChild(); childLeftTuple != null; ) { LeftTuple childNext = childLeftTuple.getLeftParentNext(); childLeftTuple.reAddRight(); childLeftTuple = childNext; } } leftTuple = next; } }
/** * Test method for {@link * org.drools.reteoo.AccumulateNode#assertLeftTuple(org.drools.reteoo.LeftTupleImpl, * org.drools.spi.PropagationContext, org.drools.reteoo.ReteooWorkingMemory)}. */ @Test public void testAssertTupleWithObjects() { final DefaultFactHandle f0 = (DefaultFactHandle) this.workingMemory .getFactHandleFactory() .newFactHandle("cheese", null, null, workingMemory); final DefaultFactHandle f1 = (DefaultFactHandle) this.workingMemory .getFactHandleFactory() .newFactHandle("other cheese", null, null, workingMemory); final LeftTupleImpl tuple0 = new LeftTupleImpl(f0, null, true); this.node.assertObject(f0, this.context, this.workingMemory); this.node.assertObject(f1, this.context, this.workingMemory); // assert tuple, should add one to left memory this.node.assertLeftTuple(tuple0, this.context, this.workingMemory); // check memories assertEquals(1, this.memory.getLeftTupleMemory().size()); assertEquals(2, this.memory.getRightTupleMemory().size()); assertEquals( "Wrong number of elements in matching objects list ", 2, this.accumulator.getMatchingObjects().size()); // assert tuple, should add left memory final LeftTupleImpl tuple1 = new LeftTupleImpl(f1, null, true); this.node.assertLeftTuple(tuple1, this.context, this.workingMemory); assertEquals(2, this.memory.getLeftTupleMemory().size()); assertEquals( "Wrong number of elements in matching objects list ", 2, this.accumulator.getMatchingObjects().size()); final LeftTupleMemory memory = this.memory.getLeftTupleMemory(); assertTrue(memory.contains(tuple0)); assertTrue(memory.contains(tuple1)); assertEquals("Two tuples should have been propagated", 2, this.sink.getAsserted().size()); }
public LeftTuple getFirstLeftTuple( final RightTuple rightTuple, final LeftTupleMemory memory, final PropagationContext context, final FastIterator it) { if (!this.indexedUnificationJoin) { return memory.getFirst(rightTuple); } else { return (LeftTuple) it.next(null); } }
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 modifyRightTuple( RightTuple rightTuple, PropagationContext context, InternalWorkingMemory workingMemory) { final AccumulateMemory memory = (AccumulateMemory) workingMemory.getNodeMemory(this); BetaMemory bm = memory.betaMemory; // Add and remove to make sure we are in the right bucket and at the end // this is needed to fix for indexing and deterministic iteration bm.getRightTupleMemory().removeAdd(rightTuple); if (bm.getLeftTupleMemory() == null || bm.getLeftTupleMemory().size() == 0) { // do nothing here, as we know there are no left tuples at this stage in sequential mode. return; } LeftTuple childLeftTuple = rightTuple.firstChild; LeftTupleMemory leftMemory = bm.getLeftTupleMemory(); FastIterator leftIt = getLeftIterator(leftMemory); LeftTuple leftTuple = getFirstLeftTuple(rightTuple, leftMemory, context, leftIt); this.constraints.updateFromFactHandle( bm.getContext(), workingMemory, rightTuple.getFactHandle()); // first check our index (for indexed nodes only) hasn't changed and we are returning the same // bucket // We assume a bucket change if leftTuple == null if (childLeftTuple != null && leftMemory.isIndexed() && !leftIt.isFullIterator() && (leftTuple == null || (leftTuple.getMemory() != childLeftTuple.getLeftParent().getMemory()))) { // our index has changed, so delete all the previous matches removePreviousMatchesForRightTuple( rightTuple, context, workingMemory, memory, childLeftTuple); childLeftTuple = null; // null so the next check will attempt matches for new bucket } // if LeftTupleMemory is empty, there are no matches to modify if (leftTuple != null) { if (childLeftTuple == null) { // either we are indexed and changed buckets or // we had no children before, but there is a bucket to potentially match, so try as normal // assert for (; leftTuple != null; leftTuple = (LeftTuple) leftIt.next(leftTuple)) { if (this.constraints.isAllowedCachedRight(bm.getContext(), leftTuple)) { final AccumulateContext accctx = (AccumulateContext) leftTuple.getObject(); // add a new match 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); } } } } else { // in the same bucket, so iterate and compare for (; leftTuple != null; leftTuple = (LeftTuple) leftIt.next(leftTuple)) { if (this.constraints.isAllowedCachedRight(bm.getContext(), leftTuple)) { final AccumulateContext accctx = (AccumulateContext) leftTuple.getObject(); LeftTuple temp = null; if (childLeftTuple != null && childLeftTuple.getLeftParent() == leftTuple) { temp = childLeftTuple.getRightParentNext(); // we must re-add this to ensure deterministic iteration childLeftTuple.reAddLeft(); removeMatch(rightTuple, childLeftTuple, workingMemory, memory, accctx, true); childLeftTuple = temp; } // add a new match addMatch( leftTuple, rightTuple, null, childLeftTuple, workingMemory, memory, accctx, true); if (temp != null) { childLeftTuple = temp; } 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); } } else if (childLeftTuple != null && childLeftTuple.getLeftParent() == leftTuple) { LeftTuple temp = childLeftTuple.getRightParentNext(); final AccumulateContext accctx = (AccumulateContext) leftTuple.getObject(); // remove the match removeMatch(rightTuple, childLeftTuple, 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); } childLeftTuple = temp; } // else do nothing, was false before and false now. } } } this.constraints.resetFactHandle(bm.getContext()); }