You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by ju...@apache.org on 2012/08/09 13:35:58 UTC

svn commit: r1371168 - in /jackrabbit/oak/trunk/oak-core/src: main/java/org/apache/jackrabbit/oak/kernel/ main/java/org/apache/jackrabbit/oak/plugins/lucene/ main/java/org/apache/jackrabbit/oak/plugins/memory/ main/java/org/apache/jackrabbit/oak/query/...

Author: jukka
Date: Thu Aug  9 11:35:58 2012
New Revision: 1371168

URL: http://svn.apache.org/viewvc?rev=1371168&view=rev
Log:
OAK-233: Query should use the NodeStore abstraction

Add a NodeState argument to Query.executeQuery().
Adjust the TraversingIndex to use the NodeState instead of directly calling the MicroKernel.
Also extend the TraversingIndex to support common PropertyRestrictions

Modified:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeState.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/lucene/LuceneIndex.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/StringValue.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/Query.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryEngineImpl.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ResultImpl.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/JoinImpl.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SelectorImpl.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SourceImpl.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/index/PropertyContentIndex.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/index/TraversingCursor.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/index/TraversingIndex.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/QueryIndex.java
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/lucene/LuceneEditorTest.java
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/index/TraversingCursorTest.java

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeState.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeState.java?rev=1371168&r1=1371167&r2=1371168&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeState.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeState.java Thu Aug  9 11:35:58 2012
@@ -48,7 +48,7 @@ import com.google.common.collect.Lists;
  * Basic {@link NodeState} implementation based on the {@link MicroKernel}
  * interface. This class makes an attempt to load data lazily.
  */
-final class KernelNodeState extends AbstractNodeState {
+public final class KernelNodeState extends AbstractNodeState {
 
     /**
      * Maximum number of child nodes kept in memory.

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/lucene/LuceneIndex.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/lucene/LuceneIndex.java?rev=1371168&r1=1371167&r2=1371168&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/lucene/LuceneIndex.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/lucene/LuceneIndex.java Thu Aug  9 11:35:58 2012
@@ -31,6 +31,7 @@ import org.apache.jackrabbit.oak.spi.Cur
 import org.apache.jackrabbit.oak.spi.Filter;
 import org.apache.jackrabbit.oak.spi.Filter.PropertyRestriction;
 import org.apache.jackrabbit.oak.spi.QueryIndex;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
 import org.apache.jackrabbit.oak.spi.state.NodeStore;
 import org.apache.lucene.index.DirectoryReader;
 import org.apache.lucene.index.IndexReader;
@@ -76,9 +77,9 @@ public class LuceneIndex implements Quer
     }
 
     @Override
-    public Cursor query(Filter filter, String revisionId) {
+    public Cursor query(Filter filter, String revisionId, NodeState root) {
         try {
-            Directory directory = new OakDirectory(store, store.getRoot(), index.getPath());
+            Directory directory = new OakDirectory(store, root, index.getPath());
             try {
                 IndexReader reader = DirectoryReader.open(directory);
                 try {

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/StringValue.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/StringValue.java?rev=1371168&r1=1371167&r2=1371168&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/StringValue.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/StringValue.java Thu Aug  9 11:35:58 2012
@@ -18,7 +18,7 @@ package org.apache.jackrabbit.oak.plugin
 
 import javax.jcr.PropertyType;
 
-final class StringValue extends MemoryValue {
+public final class StringValue extends MemoryValue {
 
     private final String value;
 

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/Query.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/Query.java?rev=1371168&r1=1371167&r2=1371168&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/Query.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/Query.java Thu Aug  9 11:35:58 2012
@@ -53,6 +53,7 @@ import org.apache.jackrabbit.oak.query.a
 import org.apache.jackrabbit.oak.query.ast.UpperCaseImpl;
 import org.apache.jackrabbit.oak.query.index.FilterImpl;
 import org.apache.jackrabbit.oak.spi.QueryIndex;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
 
 /**
  * Represents a parsed query. Lifecycle: use the constructor to create a new
@@ -286,11 +287,11 @@ public class Query {
         this.explain = explain;
     }
 
-    public ResultImpl executeQuery(String revisionId) {
-        return new ResultImpl(this, revisionId);
+    public ResultImpl executeQuery(String revisionId, NodeState root) {
+        return new ResultImpl(this, revisionId, root);
     }
 
-    Iterator<ResultRowImpl> getRows(String revisionId) {
+    Iterator<ResultRowImpl> getRows(String revisionId, NodeState root) {
         prepare();
         Iterator<ResultRowImpl> it;
         if (explain) {
@@ -299,7 +300,7 @@ public class Query {
             ResultRowImpl r = new ResultRowImpl(this, new String[0], new CoreValue[] { getValueFactory().createValue(plan) }, null);
             it = Arrays.asList(r).iterator();
         } else {
-            it = new RowIterator(revisionId, limit, offset);
+            it = new RowIterator(revisionId, root, limit, offset);
             if (orderings != null) {
                 // TODO "order by" is not necessary if the used index returns
                 // rows in the same order
@@ -355,12 +356,14 @@ public class Query {
     class RowIterator implements Iterator<ResultRowImpl> {
 
         private final String revisionId;
+        private final NodeState root;
         private ResultRowImpl current;
         private boolean started, end;
         private long limit, offset, rowIndex;
 
-        RowIterator(String revisionId, long limit, long offset) {
+        RowIterator(String revisionId, NodeState root, long limit, long offset) {
             this.revisionId = revisionId;
+            this.root = root;
             this.limit = limit;
             this.offset = offset;
         }
@@ -374,7 +377,7 @@ public class Query {
                 return;
             }
             if (!started) {
-                source.execute(revisionId);
+                source.execute(revisionId, root);
                 started = true;
             }
             while (true) {

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryEngineImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryEngineImpl.java?rev=1371168&r1=1371167&r2=1371168&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryEngineImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryEngineImpl.java Thu Aug  9 11:35:58 2012
@@ -26,6 +26,7 @@ import org.apache.jackrabbit.oak.api.Con
 import org.apache.jackrabbit.oak.api.CoreValue;
 import org.apache.jackrabbit.oak.api.CoreValueFactory;
 import org.apache.jackrabbit.oak.api.QueryEngine;
+import org.apache.jackrabbit.oak.kernel.KernelNodeState;
 import org.apache.jackrabbit.oak.namepath.NamePathMapper;
 import org.apache.jackrabbit.oak.query.index.FilterImpl;
 import org.apache.jackrabbit.oak.query.index.TraversingIndex;
@@ -109,7 +110,8 @@ public class QueryEngineImpl implements 
         }
         q.setQueryEngine(this);
         q.prepare();
-        return q.executeQuery(mk.getHeadRevision());
+        String revision = mk.getHeadRevision();
+        return q.executeQuery(revision, new KernelNodeState(mk, "/", revision));
     }
 
     public QueryIndex getBestIndex(FilterImpl filter) {
@@ -122,7 +124,7 @@ public class QueryEngineImpl implements 
             }
         }
         if (best == null) {
-            best = new TraversingIndex(mk);
+            best = new TraversingIndex();
         }
         return best;
     }

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ResultImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ResultImpl.java?rev=1371168&r1=1371167&r2=1371168&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ResultImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ResultImpl.java Thu Aug  9 11:35:58 2012
@@ -22,6 +22,7 @@ import org.apache.jackrabbit.oak.api.Res
 import org.apache.jackrabbit.oak.api.ResultRow;
 import org.apache.jackrabbit.oak.query.ast.ColumnImpl;
 import org.apache.jackrabbit.oak.query.ast.SelectorImpl;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
 
 /**
  * A query result.
@@ -30,10 +31,12 @@ public class ResultImpl implements Resul
 
     protected final Query query;
     protected final String revisionId;
+    protected final NodeState root;
 
-    ResultImpl(Query query, String revisionId) {
+    ResultImpl(Query query, String revisionId, NodeState root) {
         this.query = query;
         this.revisionId = revisionId;
+        this.root = root;
     }
 
     @Override
@@ -62,7 +65,7 @@ public class ResultImpl implements Resul
 
             @Override
             public Iterator<ResultRowImpl> iterator() {
-                return query.getRows(revisionId);
+                return query.getRows(revisionId, root);
             }
         };
     }

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/JoinImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/JoinImpl.java?rev=1371168&r1=1371167&r2=1371168&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/JoinImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/JoinImpl.java Thu Aug  9 11:35:58 2012
@@ -15,6 +15,7 @@ package org.apache.jackrabbit.oak.query.
 
 import org.apache.jackrabbit.mk.api.MicroKernel;
 import org.apache.jackrabbit.oak.query.Query;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
 
 /**
  * A join.
@@ -30,6 +31,7 @@ public class JoinImpl extends SourceImpl
     private boolean leftNeedNext;
     private boolean foundJoinedRow;
     private boolean end;
+    private NodeState root;
     private String revisionId;
 
     public JoinImpl(SourceImpl left, SourceImpl right, JoinType joinType,
@@ -123,7 +125,8 @@ public class JoinImpl extends SourceImpl
     }
 
     @Override
-    public void execute(String revisionId) {
+    public void execute(String revisionId, NodeState root) {
+        this.root = root;
         this.revisionId = revisionId;
         leftNeedExecute = true;
         end = false;
@@ -135,7 +138,7 @@ public class JoinImpl extends SourceImpl
             return false;
         }
         if (leftNeedExecute) {
-            left.execute(revisionId);
+            left.execute(revisionId, root);
             leftNeedExecute = false;
             leftNeedNext = true;
         }
@@ -149,7 +152,7 @@ public class JoinImpl extends SourceImpl
                 rightNeedExecute = true;
             }
             if (rightNeedExecute) {
-                right.execute(revisionId);
+                right.execute(revisionId, root);
                 foundJoinedRow = false;
                 rightNeedExecute = false;
             }

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SelectorImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SelectorImpl.java?rev=1371168&r1=1371167&r2=1371168&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SelectorImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SelectorImpl.java Thu Aug  9 11:35:58 2012
@@ -27,6 +27,7 @@ import org.apache.jackrabbit.oak.query.Q
 import org.apache.jackrabbit.oak.query.index.FilterImpl;
 import org.apache.jackrabbit.oak.spi.Cursor;
 import org.apache.jackrabbit.oak.spi.QueryIndex;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
 
 /**
  * A selector within a query.
@@ -77,8 +78,8 @@ public class SelectorImpl extends Source
     }
 
     @Override
-    public void execute(String revisionId) {
-        cursor = index.query(createFilter(), revisionId);
+    public void execute(String revisionId, NodeState root) {
+        cursor = index.query(createFilter(), revisionId, root);
     }
 
     @Override

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SourceImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SourceImpl.java?rev=1371168&r1=1371167&r2=1371168&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SourceImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SourceImpl.java Thu Aug  9 11:35:58 2012
@@ -20,6 +20,7 @@ package org.apache.jackrabbit.oak.query.
 
 import org.apache.jackrabbit.mk.api.MicroKernel;
 import org.apache.jackrabbit.oak.query.Query;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
 
 /**
  * The base class of a selector and a join.
@@ -92,8 +93,9 @@ public abstract class SourceImpl extends
      * Execute the query. The current node is set to before the first row.
      *
      * @param revisionId the revision to use
+     * @param root root state of the given revision
      */
-    public abstract void execute(String revisionId);
+    public abstract void execute(String revisionId, NodeState root);
 
     /**
      * Go to the next node for the given source. This will also filter the

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/index/PropertyContentIndex.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/index/PropertyContentIndex.java?rev=1371168&r1=1371167&r2=1371168&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/index/PropertyContentIndex.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/index/PropertyContentIndex.java Thu Aug  9 11:35:58 2012
@@ -24,6 +24,7 @@ import org.apache.jackrabbit.oak.api.Cor
 import org.apache.jackrabbit.oak.spi.Cursor;
 import org.apache.jackrabbit.oak.spi.Filter;
 import org.apache.jackrabbit.oak.spi.QueryIndex;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
 
 /**
  * An index that stores the index data in a {@code MicroKernel}.
@@ -59,7 +60,7 @@ public class PropertyContentIndex implem
     }
 
     @Override
-    public Cursor query(Filter filter, String revisionId) {
+    public Cursor query(Filter filter, String revisionId, NodeState root) {
         String propertyName = index.getPropertyName();
         Filter.PropertyRestriction restriction = filter.getPropertyRestriction(propertyName);
         if (restriction == null) {

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/index/TraversingCursor.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/index/TraversingCursor.java?rev=1371168&r1=1371167&r2=1371168&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/index/TraversingCursor.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/index/TraversingCursor.java Thu Aug  9 11:35:58 2012
@@ -13,43 +13,82 @@
  */
 package org.apache.jackrabbit.oak.query.index;
 
-import org.apache.jackrabbit.mk.api.MicroKernel;
-import org.apache.jackrabbit.mk.simple.NodeImpl;
+import static org.apache.jackrabbit.oak.spi.Filter.PathRestriction.ALL_CHILDREN;
+
+import java.util.Deque;
+import java.util.Iterator;
+
+import javax.jcr.PropertyType;
+
+import org.apache.jackrabbit.oak.api.CoreValue;
+import org.apache.jackrabbit.oak.api.PropertyState;
 import org.apache.jackrabbit.oak.commons.PathUtils;
+import org.apache.jackrabbit.oak.plugins.memory.MemoryChildNodeEntry;
+import org.apache.jackrabbit.oak.plugins.memory.StringValue;
 import org.apache.jackrabbit.oak.spi.Cursor;
-import java.util.ArrayList;
+import org.apache.jackrabbit.oak.spi.Filter;
+import org.apache.jackrabbit.oak.spi.Filter.PropertyRestriction;
+import org.apache.jackrabbit.oak.spi.state.ChildNodeEntry;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+
+import com.google.common.collect.Iterators;
+import com.google.common.collect.Queues;
 
 /**
  * A cursor that reads all nodes in a given subtree.
  */
 public class TraversingCursor implements Cursor {
 
-    private final MicroKernel mk;
-    private final String revisionId;
-    private final int childBlockSize;
+    private final Filter filter;
+
+    private final Deque<Iterator<? extends ChildNodeEntry>> nodes =
+            Queues.newArrayDeque();
+
+    private String parentPath;
 
-    private ArrayList<NodeCursor> nodes = new ArrayList<NodeCursor>();
     private String currentPath;
 
-    public TraversingCursor(MicroKernel mk, String revisionId, int childBlockSize, String path) {
-        this.mk = mk;
-        this.revisionId = revisionId;
-        this.childBlockSize = childBlockSize;
-        currentPath = path;
-    }
+    public TraversingCursor(Filter filter, NodeState root) {
+        this.filter = filter;
 
-    private boolean loadChildren(String path, long offset) {
-        String s = mk.getNodes(path, revisionId, 0, offset, childBlockSize, null);
-        if (s == null) {
-            return false;
+        String path = filter.getPath();
+        parentPath = null;
+        currentPath = "/";
+        NodeState parent = null;
+        NodeState node = root;
+        if (!path.equals("/")) {
+            for (String name : path.substring(1).split("/")) {
+                parentPath = currentPath;
+                currentPath = PathUtils.concat(parentPath, name);
+
+                parent = node;
+                node = parent.getChildNode(name);
+
+                if (node == null) {
+                    return; // nothing can match this filter, leave nodes empty
+                }
+            }
+        }
+
+        switch (filter.getPathRestriction()) {
+        case EXACT:
+        case ALL_CHILDREN:
+            nodes.add(Iterators.singletonIterator(
+                    new MemoryChildNodeEntry(currentPath, node)));
+            parentPath = "";
+            break;
+        case PARENT:
+            if (parent != null) {
+                nodes.add(Iterators.singletonIterator(
+                        new MemoryChildNodeEntry(parentPath, parent)));
+                parentPath = "";
+            }
+            break;
+        case DIRECT_CHILDREN:
+            nodes.add(node.getChildNodeEntries().iterator());
+            parentPath = currentPath;
+            break;
         }
-        NodeCursor c = new NodeCursor();
-        c.node = NodeImpl.parse(s);
-        c.node.setPath(path);
-        c.pos = offset;
-        nodes.add(c);
-        String child = c.node.getChildNodeName(0);
-        return child != null;
     }
 
     @Override
@@ -59,53 +98,104 @@ public class TraversingCursor implements
 
     @Override
     public boolean next() {
-        if (nodes == null) {
-            currentPath = null;
-            return false;
-        }
-        if (nodes.isEmpty()) {
-            if (!mk.nodeExists(currentPath, revisionId)) {
-                nodes = null;
-                currentPath = null;
-                return false;
+        while (!nodes.isEmpty()) {
+            Iterator<? extends ChildNodeEntry> iterator = nodes.getLast();
+            if (iterator.hasNext()) {
+                ChildNodeEntry entry = iterator.next();
+                NodeState node = entry.getNodeState();
+
+                String name = entry.getName();
+                currentPath = PathUtils.concat(parentPath, name);
+
+                if (filter.getPathRestriction() == ALL_CHILDREN) {
+                    nodes.addLast(node.getChildNodeEntries().iterator());
+                    parentPath = currentPath;
+                }
+
+                if (matchesFilter(node, currentPath)) {
+                    return true;
+                }
+            } else {
+                nodes.removeLast();
+                parentPath = PathUtils.getParentPath(parentPath);
             }
-            loadChildren(currentPath, 0);
-            return true;
         }
-        while (!nodes.isEmpty()) {
-            // next child node in the deepest level
-            NodeCursor c = nodes.get(nodes.size() - 1);
-            currentPath = c.node.getPath();
-            long pos = c.pos++;
-            if (pos >= c.node.getTotalChildNodeCount()) {
-                // there are no more child nodes
-                nodes.remove(nodes.size() - 1);
+        currentPath = null;
+        return false;
+    }
+
+    private boolean matchesFilter(NodeState node, String path) {
+        for (PropertyRestriction pr : filter.getPropertyRestrictions()) {
+            if ("jcr:path".equals(pr.propertyName)) {
+                if (!matchesValue(new StringValue(path), pr)) {
+                    return false;
+                }
             } else {
-                if (pos > 0 && pos % childBlockSize == 0) {
-                    // need to load a new block
-                    nodes.remove(nodes.size() - 1);
-                    if (loadChildren(currentPath, pos)) {
-                        c = nodes.get(nodes.size() - 1);
-                        c.pos++;
+                PropertyState property = getProperty(node, pr.propertyName);
+                if (property == null) {
+                    return false;
+                } else if (pr.first != null || pr.last != null) {
+                    boolean matches = false;
+                    for (CoreValue value : property.getValues()) {
+                        if (matchesValue(value, pr)) {
+                            matches = true;
+                        }
+                    }
+                    if (!matches) {
+                        return false;
                     }
                 }
-                String childName = c.node.getChildNodeName(pos % childBlockSize);
-                currentPath = PathUtils.concat(currentPath, childName);
-                loadChildren(currentPath, 0);
-                return true;
             }
         }
-        nodes = null;
-        currentPath = null;
-        return false;
+        return true;
+    }
+
+    private PropertyState getProperty(NodeState node, String path) {
+        int slash = path.indexOf('/');
+        while (slash != -1) {
+            node = node.getChildNode(path.substring(0, slash));
+            if (node == null) {
+                return null;
+            }
+            path = path.substring(slash + 1);
+            slash = path.indexOf('/');
+        }
+        return node.getProperty(path);
     }
 
-    /**
-     * A pointer to a child node within a node.
-     */
-    static class NodeCursor {
-        NodeImpl node;
-        long pos;
+    private boolean matchesValue(CoreValue value, PropertyRestriction pr) {
+        int first = -1;
+        if (pr.first != null) {
+            first = compareValues(pr.first, value, pr.first.getType());
+        }
+        if (first > 0 || (first == 0 && !pr.firstIncluding)) {
+            return false;
+        }
+
+        int last = -1;
+        if (pr.last != null) {
+            last = compareValues(value, pr.last, pr.last.getType());
+        }
+        if (last > 0 || (last == 0 && !pr.lastIncluding)) {
+            return false;
+        }
+
+        return true;
+    }
+
+    private int compareValues(CoreValue a, CoreValue b, int type) {
+        if (type == PropertyType.BOOLEAN) {
+            return Boolean.valueOf(a.getBoolean()).compareTo(
+                    Boolean.valueOf(b.getBoolean()));
+        } else if (type == PropertyType.DECIMAL) {
+            return a.getDecimal().compareTo(b.getDecimal());
+        } else if (type == PropertyType.DOUBLE) {
+            return Double.compare(a.getDouble(), b.getDouble());
+        } else if (type == PropertyType.LONG) {
+            return Long.signum(a.getLong() - b.getLong());
+        } else {
+            return a.getString().compareTo(b.getString());
+        }
     }
 
 }

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/index/TraversingIndex.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/index/TraversingIndex.java?rev=1371168&r1=1371167&r2=1371168&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/index/TraversingIndex.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/index/TraversingIndex.java Thu Aug  9 11:35:58 2012
@@ -18,31 +18,20 @@
  */
 package org.apache.jackrabbit.oak.query.index;
 
-import org.apache.jackrabbit.mk.api.MicroKernel;
 import org.apache.jackrabbit.oak.commons.PathUtils;
 import org.apache.jackrabbit.oak.spi.Cursor;
 import org.apache.jackrabbit.oak.spi.Filter;
 import org.apache.jackrabbit.oak.spi.QueryIndex;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
 
 /**
  * An index that traverses over a given subtree.
  */
 public class TraversingIndex implements QueryIndex {
 
-    private final MicroKernel mk;
-    private int childBlockSize = 2000;
-
-    public TraversingIndex(MicroKernel mk) {
-        this.mk = mk;
-    }
-
-    public void setChildBlockSize(int childBlockSize) {
-        this.childBlockSize = childBlockSize;
-    }
-
     @Override
-    public Cursor query(Filter filter, String revisionId) {
-        return new TraversingCursor(mk, revisionId, childBlockSize, filter.getPath());
+    public Cursor query(Filter filter, String revisionId, NodeState root) {
+        return new TraversingCursor(filter, root);
     }
 
     @Override

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/QueryIndex.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/QueryIndex.java?rev=1371168&r1=1371167&r2=1371168&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/QueryIndex.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/QueryIndex.java Thu Aug  9 11:35:58 2012
@@ -18,6 +18,8 @@
  */
 package org.apache.jackrabbit.oak.spi;
 
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+
 /**
  * Represents an index. The index should use the data in the filter if possible
  * to speed up reading.
@@ -39,9 +41,10 @@ public interface QueryIndex {
      *
      * @param filter the filter
      * @param revisionId the revision
+     * @param root root state of the given revision
      * @return a cursor to iterate over the result
      */
-    Cursor query(Filter filter, String revisionId);
+    Cursor query(Filter filter, String revisionId, NodeState root);
 
     /**
      * Get the query plan for the given filter.

Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/lucene/LuceneEditorTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/lucene/LuceneEditorTest.java?rev=1371168&r1=1371167&r2=1371168&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/lucene/LuceneEditorTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/lucene/LuceneEditorTest.java Thu Aug  9 11:35:58 2012
@@ -59,7 +59,7 @@ public class LuceneEditorTest {
                 "foo",
                 Operator.EQUAL,
                 MemoryValueFactory.INSTANCE.createValue("bar"));
-        Cursor cursor = index.query(filter, null);
+        Cursor cursor = index.query(filter, null, store.getRoot());
         assertTrue(cursor.next());
         assertEquals("/", cursor.currentPath());
         assertFalse(cursor.next());

Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/index/TraversingCursorTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/index/TraversingCursorTest.java?rev=1371168&r1=1371167&r2=1371168&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/index/TraversingCursorTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/index/TraversingCursorTest.java Thu Aug  9 11:35:58 2012
@@ -26,6 +26,7 @@ import java.util.Collections;
 import java.util.List;
 import org.apache.jackrabbit.mk.api.MicroKernel;
 import org.apache.jackrabbit.mk.core.MicroKernelImpl;
+import org.apache.jackrabbit.oak.kernel.KernelNodeState;
 import org.apache.jackrabbit.oak.spi.Cursor;
 import org.junit.Test;
 
@@ -34,22 +35,11 @@ import org.junit.Test;
  */
 public class TraversingCursorTest {
 
-    private final MicroKernel mk = new MicroKernelImpl();
-
     @Test
     public void traverse() throws Exception {
-        TraversingIndex t = new TraversingIndex(mk);
-        traverse(t);
-    }
-
-    @Test
-    public void traverseBlockwise() throws Exception {
-        TraversingIndex t = new TraversingIndex(mk);
-        t.setChildBlockSize(2);
-        traverse(t);
-    }
+        TraversingIndex t = new TraversingIndex();
 
-    private void traverse(TraversingIndex t) {
+        MicroKernel mk = new MicroKernelImpl();
         String head = mk.getHeadRevision();
         head = mk.commit("/", "+ \"parents\": { \"p0\": {\"id\": \"0\"}, \"p1\": {\"id\": \"1\"}, \"p2\": {\"id\": \"2\"}}", head, "");
         head = mk.commit("/", "+ \"children\": { \"c1\": {\"p\": \"1\"}, \"c2\": {\"p\": \"1\"}, \"c3\": {\"p\": \"2\"}, \"c4\": {\"p\": \"3\"}}", head, "");
@@ -57,7 +47,7 @@ public class TraversingCursorTest {
 
         f.setPath("/");
         List<String> paths = new ArrayList<String>();
-        Cursor c = t.query(f, head);
+        Cursor c = t.query(f, head, new KernelNodeState(mk, "/", head));
         while (c.next()) {
             paths.add(c.currentPath());
         }
@@ -72,7 +62,7 @@ public class TraversingCursorTest {
         assertFalse(c.next());
 
         f.setPath("/nowhere");
-        c = t.query(f, head);
+        c = t.query(f, head, new KernelNodeState(mk, "/", head));
         assertFalse(c.next());
         // endure it stays false
         assertFalse(c.next());