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 th...@apache.org on 2014/04/01 15:16:15 UTC

svn commit: r1583658 - in /jackrabbit/oak/trunk/oak-core/src: main/java/org/apache/jackrabbit/oak/spi/query/Cursors.java test/java/org/apache/jackrabbit/oak/spi/query/ test/java/org/apache/jackrabbit/oak/spi/query/CursorsTest.java

Author: thomasm
Date: Tue Apr  1 13:16:15 2014
New Revision: 1583658

URL: http://svn.apache.org/r1583658
Log:
OAK-1654 Composite index aggregates (helper class)

Added:
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/query/
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/query/CursorsTest.java
Modified:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/query/Cursors.java

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/query/Cursors.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/query/Cursors.java?rev=1583658&r1=1583657&r2=1583658&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/query/Cursors.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/query/Cursors.java Tue Apr  1 13:16:15 2014
@@ -17,6 +17,7 @@
 package org.apache.jackrabbit.oak.spi.query;
 
 import java.util.Deque;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
 
@@ -51,6 +52,10 @@ public class Cursors {
 
     private Cursors() {
     }
+    
+    public static Cursor newIntersectionCursor(Cursor a, Cursor b, QueryEngineSettings settings) {
+        return new IntersectionCursor(a, b, settings);
+    }
 
     /**
      * Creates a {@link Cursor} over paths.
@@ -328,4 +333,85 @@ public class Cursors {
         }
 
     }
+    
+    /**
+     * A cursor that intersects two cursors.
+     */
+    private static class IntersectionCursor extends AbstractCursor {
+
+        private final HashMap<String, IndexRow> secondSet = new HashMap<String, IndexRow>();
+        private final HashSet<String> seen = new HashSet<String>();
+        private final Cursor first, second;
+        private final QueryEngineSettings settings;
+        private boolean init;
+        private boolean closed;
+        private IndexRow current;
+        
+        IntersectionCursor(Cursor first, Cursor second, QueryEngineSettings settings) {
+            this.first = first;
+            this.second = second;
+            this.settings = settings;
+        }
+        
+        @Override
+        public IndexRow next() {
+            if (closed) {
+                throw new IllegalStateException("This cursor is closed");
+            }
+            if (!init) {
+                fetchNext();
+                init = true;
+            }
+            IndexRow result = current;
+            fetchNext();
+            return result;
+        }
+
+        @Override
+        public boolean hasNext() {
+            if (!closed && !init) {
+                fetchNext();
+                init = true;
+            }
+            return !closed;
+        }
+        
+        private void fetchNext() {
+            while (true) {
+                if (!first.hasNext()) {
+                    closed = true;
+                    return;
+                }
+                IndexRow c = first.next();
+                String p = c.getPath();
+                if (seen.contains(p)) {
+                    continue;
+                }
+                if (secondSet.remove(p) != null) {
+                    current = c;
+                    markSeen(p);
+                    return;
+                }
+                while (second.hasNext()) {
+                    IndexRow s = second.next();
+                    String p2 = s.getPath();
+                    if (p.equals(p2)) {
+                        current = c;
+                        markSeen(p);
+                        return;
+                    }
+                    secondSet.put(p2, s);
+                    FilterIterators.checkMemoryLimit(secondSet.size(), settings.getLimitInMemory());
+                }                    
+                closed = true;
+            }
+        }
+        
+        private void markSeen(String path) {
+            seen.add(path);
+            FilterIterators.checkMemoryLimit(seen.size(), settings.getLimitInMemory());
+        }
+        
+    }
+    
 }

Added: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/query/CursorsTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/query/CursorsTest.java?rev=1583658&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/query/CursorsTest.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/query/CursorsTest.java Tue Apr  1 13:16:15 2014
@@ -0,0 +1,131 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      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.apache.jackrabbit.oak.spi.query;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.fail;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+
+import org.apache.jackrabbit.oak.api.PropertyValue;
+import org.apache.jackrabbit.oak.query.QueryEngineSettings;
+import org.junit.Test;
+
+/**
+ * Tests the cursors implementations.
+ */
+public class CursorsTest {
+
+    @Test
+    public void intersectionCursor() {
+        QueryEngineSettings s = new QueryEngineSettings();
+        Cursor a = new SimpleCursor("1:", "/b", "/c", "/e", "/e", "/c");
+        Cursor b = new SimpleCursor("2:", "/a", "/c", "/d", "/b", "/c");
+        Cursor c = Cursors.newIntersectionCursor(a, b, s);
+        assertEquals("1:/b, 1:/c", list(c));
+        assertFalse(c.hasNext());
+    }
+
+    @Test
+    public void intersectionCursorExceptions() {
+        QueryEngineSettings s = new QueryEngineSettings();
+        Cursor a = new SimpleCursor("1:", "/b", "/c", "/e", "/e", "/c");
+        Cursor b = new SimpleCursor("2:", "/a", "/c", "/d", "/b", "/c");
+        Cursor c = Cursors.newIntersectionCursor(a, b, s);
+        c.next();
+        c.next();
+        try {
+            c.remove();
+            fail();
+        } catch (UnsupportedOperationException e) {
+            // expected
+        }
+        try {
+            c.next();
+            fail();
+        } catch (IllegalStateException e) {
+            // expected
+        }
+    }
+
+    static String list(Cursor c) {
+        StringBuilder buff = new StringBuilder();
+        while (c.hasNext()) {
+            buff.append(buff.length() == 0 ? "" : ", ");
+            buff.append(c.next());
+        }
+        return buff.toString();
+    }
+    
+    static class SimpleCursor implements Cursor {
+        
+        final Iterator<IndexRow> rows;
+        
+        SimpleCursor(String idPrefix, String... paths) {
+            ArrayList<IndexRow> list = new ArrayList<IndexRow>();
+            for (String p : paths) {
+                list.add(new SimpleIndexRow(p, idPrefix + p));
+            }
+            rows = list.iterator();
+        }
+
+        @Override
+        public boolean hasNext() {
+            return rows.hasNext();
+        }
+
+        @Override
+        public void remove() {
+            rows.remove();
+        }
+
+        @Override
+        public IndexRow next() {
+            return rows.next();
+        }
+        
+    }
+    
+    static class SimpleIndexRow implements IndexRow {
+        
+        final String path;
+        final String id;
+        
+        SimpleIndexRow(String path, String id) {
+            this.path = path;
+            this.id = id;
+        }
+
+        @Override
+        public String getPath() {
+            return path;
+        }
+
+        @Override
+        public PropertyValue getValue(String columnName) {
+            return null;
+        }
+        
+        @Override
+        public String toString() {
+            return id;
+        }
+        
+    }
+}