Author: tolusha
Date: 2009-12-25 10:02:53 -0500 (Fri, 25 Dec 2009)
New Revision: 1187
Added:
jcr/branches/1.12.0-OPT/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/util/NodeIteratorOnDemand.java
Modified:
jcr/branches/1.12.0-OPT/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/NodeImpl.java
jcr/branches/1.12.0-OPT/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/SessionDataManager.java
jcr/branches/1.12.0-OPT/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/api/nodetypes/TestPredefinedPrimaryNodeTypes.java
jcr/branches/1.12.0-OPT/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/api/writing/TestOrderBefore.java
jcr/branches/1.12.0-OPT/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/load/perf/TestGetNodesPerf.java
Log:
EXOJCR-338: NodeIteratorOnDemand
Modified:
jcr/branches/1.12.0-OPT/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/NodeImpl.java
===================================================================
---
jcr/branches/1.12.0-OPT/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/NodeImpl.java 2009-12-25
15:02:33 UTC (rev 1186)
+++
jcr/branches/1.12.0-OPT/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/NodeImpl.java 2009-12-25
15:02:53 UTC (rev 1187)
@@ -58,6 +58,7 @@
import org.exoplatform.services.jcr.impl.dataflow.session.SessionChangesLog;
import org.exoplatform.services.jcr.impl.dataflow.session.TransactionableDataManager;
import org.exoplatform.services.jcr.impl.util.EntityCollection;
+import org.exoplatform.services.jcr.impl.util.NodeIteratorOnDemand;
import org.exoplatform.services.jcr.observation.ExtendedEvent;
import org.exoplatform.services.jcr.util.IdGenerator;
import org.exoplatform.services.log.ExoLogger;
@@ -155,18 +156,21 @@
*
* @param data
* Node data
- * @param parent
- * parent node data is used for simple calculation item definition
- * @param session
+ * @param parentPrimaryTypeName
+ * parent primary type name
+ * @param parentMixinTypeNames
+ * parent mixin type names
+ * @param session
* Session
* @throws RepositoryException
* if error occurs during the Node data loading
*/
- public NodeImpl(NodeData data, NodeData parent, SessionImpl session) throws
RepositoryException
+ public NodeImpl(NodeData data, InternalQName parentPrimaryTypeName, InternalQName[]
parentMixinTypeNames,
+ SessionImpl session) throws RepositoryException
{
super(data, session);
this.sysLocFactory = session.getSystemLocationFactory();
- loadData(data, parent);
+ loadData(data, parentPrimaryTypeName, parentMixinTypeNames);
}
/**
@@ -1009,7 +1013,8 @@
checkValid();
try
{
- return new EntityCollection(childNodes());
+ return new NodeIteratorOnDemand(childNodesData(), dataManager,
nodeData().getPrimaryTypeName(), nodeData()
+ .getMixinTypeNames(), true);
}
finally
{
@@ -1397,14 +1402,16 @@
* Loads data.
*
* @param data
- * source item data for load
- * @param parent
- * parent node data is used for simple calculation item definition
+ * source item data for load
+ * @param parentPrimaryTypeName
+ * parent primary type name
+ * @param parentMixinTypeNames
+ * parent mixin type names
* @throws RepositoryException
* if error occurs
*/
- private void loadData(ItemData data, NodeData parent) throws RepositoryException,
InvalidItemStateException,
- ConstraintViolationException
+ private void loadData(ItemData data, InternalQName parentPrimaryTypeName,
InternalQName[] parentMixinTypeNames)
+ throws RepositoryException, InvalidItemStateException,
ConstraintViolationException
{
if (data == null)
@@ -1432,7 +1439,7 @@
this.qpath = nodeData.getQPath();
this.location = null;
- initDefinition(parent);
+ initDefinition(parentPrimaryTypeName, parentMixinTypeNames);
}
/**
@@ -2555,6 +2562,40 @@
}
+ /**
+ * Return child Nodes list.
+ *
+ * @return List of child Nodes
+ * @throws RepositoryException
+ * if error occurs
+ * @throws AccessDeniedException
+ * if Nodes cannot be listed due to permissions on this Node
+ */
+ private List childNodesData() throws RepositoryException, AccessDeniedException
+ {
+
+ List storedNodes = dataManager.getChildNodesData(nodeData());
+ for (int i = storedNodes.size() - 1; i >= 0; i--)
+ {
+ NodeData node = (NodeData)storedNodes.get(i);
+
+ if (!(session.getAccessManager().hasPermission(node.getACL(), new
String[]{PermissionType.READ}, session
+ .getUserState().getIdentity())))
+ {
+ storedNodes.remove(i);
+ }
+
+ ItemImpl pooled = dataManager.reloadItem(node);
+ if (pooled != null)
+ {
+ storedNodes.set(i, pooled);
+ }
+ }
+
+ Collections.sort(storedNodes, new ObjectOrderComparator());
+ return storedNodes;
+ }
+
private EntityCollection createMergeFailed(Map<String, String> failed,
SessionChangesLog changes)
throws RepositoryException
{
@@ -2818,12 +2859,18 @@
/**
* Init NodeDefinition.
*
+ * @param parentPrimaryTypeName
+ * parent primary type name
+ * @param parentMixinTypeNames
+ * parent mixin type names
+ *
* @throws RepositoryException
* if error occurs
* @throws ConstraintViolationException
* if definition not found
*/
- private void initDefinition(NodeData parent) throws RepositoryException,
ConstraintViolationException
+ private void initDefinition(InternalQName parentPrimaryTypeName, InternalQName[]
parentMixinTypeNames)
+ throws RepositoryException, ConstraintViolationException
{
if (this.isRoot())
@@ -2835,8 +2882,8 @@
}
this.definition =
-
session.getWorkspace().getNodeTypesHolder().getChildNodeDefinition(getInternalName(),
- parent.getPrimaryTypeName(), parent.getMixinTypeNames());
+
session.getWorkspace().getNodeTypesHolder().getChildNodeDefinition(getInternalName(),
parentPrimaryTypeName,
+ parentMixinTypeNames);
if (definition == null)
throw new ConstraintViolationException("Node definition not found for
" + getPath());
@@ -2943,6 +2990,17 @@
}
}
+ private static class ObjectOrderComparator implements Comparator<Object>
+ {
+ public int compare(Object n1, Object n2)
+ {
+ int order1 = n1 instanceof NodeData ? ((NodeData)n1).getOrderNumber() :
((NodeImpl)n1).getOrderNumber();
+ int order2 = n2 instanceof NodeData ? ((NodeData)n2).getOrderNumber() :
((NodeImpl)n2).getOrderNumber();
+
+ return order1 - order2;
+ }
+ }
+
// ===================== helpers =====================
private static class NodesOrderComparator implements Comparator<NodeImpl>
Modified:
jcr/branches/1.12.0-OPT/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/SessionDataManager.java
===================================================================
---
jcr/branches/1.12.0-OPT/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/SessionDataManager.java 2009-12-25
15:02:33 UTC (rev 1186)
+++
jcr/branches/1.12.0-OPT/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/SessionDataManager.java 2009-12-25
15:02:53 UTC (rev 1187)
@@ -28,6 +28,7 @@
import org.exoplatform.services.jcr.dataflow.PlainChangesLog;
import org.exoplatform.services.jcr.dataflow.SharedDataManager;
import org.exoplatform.services.jcr.datamodel.IllegalPathException;
+import org.exoplatform.services.jcr.datamodel.InternalQName;
import org.exoplatform.services.jcr.datamodel.ItemData;
import org.exoplatform.services.jcr.datamodel.NodeData;
import org.exoplatform.services.jcr.datamodel.PropertyData;
@@ -581,7 +582,7 @@
for (int i = 0, length = nodeDatas.size(); i < length; i++)
{
NodeData data = nodeDatas.get(i);
- NodeImpl item = itemFactory.createNode(data, parent);
+ NodeImpl item = itemFactory.createNode(data, parent.getPrimaryTypeName(),
parent.getMixinTypeNames());
session.getActionHandler().postRead(item);
@@ -833,6 +834,19 @@
}
}
+ /**
+ * Reloads item in pool.
+ *
+ * @param data
+ * item data
+ * @return
+ * @throws RepositoryException
+ */
+ ItemImpl reloadItem(ItemData data) throws RepositoryException
+ {
+ return itemsPool.reload(data);
+ }
+
public void rename(NodeData srcData, ItemDataMoveVisitor initializer) throws
RepositoryException
{
@@ -1379,6 +1393,50 @@
}
/**
+ * Wraps NodeData into NodeImpl.
+ *
+ * @param data
+ * NodeData to wrap
+ * @param parentPrimaryTypeName
+ * parent primary type name
+ * @param parentMixinTypeNames
+ * parent mixin type names
+ * @param pool
+ * indicates does the item fall in pool
+ * @return NodeImpl object
+ * @throws RepositoryException
+ * if errors is occurs
+ */
+ public NodeImpl wrapNodeData(NodeData data, InternalQName parentPrimaryTypeName,
+ InternalQName[] parentMixinTypeNames, boolean pool) throws RepositoryException
+ {
+ NodeImpl item = itemFactory.createNode(data, parentPrimaryTypeName,
parentMixinTypeNames);
+ session.getActionHandler().postRead(item);
+
+ if (pool)
+ {
+ NodeImpl pooledItem = (NodeImpl)itemsPool.getItem(data.getIdentifier());
+
+ if (pooledItem == null)
+ {
+ NodeData pooledData = (NodeData)itemsPool.getData(data.getIdentifier());
+ if (pooledData != null)
+ {
+ item.loadData(pooledData);
+ }
+
+ item = (NodeImpl)itemsPool.get(item);
+ }
+ else
+ {
+ item = pooledItem;
+ }
+ }
+
+ return item;
+ }
+
+ /**
* Removes all pending changes of this item
*
* @param item
@@ -1559,7 +1617,7 @@
{
retval = new ArrayList<ItemData>(desc);
}
-
+
return retval;
}
@@ -1607,7 +1665,7 @@
retval.add(itemData);
if (deep)
retval.addAll(mergeList(itemData, dataManager, true, action));
- }
+ }
}
else
{
@@ -1717,13 +1775,17 @@
private WeakHashMap<String, ItemImpl> items;
+ private WeakHashMap<String, ItemData> datas;
+
ItemReferencePool()
{
items = new WeakHashMap<String, ItemImpl>();
+ datas = new WeakHashMap<String, ItemData>();
}
ItemImpl remove(String identifier)
{
+ datas.remove(identifier);
return items.remove(identifier);
}
@@ -1755,9 +1817,11 @@
ItemImpl get(ItemImpl newItem) throws RepositoryException
{
String identifier = newItem.getInternalIdentifier();
+
ItemImpl item = items.get(identifier);
if (item == null)
{
+ datas.remove(identifier);
items.put(identifier, newItem);
return newItem;
}
@@ -1766,9 +1830,34 @@
item.loadData(newItem.getData(), newItem.getItemDefinitionData());
return item;
}
+
}
/**
+ * Gets item from pool.
+ *
+ * @param identifier
+ * item identifier
+ * @return ItemImpl object from pool
+ */
+ ItemImpl getItem(String identifier)
+ {
+ return items.get(identifier);
+ }
+
+ /**
+ * Gets item from pool.
+ *
+ * @param identifier
+ * item identifier
+ * @return ItemData object from pool
+ */
+ ItemData getData(String identifier)
+ {
+ return datas.get(identifier);
+ }
+
+ /**
* Reload an existed item in the pool with given data
*
* @param itemData
@@ -1789,6 +1878,10 @@
item.loadData(newItemData);
return item;
}
+ else
+ {
+ datas.put(identifier, newItemData);
+ }
return null;
}
@@ -1921,9 +2014,10 @@
return node;
}
- private NodeImpl createNode(NodeData data, NodeData parent) throws
RepositoryException
+ private NodeImpl createNode(NodeData data, InternalQName parentPrimaryTypeName,
+ InternalQName[] parentMixinTypeNames) throws RepositoryException
{
- NodeImpl node = new NodeImpl(data, parent, session);
+ NodeImpl node = new NodeImpl(data, parentPrimaryTypeName, parentMixinTypeNames,
session);
if (data.getPrimaryTypeName().equals(Constants.NT_VERSION))
{
return new VersionImpl(data, session);
Added:
jcr/branches/1.12.0-OPT/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/util/NodeIteratorOnDemand.java
===================================================================
---
jcr/branches/1.12.0-OPT/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/util/NodeIteratorOnDemand.java
(rev 0)
+++
jcr/branches/1.12.0-OPT/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/util/NodeIteratorOnDemand.java 2009-12-25
15:02:53 UTC (rev 1187)
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2003-2009 eXo Platform SAS.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Affero 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.exoplatform.services.jcr.impl.util;
+
+import org.exoplatform.services.jcr.datamodel.InternalQName;
+import org.exoplatform.services.jcr.datamodel.NodeData;
+import org.exoplatform.services.jcr.impl.core.NodeImpl;
+import org.exoplatform.services.jcr.impl.core.SessionDataManager;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.RepositoryException;
+
+/**
+ * Created by The eXo Platform SAS.
+ *
+ * <br/>
+ * Date: 2009
+ *
+ * @author <a href="mailto:anatoliy.bazko@exoplatform.com.ua">Anatoliy
Bazko</a>
+ * @version $Id$
+ */
+public class NodeIteratorOnDemand implements NodeIterator
+{
+
+ private Iterator iter;
+
+ private List list;
+
+ private SessionDataManager dataManager;
+
+ private InternalQName parentPrimaryTypeName;
+
+ private InternalQName[] parentMixinTypeNames;
+
+ private boolean pool;
+
+ private int pos;
+
+ /**
+ * NodeIteratorOnDemand constructor. Gets list of NodeData and returns NodeImpl
object on demand.
+ * NodeImpl objects will be created on next() or nextNode() methods when will be
called.
+ *
+ * @param list
+ * NodeData list
+ * @param parentPrimaryTypeName
+ * parent primary type name
+ * @param parentMixinTypeNames
+ * parent mixin type names
+ * @param pool
+ * indicates does the item fall in pool when NodeImpl will be created
+ * @param dataManager
+ * session data manager
+ */
+ public NodeIteratorOnDemand(List list, SessionDataManager dataManager, InternalQName
parentPrimaryTypeName,
+ InternalQName[] parentMixinTypeNames, boolean pool)
+ {
+ if (list == null)
+ this.list = new ArrayList();
+ else
+ this.list = list;
+
+ this.dataManager = dataManager;
+ this.parentPrimaryTypeName = parentPrimaryTypeName;
+ this.parentMixinTypeNames = parentMixinTypeNames;
+ this.pool = pool;
+
+ this.iter = list.iterator();
+ this.pos = 0;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Node nextNode()
+ {
+ wrapNodeData();
+
+ pos++;
+ return (Node)iter.next();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void skip(long skipNum)
+ {
+ pos += skipNum;
+ while (skipNum-- > 0)
+ {
+ iter.next();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public long getSize()
+ {
+ return list.size();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public long getPosition()
+ {
+ return pos;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean hasNext()
+ {
+ return iter.hasNext();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Object next()
+ {
+ wrapNodeData();
+
+ pos++;
+ return iter.next();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void remove()
+ {
+ iter.remove();
+ }
+
+ /**
+ * Wraps NodeData into NodeImpl.
+ */
+ private void wrapNodeData()
+ {
+ if (pos == list.size())
+ {
+ return;
+ }
+
+ Object obj = list.get(pos);
+
+ if (!(obj instanceof NodeImpl))
+ {
+ try
+ {
+ list.set(pos, dataManager.wrapNodeData((NodeData)obj, parentPrimaryTypeName,
parentMixinTypeNames, pool));
+ }
+ catch (RepositoryException e)
+ {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+ }
+}
Property changes on:
jcr/branches/1.12.0-OPT/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/util/NodeIteratorOnDemand.java
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Modified:
jcr/branches/1.12.0-OPT/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/api/nodetypes/TestPredefinedPrimaryNodeTypes.java
===================================================================
---
jcr/branches/1.12.0-OPT/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/api/nodetypes/TestPredefinedPrimaryNodeTypes.java 2009-12-25
15:02:33 UTC (rev 1186)
+++
jcr/branches/1.12.0-OPT/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/api/nodetypes/TestPredefinedPrimaryNodeTypes.java 2009-12-25
15:02:53 UTC (rev 1187)
@@ -20,7 +20,6 @@
import org.exoplatform.services.jcr.JcrAPIBaseTest;
import org.exoplatform.services.jcr.impl.Constants;
-import org.exoplatform.services.jcr.impl.util.EntityCollection;
import javax.jcr.Node;
import javax.jcr.RepositoryException;
@@ -47,8 +46,8 @@
NodeDefinition def = node.getDefinition();
NodeType type = node.getPrimaryNodeType();
- assertTrue("have child ", ((EntityCollection)node.getNodes()).size() ==
0);
- assertTrue("prop num !=1 ",
((EntityCollection)node.getProperties()).size() == 1);
+ assertTrue("have child ", node.getNodes().getSize() == 0);
+ assertTrue("prop num !=1 ", node.getProperties().getSize() == 1);
assertEquals("Prop not default ", "nt:unstructured",
node.getProperty("jcr:primaryType").getString());
assertEquals("Type!= nt:unstructured", type.getName(),
"nt:unstructured");
@@ -82,9 +81,8 @@
NodeDefinition def = node.getDefinition();
NodeType type = node.getPrimaryNodeType();
- assertTrue("have child ", ((EntityCollection)node.getNodes()).size() ==
0);
- assertTrue("prop num !=2 ==" +
((EntityCollection)node.getProperties()).size(), ((EntityCollection)node
- .getProperties()).size() == 2);
+ assertTrue("have child ", node.getNodes().getSize() == 0);
+ assertTrue("prop num !=2 ==" + node.getProperties().getSize(),
node.getProperties().getSize() == 2);
PropertyDefinition[] propertyDefinitions = type.getPropertyDefinitions();
assertTrue("typePropDefs != 3", propertyDefinitions.length == 3);
Modified:
jcr/branches/1.12.0-OPT/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/api/writing/TestOrderBefore.java
===================================================================
---
jcr/branches/1.12.0-OPT/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/api/writing/TestOrderBefore.java 2009-12-25
15:02:33 UTC (rev 1186)
+++
jcr/branches/1.12.0-OPT/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/api/writing/TestOrderBefore.java 2009-12-25
15:02:53 UTC (rev 1187)
@@ -21,6 +21,9 @@
import org.exoplatform.services.jcr.JcrAPIBaseTest;
import org.exoplatform.services.jcr.impl.util.EntityCollection;
+import java.util.ArrayList;
+import java.util.List;
+
import javax.jcr.ItemExistsException;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
@@ -865,7 +868,7 @@
// n1[100] -> n1[99] pos:99
testBase.orderBefore("n1[2]", "n_21");
- EntityCollection nodes = (EntityCollection)testBase.getNodes();
+ EntityCollection nodes = getEntityCollection(testBase.getNodes());
assertEquals("Nodes must be equals ", n1__2, nodes.getList().get(119));
// pos
// :
@@ -880,7 +883,7 @@
testBase.save();
- nodes = (EntityCollection)testBase.getNodes();
+ nodes = getEntityCollection(testBase.getNodes());
assertEquals("Nodes must be equals ", n1__2, nodes.getList().get(119));
// pos
// :
@@ -900,7 +903,7 @@
// n_24 -> pos:120; n1[100] -> pos:121;
testBase.orderBefore("n_24", "n1[100]");
- nodes = (EntityCollection)testBase.getNodes();
+ nodes = getEntityCollection(testBase.getNodes());
assertEquals("Nodes must be equals ", n1__100, nodes.getList().get(120));
// pos
// :
@@ -961,4 +964,15 @@
checkOrderAnotherSession(order);
}
+
+ private EntityCollection getEntityCollection(NodeIterator nodes)
+ {
+ List result = new ArrayList();
+ while (nodes.hasNext())
+ {
+ result.add(nodes.next());
+ }
+
+ return new EntityCollection(result);
+ }
}
Modified:
jcr/branches/1.12.0-OPT/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/load/perf/TestGetNodesPerf.java
===================================================================
---
jcr/branches/1.12.0-OPT/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/load/perf/TestGetNodesPerf.java 2009-12-25
15:02:33 UTC (rev 1186)
+++
jcr/branches/1.12.0-OPT/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/load/perf/TestGetNodesPerf.java 2009-12-25
15:02:53 UTC (rev 1187)
@@ -35,9 +35,9 @@
{
private static final String testName = "testRoot";
- private static final int sessionCount = 10;
+ private static final int sessionCount = 1;
- private static final int tryCount = 5;
+ private static final int tryCount = 1;
private Session[] sessions = new Session[sessionCount];
@@ -92,6 +92,7 @@
break;
}
+ log.info("Memory used: " + (rt.totalMemory() - rt.freeMemory() -
usedMemory) / 1024 / 1024 + "Mb");
log.info("waiting for 10 seconds...");
Thread.sleep(10000);
}
@@ -127,4 +128,20 @@
}
}
}
+
+ public void _testNodeItetatorPerfomance() throws Exception
+ {
+ Node testRoot = session.getRootNode().getNode(testName);
+
+ // Test iterator perfomance
+ NodeIterator nodes = testRoot.getNodes();
+ log.info(nodes.getSize() + " nodes");
+
+ long startTime = System.currentTimeMillis();
+ while (nodes.hasNext())
+ {
+ nodes.nextNode();
+ }
+ log.info("Iterating all nodes consumes : " + (System.currentTimeMillis()
- startTime) + "ms");
+ }
}