/**
* Copyright (c) 2002-2013 "Neo Technology,"
* Network Engine for Objects in Lund AB [http://neotechnology.com]
*
* This file is part of Neo4j.
*
* Neo4j is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.neo4j.kernel.impl.core;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.neo4j.graphdb.NotFoundException;
import org.neo4j.graphdb.Relationship;
import org.neo4j.graphdb.RelationshipType;
import org.neo4j.helpers.collection.PrefetchingIterator;
import org.neo4j.kernel.impl.util.RelIdArray;
import org.neo4j.kernel.impl.util.RelIdArray.DirectionWrapper;
import org.neo4j.kernel.impl.util.RelIdIterator;
class IntArrayIterator extends PrefetchingIterator<Relationship> implements Iterable<Relationship>
{
private Iterator<RelIdIterator> typeIterator;
private RelIdIterator currentTypeIterator;
private final NodeImpl fromNode;
private final DirectionWrapper direction;
private final NodeManager nodeManager;
private final RelationshipType types[];
private final List<RelIdIterator> rels;
// This is just for optimization
private boolean isFullyLoaded;
IntArrayIterator( List<RelIdIterator> rels, NodeImpl fromNode,
DirectionWrapper direction, NodeManager nodeManager, RelationshipType[] types,
boolean isFullyLoaded )
{
this.rels = rels;
this.isFullyLoaded = isFullyLoaded;
this.typeIterator = rels.iterator();
this.currentTypeIterator = typeIterator.hasNext() ? typeIterator.next() : RelIdArray.EMPTY.iterator( direction );
this.fromNode = fromNode;
this.direction = direction;
this.nodeManager = nodeManager;
this.types = types;
}
public Iterator<Relationship> iterator()
{
return this;
}
@Override
protected Relationship fetchNextOrNull()
{
do
{
if ( currentTypeIterator.hasNext() )
{
long nextId = currentTypeIterator.next();
try
{
return new RelationshipProxy( nextId, nodeManager );
}
catch ( NotFoundException e )
{ // ok deleted
}
}
while ( !currentTypeIterator.hasNext() )
{
if ( typeIterator.hasNext() )
{
currentTypeIterator = typeIterator.next();
}
else if ( fromNode.getMoreRelationships( nodeManager ) ||
// This is here to guard for that someone else might have loaded
// stuff in this relationship chain (and exhausted it) while I
// iterated over my batch of relationships. It will only happen
// for nodes which have more than <grab size> relationships and
// isn't fully loaded when starting iterating.
!isFullyLoaded )
{
Map<String,RelIdIterator> newRels = new HashMap<String,RelIdIterator>();
for ( RelIdIterator itr : rels )
{
String type = itr.getType();
RelIdArray newSrc = fromNode.getRelationshipIds( type );
if ( newSrc != null )
{
itr = itr.updateSource( newSrc );
itr.doAnotherRound();
}
newRels.put( type, itr );
}
// If we wanted relationships of any type check if there are
// any new relationship types loaded for this node and if so
// initiate iterators for them
if ( types.length == 0 )
{
for ( RelIdArray ids : fromNode.getRelationshipIds() )
{
String type = ids.getType();
RelIdIterator itr = newRels.get( type );
if ( itr == null )
{
Collection<Long> remove = nodeManager.getCowRelationshipRemoveMap( fromNode, type );
itr = remove == null ? ids.iterator( direction ) :
RelIdArray.from( ids, null, remove ).iterator( direction );
newRels.put( type, itr );
}
else
{
itr = itr.updateSource( ids );
newRels.put( type, itr );
}
}
}
rels.clear();
rels.addAll( newRels.values() );
typeIterator = rels.iterator();
currentTypeIterator = typeIterator.hasNext() ? typeIterator.next() : RelIdArray.EMPTY.iterator( direction );
isFullyLoaded = !fromNode.hasMoreRelationshipsToLoad();
}
else
{
break;
}
}
} while ( currentTypeIterator.hasNext() );
// no next element found
return null;
}
}