Skip to content

Commit

Permalink
[DROOLS-6636] reoreder right tuple and blockers in NotNode even when …
Browse files Browse the repository at this point in the history
…property reactivity prevents propagation (apache#3869) (apache#3881)

(cherry picked from commit dd3289d)
  • Loading branch information
mariofusco authored Oct 7, 2021
1 parent b40751b commit 3f43fd6
Show file tree
Hide file tree
Showing 5 changed files with 229 additions and 86 deletions.
96 changes: 50 additions & 46 deletions drools-core/src/main/java/org/drools/core/phreak/PhreakNotNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,10 @@
import org.drools.core.reteoo.LeftTupleSink;
import org.drools.core.reteoo.NotNode;
import org.drools.core.reteoo.RightTuple;
import org.drools.core.reteoo.SubnetworkTuple;
import org.drools.core.reteoo.TupleMemory;
import org.drools.core.rule.ContextEntry;
import org.drools.core.spi.PropagationContext;
import org.drools.core.util.FastIterator;
import org.drools.core.util.index.TupleList;

import static org.drools.core.phreak.PhreakJoinNode.updateChildLeftTuple;

Expand Down Expand Up @@ -363,66 +361,72 @@ public void doRightUpdates(NotNode notNode,
}
}

LeftTuple firstBlocked = rightTuple.getTempBlocked();
if ( firstBlocked != null ) {
RightTuple rootBlocker = rightTuple.getTempNextRightTuple();
if ( rootBlocker == null ) {
iterateFromStart = true;
}
iterateFromStart = updateBlockersAndPropagate(notNode, rightTuple, wm, rtm, contextEntry, constraints, iterateFromStart, sink, trgLeftTuples, ltm);
rightTuple.clearStaged();
rightTuple = next;
}

FastIterator rightIt = notNode.getRightIterator( rtm );
constraints.resetFactHandle(contextEntry);
constraints.resetTuple(contextEntry);
}

// iterate all the existing previous blocked LeftTuples
for ( LeftTuple leftTuple = firstBlocked; leftTuple != null; ) {
LeftTuple temp = leftTuple.getBlockedNext();
public static boolean updateBlockersAndPropagate(NotNode notNode, RightTuple rightTuple, InternalWorkingMemory wm, TupleMemory rtm, ContextEntry[] contextEntry,
BetaConstraints constraints, boolean iterateFromStart, LeftTupleSink sink, TupleSets<LeftTuple> trgLeftTuples, TupleMemory ltm) {
LeftTuple firstBlocked = rightTuple.getTempBlocked();
if ( firstBlocked != null ) {
RightTuple rootBlocker = rightTuple.getTempNextRightTuple();
if ( rootBlocker == null ) {
iterateFromStart = true;
}

leftTuple.clearBlocker();
FastIterator rightIt = notNode.getRightIterator(rtm);

if ( leftTuple.getStagedType() == LeftTuple.UPDATE ) {
// ignore, as it will get processed via left iteration. Children cannot be processed twice
// but need to add it back into list first
leftTuple.setBlocker( rightTuple );
rightTuple.addBlocked( leftTuple );
// iterate all the existing previous blocked LeftTuples
for ( LeftTuple leftTuple = firstBlocked; leftTuple != null; ) {
LeftTuple temp = leftTuple.getBlockedNext();

leftTuple = temp;
continue;
}
leftTuple.clearBlocker();

constraints.updateFromTuple( contextEntry,
wm,
leftTuple );
if ( leftTuple.getStagedType() == LeftTuple.UPDATE ) {
// ignore, as it will get processed via left iteration. Children cannot be processed twice
// but need to add it back into list first
leftTuple.setBlocker(rightTuple);
rightTuple.addBlocked( leftTuple );

if ( iterateFromStart ) {
rootBlocker = notNode.getFirstRightTuple( leftTuple, rtm, null, rightIt );
}
leftTuple = temp;
continue;
}

// we know that older tuples have been checked so continue next
for ( RightTuple newBlocker = rootBlocker; newBlocker != null; newBlocker = (RightTuple) rightIt.next( newBlocker ) ) {
// cannot select a RightTuple queued in the delete list
// There may be UPDATE RightTuples too, but that's ok. They've already been re-added to the correct bucket, safe to be reprocessed.
if ( leftTuple.getStagedType() != LeftTuple.DELETE && newBlocker.getStagedType() != LeftTuple.DELETE &&
constraints.isAllowedCachedLeft( contextEntry, newBlocker.getFactHandleForEvaluation() ) ) {
constraints.updateFromTuple(contextEntry,
wm,
leftTuple );

leftTuple.setBlocker( newBlocker );
newBlocker.addBlocked( leftTuple );
if (iterateFromStart) {
rootBlocker = notNode.getFirstRightTuple( leftTuple, rtm, null, rightIt );
}

break;
}
}
// we know that older tuples have been checked so continue next
for ( RightTuple newBlocker = rootBlocker; newBlocker != null; newBlocker = (RightTuple) rightIt.next( newBlocker ) ) {
// cannot select a RightTuple queued in the delete list
// There may be UPDATE RightTuples too, but that's ok. They've already been re-added to the correct bucket, safe to be reprocessed.
if ( leftTuple.getStagedType() != LeftTuple.DELETE && newBlocker.getStagedType() != LeftTuple.DELETE &&
constraints.isAllowedCachedLeft(contextEntry, newBlocker.getFactHandleForEvaluation() ) ) {

if ( leftTuple.getBlocker() == null ) {
insertChildLeftTuple( sink, trgLeftTuples, ltm, leftTuple, rightTuple.getPropagationContext(), true );
leftTuple.setBlocker( newBlocker );
newBlocker.addBlocked( leftTuple );

break;
}
}

leftTuple = temp;
if ( trgLeftTuples != null && leftTuple.getBlocker() == null ) {
insertChildLeftTuple(sink, trgLeftTuples, ltm, leftTuple, rightTuple.getPropagationContext(), true );
}

leftTuple = temp;
}
rightTuple.clearStaged();
rightTuple = next;
}

constraints.resetFactHandle(contextEntry);
constraints.resetTuple(contextEntry);
return iterateFromStart;
}

public void doLeftDeletes(BetaMemory bm,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import static org.drools.core.phreak.PhreakNotNode.updateBlockersAndPropagate;
import static org.drools.core.reteoo.BetaNode.getBetaMemory;

public class RuleNetworkEvaluator {

private static final Logger log = LoggerFactory.getLogger(RuleNetworkEvaluator.class);
Expand Down Expand Up @@ -871,9 +874,7 @@ public static void doUpdatesReorderChildLeftTuple( RightTuple rightTuple ) {
}
}

public static void doUpdatesExistentialReorderRightMemory(BetaMemory bm,
BetaNode betaNode,
TupleSets<RightTuple> srcRightTuples) {
public static void doUpdatesExistentialReorderRightMemory(BetaMemory bm, BetaNode betaNode, TupleSets<RightTuple> srcRightTuples) {
TupleMemory rtm = bm.getRightTupleMemory();

boolean resumeFromCurrent = !(betaNode.isIndexedUnificationJoin() || rtm.getIndexType().isComparison());
Expand All @@ -889,53 +890,72 @@ public static void doUpdatesExistentialReorderRightMemory(BetaMemory bm,
}

for (RightTuple rightTuple = srcRightTuples.getUpdateFirst(); rightTuple != null; rightTuple = rightTuple.getStagedNext()) {
if (rightTuple.getMemory() != null) {
doRemoveExistentialRightMemoryForReorder(rtm, resumeFromCurrent, rightTuple);
}

if (resumeFromCurrent) {
if (rightTuple.getBlocked() != null) {
// look for a non-staged right tuple first forward ...
RightTuple tempRightTuple = ( RightTuple ) rightTuple.getNext();
while ( tempRightTuple != null && tempRightTuple.getStagedType() != LeftTuple.NONE ) {
// next cannot be an updated or deleted rightTuple
tempRightTuple = (RightTuple) tempRightTuple.getNext();
}
for (RightTuple rightTuple = srcRightTuples.getUpdateFirst(); rightTuple != null; rightTuple = rightTuple.getStagedNext()) {
doAddExistentialRightMemoryForReorder(rtm, resumeFromCurrent, rightTuple);
}

// ... and if cannot find one try backward
if ( tempRightTuple == null ) {
tempRightTuple = ( RightTuple ) rightTuple.getPrevious();
while ( tempRightTuple != null && tempRightTuple.getStagedType() != LeftTuple.NONE ) {
// next cannot be an updated or deleted rightTuple
tempRightTuple = (RightTuple) tempRightTuple.getPrevious();
}
}
if ( rtm.getIndexType() != TupleMemory.IndexType.NONE) {
for ( RightTuple rightTuple = srcRightTuples.getDeleteFirst(); rightTuple != null; rightTuple = rightTuple.getStagedNext() ) {
rtm.add( rightTuple );
}
}
}

rightTuple.setTempNextRightTuple( tempRightTuple );
}
}
public static void doExistentialUpdatesReorderChildLeftTuple(InternalWorkingMemory wm, NotNode notNode, RightTuple rightTuple) {
BetaMemory bm = getBetaMemory(notNode, wm);
TupleMemory rtm = bm.getRightTupleMemory();

rightTuple.setTempBlocked(rightTuple.getBlocked());
rightTuple.setBlocked(null);
rtm.remove(rightTuple);
boolean resumeFromCurrent = !(notNode.isIndexedUnificationJoin() || rtm.getIndexType().isComparison());
doRemoveExistentialRightMemoryForReorder(rtm, resumeFromCurrent, rightTuple);
doAddExistentialRightMemoryForReorder(rtm, resumeFromCurrent, rightTuple);

updateBlockersAndPropagate(notNode, rightTuple, wm, rtm, bm.getContext(), notNode.getRawConstraints(), !resumeFromCurrent, null, null, null);;
}

private static void doAddExistentialRightMemoryForReorder(TupleMemory rtm, boolean resumeFromCurrent, RightTuple rightTuple) {
rtm.add(rightTuple);

if (resumeFromCurrent) {
if ( rightTuple.getBlocked() != null && rightTuple.getTempNextRightTuple() == null ) {
// the next RightTuple was null, but current RightTuple was added back into the same bucket, so reset as root blocker to re-match can be attempted
rightTuple.setTempNextRightTuple(rightTuple);
}
}

for (RightTuple rightTuple = srcRightTuples.getUpdateFirst(); rightTuple != null; rightTuple = rightTuple.getStagedNext()) {
rtm.add( rightTuple );
doUpdatesReorderChildLeftTuple(rightTuple);
}

private static void doRemoveExistentialRightMemoryForReorder(TupleMemory rtm, boolean resumeFromCurrent, RightTuple rightTuple) {
if (rightTuple.getMemory() != null) {

if (resumeFromCurrent) {
if ( rightTuple.getBlocked() != null && rightTuple.getTempNextRightTuple() == null ) {
// the next RightTuple was null, but current RightTuple was added back into the same bucket, so reset as root blocker to re-match can be attempted
rightTuple.setTempNextRightTuple( rightTuple );
}
}
if (rightTuple.getBlocked() != null) {
// look for a non-staged right tuple first forward ...
RightTuple tempRightTuple = ( RightTuple ) rightTuple.getNext();
while ( tempRightTuple != null && tempRightTuple.getStagedType() != LeftTuple.NONE ) {
// next cannot be an updated or deleted rightTuple
tempRightTuple = (RightTuple) tempRightTuple.getNext();
}

doUpdatesReorderChildLeftTuple( rightTuple );
}
// ... and if cannot find one try backward
if ( tempRightTuple == null ) {
tempRightTuple = ( RightTuple ) rightTuple.getPrevious();
while ( tempRightTuple != null && tempRightTuple.getStagedType() != LeftTuple.NONE ) {
// next cannot be an updated or deleted rightTuple
tempRightTuple = (RightTuple) tempRightTuple.getPrevious();
}
}

if ( rtm.getIndexType() != TupleMemory.IndexType.NONE) {
for ( RightTuple rightTuple = srcRightTuples.getDeleteFirst(); rightTuple != null; rightTuple = rightTuple.getStagedNext() ) {
rtm.add( rightTuple );
rightTuple.setTempNextRightTuple( tempRightTuple );
}
}

rightTuple.setTempBlocked(rightTuple.getBlocked());
rightTuple.setBlocked(null);
rtm.remove(rightTuple);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -340,8 +340,7 @@ public void modifyObject(InternalFactHandle factHandle, ModifyPreviousTuples mod
rightTuple.setPropagationContext( context );
doUpdateRightTuple(rightTuple, wm, bm);
} else if (rightTuple.getMemory() != null) {
getBetaMemory( this, wm ).getRightTupleMemory().removeAdd(rightTuple);
doUpdatesReorderChildLeftTuple( rightTuple );
reorderRightTuple(wm, rightTuple);
}
} else {
if ( context.getModificationMask().intersects(getRightInferredMask()) ) {
Expand All @@ -353,6 +352,11 @@ public void modifyObject(InternalFactHandle factHandle, ModifyPreviousTuples mod
}
}

protected void reorderRightTuple(InternalWorkingMemory wm, RightTuple rightTuple) {
getBetaMemory( this, wm).getRightTupleMemory().removeAdd(rightTuple);
doUpdatesReorderChildLeftTuple(rightTuple);
}

public void doDeleteRightTuple(final RightTuple rightTuple,
final InternalWorkingMemory wm,
final BetaMemory memory) {
Expand Down
6 changes: 6 additions & 0 deletions drools-core/src/main/java/org/drools/core/reteoo/NotNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import org.drools.core.spi.PropagationContext;

import static org.drools.core.phreak.AddRemoveRule.flushLeftTupleIfNecessary;
import static org.drools.core.phreak.RuleNetworkEvaluator.doExistentialUpdatesReorderChildLeftTuple;

public class NotNode extends BetaNode {
private static final long serialVersionUID = 510l;
Expand Down Expand Up @@ -70,6 +71,11 @@ public void writeExternal(ObjectOutput out) throws IOException {
out.writeBoolean( emptyBetaConstraints );
}

@Override
protected void reorderRightTuple(InternalWorkingMemory wm, RightTuple rightTuple) {
doExistentialUpdatesReorderChildLeftTuple(wm, this, rightTuple);
}

public boolean isEmptyBetaConstraints() {
return emptyBetaConstraints;
}
Expand Down
Loading

0 comments on commit 3f43fd6

Please sign in to comment.