View Javadoc

1   /**
2    * Copyright (c) 2002-2011 "Neo Technology,"
3    * Network Engine for Objects in Lund AB [http://neotechnology.com]
4    *
5    * This file is part of Neo4j.
6    *
7    * Neo4j is free software: you can redistribute it and/or modify
8    * it under the terms of the GNU General Public License as published by
9    * the Free Software Foundation, either version 3 of the License, or
10   * (at your option) any later version.
11   *
12   * This program is distributed in the hope that it will be useful,
13   * but WITHOUT ANY WARRANTY; without even the implied warranty of
14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   * GNU General Public License for more details.
16   *
17   * You should have received a copy of the GNU General Public License
18   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19   */
20  package org.neo4j.kernel.impl.core;
21  
22  import java.util.Collection;
23  import java.util.HashMap;
24  import java.util.Iterator;
25  import java.util.List;
26  import java.util.Map;
27  
28  import org.neo4j.graphdb.NotFoundException;
29  import org.neo4j.graphdb.Relationship;
30  import org.neo4j.graphdb.RelationshipType;
31  import org.neo4j.helpers.collection.PrefetchingIterator;
32  import org.neo4j.kernel.impl.util.RelIdArray;
33  import org.neo4j.kernel.impl.util.RelIdArray.DirectionWrapper;
34  import org.neo4j.kernel.impl.util.RelIdIterator;
35  
36  class IntArrayIterator extends PrefetchingIterator<Relationship> implements Iterable<Relationship>
37  {
38      private Iterator<RelIdIterator> typeIterator;
39      private RelIdIterator currentTypeIterator;
40      private final NodeImpl fromNode;
41      private final DirectionWrapper direction;
42      private final NodeManager nodeManager;
43      private final RelationshipType types[];
44      private final List<RelIdIterator> rels;
45      
46      // This is just for optimization
47      private boolean isFullyLoaded;
48  
49      IntArrayIterator( List<RelIdIterator> rels, NodeImpl fromNode,
50          DirectionWrapper direction, NodeManager nodeManager, RelationshipType[] types,
51          boolean isFullyLoaded )
52      {
53          this.rels = rels;
54          this.isFullyLoaded = isFullyLoaded;
55          this.typeIterator = rels.iterator();
56          this.currentTypeIterator = typeIterator.hasNext() ? typeIterator.next() : RelIdArray.EMPTY.iterator( direction );
57          this.fromNode = fromNode;
58          this.direction = direction;
59          this.nodeManager = nodeManager;
60          this.types = types;
61      }
62  
63      public Iterator<Relationship> iterator()
64      {
65          return this;
66      }
67  
68      @Override
69      protected Relationship fetchNextOrNull()
70      {
71          do
72          {
73              if ( currentTypeIterator.hasNext() )
74              {
75                  long nextId = currentTypeIterator.next();
76                  try
77                  {
78                      return new RelationshipProxy( nextId, nodeManager );
79                  }
80                  catch ( NotFoundException e )
81                  { // ok deleted 
82                  }
83              }
84              
85              while ( !currentTypeIterator.hasNext() )
86              {
87                  if ( typeIterator.hasNext() )
88                  {
89                      currentTypeIterator = typeIterator.next();
90                  }
91                  else if ( fromNode.getMoreRelationships( nodeManager ) ||
92                          // This is here to guard for that someone else might have loaded
93                          // stuff in this relationship chain (and exhausted it) while I
94                          // iterated over my batch of relationships. It will only happen
95                          // for nodes which have more than <grab size> relationships and
96                          // isn't fully loaded when starting iterating.
97                          !isFullyLoaded )
98                  {
99                      Map<String,RelIdIterator> newRels = new HashMap<String,RelIdIterator>();
100                     for ( RelIdIterator itr : rels )
101                     {
102                         String type = itr.getType();
103                         RelIdArray newSrc = fromNode.getRelationshipIds( type );
104                         if ( newSrc != null )
105                         {
106                             itr = itr.updateSource( newSrc );
107                             itr.doAnotherRound();
108                         }
109                         newRels.put( type, itr );
110                     }
111                     
112                     // If we wanted relationships of any type check if there are
113                     // any new relationship types loaded for this node and if so
114                     // initiate iterators for them
115                     if ( types.length == 0 )
116                     {
117                         for ( RelIdArray ids : fromNode.getRelationshipIds() )
118                         {
119                             String type = ids.getType();
120                             RelIdIterator itr = newRels.get( type );
121                             if ( itr == null )
122                             {
123                                 Collection<Long> remove = nodeManager.getCowRelationshipRemoveMap( fromNode, type );
124                                 itr = remove == null ? ids.iterator( direction ) :
125                                         RelIdArray.from( ids, null, remove ).iterator( direction );
126                                 newRels.put( type, itr );
127                             }
128                             else
129                             {
130                                 itr = itr.updateSource( ids );
131                                 newRels.put( type, itr );
132                             }
133                         }
134                     }
135                     
136                     rels.clear();
137                     rels.addAll( newRels.values() );
138                     
139                     typeIterator = rels.iterator();
140                     currentTypeIterator = typeIterator.hasNext() ? typeIterator.next() : RelIdArray.EMPTY.iterator( direction );
141                     isFullyLoaded = !fromNode.hasMoreRelationshipsToLoad();
142                 }
143                 else
144                 {
145                     break;
146                 }
147             }
148          } while ( currentTypeIterator.hasNext() );
149         // no next element found
150         return null;
151     }
152 }