/* * Copyright 2015 Red Hat, Inc. and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.drools.core.common; import org.drools.core.reteoo.AccumulateNode; import org.drools.core.reteoo.AccumulateNode.AccumulateContext; import org.drools.core.reteoo.AccumulateNode.AccumulateMemory; import org.drools.core.reteoo.BetaMemory; import org.drools.core.reteoo.BetaNode; import org.drools.core.reteoo.EvalConditionNode; import org.drools.core.reteoo.ExistsNode; import org.drools.core.reteoo.FromNode; import org.drools.core.reteoo.FromNode.FromMemory; import org.drools.core.reteoo.JoinNode; import org.drools.core.reteoo.LeftInputAdapterNode; import org.drools.core.reteoo.LeftTuple; import org.drools.core.reteoo.LeftTupleSink; import org.drools.core.reteoo.LeftTupleSource; import org.drools.core.reteoo.NotNode; import org.drools.core.reteoo.ObjectSource; import org.drools.core.reteoo.ObjectTypeNode; import org.drools.core.reteoo.QueryElementNode; import org.drools.core.reteoo.RightTuple; import org.drools.core.spi.Tuple; import org.drools.core.util.FastIterator; import org.drools.core.util.Iterator; public class LeftTupleIterator implements Iterator<LeftTuple> { protected InternalWorkingMemory wm; protected LeftTupleSink node; protected LeftTuple currentLeftTuple; private java.util.Iterator<InternalFactHandle> otnIterator; LeftTupleIterator() { } private LeftTupleIterator(InternalWorkingMemory wm, LeftTupleSink node) { this.wm = wm; this.node = node; setFirstLeftTupleForNode(); } public static Iterator<LeftTuple> iterator( InternalWorkingMemory wm, LeftTupleSink node) { return new LeftTupleIterator(wm, node); } public void setFirstLeftTupleForNode() { LeftTupleSource source = node.getLeftTupleSource(); this.currentLeftTuple = getFirstLeftTuple( source, node, wm ); } public LeftTuple getFirstLeftTuple(LeftTupleSource source, LeftTupleSink sink, InternalWorkingMemory wm) { if ( source instanceof AccumulateNode ) { AccumulateMemory accmem = (AccumulateMemory) wm.getNodeMemory( (MemoryFactory) source ); BetaMemory memory = accmem.getBetaMemory(); FastIterator localIt = memory.getLeftTupleMemory().fullFastIterator(); Tuple leftTuple = BetaNode.getFirstTuple( memory.getLeftTupleMemory(), localIt ); if( leftTuple != null ) { AccumulateContext accctx = (AccumulateContext) leftTuple.getContextObject(); return accctx.getResultLeftTuple(); } return null; } if ( source instanceof JoinNode || source instanceof NotNode || source instanceof FromNode ||source instanceof AccumulateNode ) { BetaMemory memory; FastIterator localIt; if ( source instanceof FromNode ) { memory = ((FromMemory) wm.getNodeMemory( (MemoryFactory) source )).getBetaMemory(); } else if ( source instanceof AccumulateNode ) { memory = ((AccumulateMemory) wm.getNodeMemory( (MemoryFactory) source )).getBetaMemory(); } else { memory = (BetaMemory) wm.getNodeMemory( (MemoryFactory) source ); } localIt = memory.getLeftTupleMemory().fullFastIterator(); Tuple leftTuple = BetaNode.getFirstTuple( memory.getLeftTupleMemory(), localIt ); while ( leftTuple != null ) { for ( LeftTuple childleftTuple = leftTuple.getFirstChild(); childleftTuple != null; childleftTuple = childleftTuple.getHandleNext() ) { if ( childleftTuple.getTupleSink() == sink ) { return childleftTuple; } } leftTuple = (LeftTuple) localIt.next( leftTuple ); } } if ( source instanceof ExistsNode ) { BetaMemory memory = (BetaMemory) wm.getNodeMemory( (MemoryFactory) source ); FastIterator localIt = memory.getRightTupleMemory().fullFastIterator(); RightTuple rightTuple = (RightTuple) BetaNode.getFirstTuple( memory.getRightTupleMemory(), localIt ); while ( rightTuple != null ) { if ( rightTuple.getBlocked() != null ) { for ( LeftTuple leftTuple = rightTuple.getBlocked(); leftTuple != null; leftTuple = leftTuple.getBlockedNext() ) { for ( LeftTuple childleftTuple = leftTuple.getFirstChild(); childleftTuple != null; childleftTuple = childleftTuple.getHandleNext() ) { if ( childleftTuple.getTupleSink() == sink ) { return childleftTuple; } } } } rightTuple = (RightTuple) localIt.next( rightTuple ); } } else if ( source instanceof LeftInputAdapterNode ) { ObjectSource os = ((LeftInputAdapterNode) source).getParentObjectSource(); while ( !(os instanceof ObjectTypeNode) ) { os = os.getParentObjectSource(); } ObjectTypeNode otn = (ObjectTypeNode) os; otnIterator = wm.getNodeMemory( otn ).iterator(); while (otnIterator.hasNext()) { InternalFactHandle handle = otnIterator.next(); LeftTuple leftTuple = handle.findFirstLeftTuple( lt -> lt.getTupleSink() == sink ); if ( leftTuple != null ) { return leftTuple; } } } else if ( source instanceof EvalConditionNode || source instanceof QueryElementNode ) { LeftTuple parentLeftTuple = getFirstLeftTuple( source.getLeftTupleSource(), (LeftTupleSink) source, wm ); while ( parentLeftTuple != null ) { for ( LeftTuple leftTuple = parentLeftTuple.getFirstChild(); leftTuple != null; leftTuple = leftTuple.getHandleNext() ) { if ( leftTuple.getTupleSink() == sink ) { return leftTuple; } } parentLeftTuple = getNextLeftTuple( source.getLeftTupleSource(), (LeftTupleSink) source, parentLeftTuple, wm ); } } return null; } public LeftTuple getNextLeftTuple(LeftTupleSource source, LeftTupleSink sink, LeftTuple leftTuple, InternalWorkingMemory wm) { if ( otnIterator != null ) { LeftTuple leftParent = leftTuple.getLeftParent(); while ( leftTuple != null ) { leftTuple = leftTuple.getHandleNext(); for ( ; leftTuple != null; leftTuple = leftTuple.getHandleNext() ) { // Iterate to find the next left tuple for this sink, skip tuples for other sinks due to sharing split if ( leftTuple.getTupleSink() == sink ) { return leftTuple; } } } // We have a parent LeftTuple so try there next if ( leftParent != null ) { // we know it has to be evalNode query element node while ( leftParent != null ) { leftParent = getNextLeftTuple( source.getLeftTupleSource(), (LeftTupleSink) source, leftParent, wm ); if ( leftParent != null ) { for ( leftTuple = leftParent.getFirstChild(); leftTuple != null; leftTuple = leftTuple.getHandleNext() ) { if ( leftTuple.getTupleSink() == sink ) { return leftTuple; } } } } return null; } // We have exhausted the current FactHandle, now try the next while ( otnIterator.hasNext() ) { InternalFactHandle handle = otnIterator.next(); leftTuple = handle.findFirstLeftTuple( lt -> lt.getTupleSink() == sink ); if ( leftTuple != null ) { return leftTuple; } } // We've exhausted this OTN so set the iterator to null otnIterator = null; } else if ( source instanceof AccumulateNode ) { // when using phreak, accumulate result tuples will not link to leftParent, but to parent instead BetaMemory memory = ((AccumulateMemory) wm.getNodeMemory( (MemoryFactory) source )).getBetaMemory(); FastIterator localIt = memory.getLeftTupleMemory().fullFastIterator( leftTuple.getParent() ); LeftTuple childLeftTuple = leftTuple; leftTuple = childLeftTuple.getParent(); while ( leftTuple != null ) { if ( childLeftTuple == null ) { childLeftTuple = leftTuple.getFirstChild(); } else { childLeftTuple = childLeftTuple.getHandleNext(); } for ( ; childLeftTuple != null; childLeftTuple = childLeftTuple.getHandleNext() ) { if ( childLeftTuple.getTupleSink() == sink ) { return childLeftTuple; } } leftTuple = (LeftTuple) localIt.next( leftTuple ); } } else if ( source instanceof JoinNode || source instanceof NotNode|| source instanceof FromNode || source instanceof AccumulateNode ) { BetaMemory memory; FastIterator localIt; if ( source instanceof FromNode ) { memory = ((FromMemory) wm.getNodeMemory( (MemoryFactory) source )).getBetaMemory(); } else if ( source instanceof AccumulateNode ) { memory = ((AccumulateMemory) wm.getNodeMemory( (MemoryFactory) source )).getBetaMemory(); } else { memory = (BetaMemory) wm.getNodeMemory( (MemoryFactory) source ); } localIt = memory.getLeftTupleMemory().fullFastIterator( leftTuple.getLeftParent() ); LeftTuple childLeftTuple = leftTuple; leftTuple = childLeftTuple.getLeftParent(); while ( leftTuple != null ) { if ( childLeftTuple == null ) { childLeftTuple = leftTuple.getFirstChild(); } else { childLeftTuple = childLeftTuple.getHandleNext(); } for ( ; childLeftTuple != null; childLeftTuple = childLeftTuple.getHandleNext() ) { if ( childLeftTuple.getTupleSink() == sink ) { return childLeftTuple; } } leftTuple = (LeftTuple) localIt.next( leftTuple ); } } if ( source instanceof ExistsNode ) { BetaMemory memory = (BetaMemory) wm.getNodeMemory( (MemoryFactory) source ); RightTuple rightTuple = leftTuple.getLeftParent().getBlocker(); FastIterator localIt = memory.getRightTupleMemory().fullFastIterator( rightTuple ); for ( LeftTuple childleftTuple = leftTuple.getHandleNext(); childleftTuple != null; childleftTuple = childleftTuple.getHandleNext() ) { if ( childleftTuple.getTupleSink() == sink ) { return childleftTuple; } } leftTuple = leftTuple.getLeftParent(); // now move onto next RightTuple while ( rightTuple != null ) { if ( rightTuple.getBlocked() != null ) { if ( leftTuple != null ) { leftTuple = leftTuple.getBlockedNext(); } else { leftTuple = rightTuple.getBlocked(); } for ( ; leftTuple != null; leftTuple = leftTuple.getBlockedNext() ) { for ( LeftTuple childleftTuple = leftTuple.getFirstChild(); childleftTuple != null; childleftTuple = childleftTuple.getHandleNext() ) { if ( childleftTuple.getTupleSink() == sink ) { return childleftTuple; } } } } rightTuple = (RightTuple) localIt.next( rightTuple ); } } else if ( source instanceof EvalConditionNode || source instanceof QueryElementNode ) { LeftTuple childLeftTuple = leftTuple; if ( leftTuple != null ) { leftTuple = leftTuple.getLeftParent(); while ( leftTuple != null ) { if ( childLeftTuple != null ) { childLeftTuple = childLeftTuple.getHandleNext(); } else { childLeftTuple = leftTuple.getFirstChild(); } for ( ; childLeftTuple != null; childLeftTuple = childLeftTuple.getHandleNext() ) { if ( childLeftTuple.getTupleSink() == sink ) { return childLeftTuple; } } if ( source instanceof EvalConditionNode ) { leftTuple = getNextLeftTuple( source.getLeftTupleSource(), (LeftTupleSink) source, leftTuple, wm ); } else { leftTuple = getNextLeftTuple( source.getLeftTupleSource(), (LeftTupleSink) source, leftTuple, wm ); } } } } return null; } public void setNextLeftTuple() { LeftTupleSource source = node.getLeftTupleSource(); currentLeftTuple = getNextLeftTuple( source, node, currentLeftTuple, wm ); } public LeftTuple next() { LeftTuple leftTuple = null; if ( this.currentLeftTuple != null ) { leftTuple = currentLeftTuple; setNextLeftTuple(); } return leftTuple; } }