jackrabbit-oak-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From thom...@apache.org
Subject svn commit: r1387516 - in /jackrabbit/oak/trunk/oak-jcr/src: main/java/org/apache/jackrabbit/oak/jcr/query/ test/java/org/apache/jackrabbit/oak/jcr/query/
Date Wed, 19 Sep 2012 10:39:03 GMT
Author: thomasm
Date: Wed Sep 19 10:39:03 2012
New Revision: 1387516

URL: http://svn.apache.org/viewvc?rev=1387516&view=rev
Log:
OAK-300 Query: QueryResult.getRows().getSize()

Added:
    jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/query/PrefetchIterator.java
    jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/query/PrefetchIteratorTest.java
Modified:
    jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/query/QueryResultImpl.java

Added: jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/query/PrefetchIterator.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/query/PrefetchIterator.java?rev=1387516&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/query/PrefetchIterator.java
(added)
+++ jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/query/PrefetchIterator.java
Wed Sep 19 10:39:03 2012
@@ -0,0 +1,132 @@
+/*
+ * 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.jcr.query;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+/**
+ * An iterator that pre-fetches a number of items in order to calculate the size
+ * of the result if possible. This iterator loads at least a number of items,
+ * and then tries to load some more items until the timeout is reached or the
+ * maximum number of entries are read.
+ * <p>
+ * Prefeching is only done when size() is called.
+ * 
+ * @param <K> the iterator data type
+ */
+public class PrefetchIterator<K> implements Iterator<K> {
+
+    private final Iterator<K> it;
+    private final long minPrefetch, timeout, maxPrefetch;
+    private boolean prefetchDone;
+    private Iterator<K> prefetchIterator;
+    private long size, position;
+    
+    /**
+     * Create a new iterator.
+     * 
+     * @param it the base iterator
+     * @param min the minimum number of items to pre-fetch
+     * @param timeout the maximum time to pre-fetch in milliseconds
+     * @param max the maximum number of items to pre-fetch
+     * @param size the size (prefetching is only required if -1)
+     */
+    PrefetchIterator(Iterator<K> it, long min, long timeout, long max, long size) {
+        this.it = it;
+        this.minPrefetch = min;
+        this.timeout = timeout;
+        this.maxPrefetch = max;
+        this.size = size;
+    }
+    
+    @Override
+    public boolean hasNext() {
+        if (prefetchIterator != null) {
+            if (prefetchIterator.hasNext()) {
+                return true;
+            }
+            prefetchIterator = null;
+        }
+        boolean result = it.hasNext();
+        if (!result) {
+            size = position;
+        }
+        return result;
+    }
+
+    @Override
+    public K next() {
+        if (!hasNext()) {
+            throw new NoSuchElementException();
+        }
+        if (prefetchIterator != null) {
+            return prefetchIterator.next();
+        }
+        position++;
+        return it.next();
+    }
+
+    @Override
+    public void remove() {
+        throw new UnsupportedOperationException();
+    }
+    
+    /**
+     * Get the size if known. This call might pre-fetch data. The returned value
+     * is unknown if the actual size is larger than the number of pre-fetched
+     * elements, unless the end of the iterator has been reached already.
+     * 
+     * @return the size, or -1 if unknown
+     */
+    public long size() {
+        if (size != -1 || prefetchDone || position > maxPrefetch) {
+            return size;
+        }
+        prefetchDone = true;
+        ArrayList<K> list = new ArrayList<K>();
+        long end;
+        if (timeout <= 0) {
+            end = 0;
+        } else {
+            long nanos = System.nanoTime();
+            end = nanos + timeout * 1000 * 1000;
+        }
+        while (position <= maxPrefetch) {
+            if (position > minPrefetch) {
+                if (end == 0 || System.nanoTime() > end) {
+                    break;
+                }
+            }
+            if (!it.hasNext()) {
+                size = position;
+                break;
+            }
+            position++;
+            list.add(it.next());
+        }
+        if (list.size() > 0) {
+            prefetchIterator = list.iterator();
+            position -= list.size();
+        }
+        return size;
+    }
+
+}

Modified: jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/query/QueryResultImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/query/QueryResultImpl.java?rev=1387516&r1=1387515&r2=1387516&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/query/QueryResultImpl.java
(original)
+++ jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/query/QueryResultImpl.java
Wed Sep 19 10:39:03 2012
@@ -42,6 +42,21 @@ import org.apache.jackrabbit.oak.jcr.Ses
  * The implementation of the corresponding JCR interface.
  */
 public class QueryResultImpl implements QueryResult {
+    
+    /**
+     * The minimum number of rows / nodes to pre-fetch.
+     */ 
+    private static final int PREFETCH_MIN = 20;
+
+    /**
+     * The maximum number of rows / nodes to pre-fetch.
+     */
+    private static final int PREFETCH_MAX = 100;
+
+    /**
+     * The maximum number of milliseconds to prefetch rows / nodes.
+     */
+    private static final int PREFETCH_TIMEOUT = 100;
 
     final SessionDelegate sessionDelegate;
     final Result result;
@@ -124,9 +139,14 @@ public class QueryResultImpl implements 
             }
 
         };
-        return new RowIteratorAdapter(rowIterator) {
+        final PrefetchIterator<RowImpl> prefIt = new  PrefetchIterator<RowImpl>(
+                rowIterator, 
+                PREFETCH_MIN, PREFETCH_TIMEOUT, PREFETCH_MAX, 
+                result.getSize());
+        return new RowIteratorAdapter(prefIt) {
+            @Override
             public long getSize() {
-                return result.getSize();
+                return prefIt.size();
             }
         };
     }
@@ -195,7 +215,16 @@ public class QueryResultImpl implements 
             }
 
         };
-        return new NodeIteratorAdapter(nodeIterator, result.getSize());
+        final PrefetchIterator<NodeImpl> prefIt = new  PrefetchIterator<NodeImpl>(
+                nodeIterator, 
+                PREFETCH_MIN, PREFETCH_TIMEOUT, PREFETCH_MAX, 
+                result.getSize());
+        return new NodeIteratorAdapter(prefIt) {
+            @Override
+            public long getSize() {
+                return prefIt.size();
+            }
+        };
     }
 
     Value createValue(CoreValue value) {

Added: jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/query/PrefetchIteratorTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/query/PrefetchIteratorTest.java?rev=1387516&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/query/PrefetchIteratorTest.java
(added)
+++ jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/query/PrefetchIteratorTest.java
Wed Sep 19 10:39:03 2012
@@ -0,0 +1,168 @@
+/*
+ * 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.jcr.query;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+import org.junit.Test;
+
+/**
+ * Test the PrefetchIterator class.
+ */
+public class PrefetchIteratorTest {
+
+    @Test
+    public void testKnownSize() {
+        Iterable<Integer> s;
+        PrefetchIterator<Integer> it;
+        s = seq(0, 100);
+        it = new PrefetchIterator<Integer>(s.iterator(), 5, 0, 10, 200);
+        // reports the 'wrong' value as it was set manually
+        assertEquals(200, it.size());
+    }
+
+    @Test
+    public void testTimeout() {
+        Iterable<Integer> s;
+        PrefetchIterator<Integer> it;
+        
+        // long delay (10 ms per row)
+        long timeout = 10;
+        s = seq(0, 100, 10);
+        it = new PrefetchIterator<Integer>(s.iterator(), 5, timeout, 1000, -1);
+        assertEquals(-1, it.size());
+
+        // no delay
+        s = seq(0, 100);
+        it = new PrefetchIterator<Integer>(s.iterator(), 5, timeout, 1000, -1);
+        assertEquals(100, it.size());
+    }
+
+    @Test
+    public void test() {
+        // the following is the same as:
+        // for (int size = 0; size < 100; size++)
+        for (int size : seq(0, 100)) {
+            for (int readBefore : seq(0, 30)) {
+                // every 3th time, use a timeout
+                long timeout = size % 3 == 0 ? 100 : 0;
+                Iterable<Integer> s = seq(0, size);
+                PrefetchIterator<Integer> it = 
+                        new PrefetchIterator<Integer>(s.iterator(), 20, timeout, 30,
-1);
+                for (int x : seq(0, readBefore)) {
+                    boolean hasNext = it.hasNext();
+                    if (!hasNext) {
+                        assertEquals(x, size);
+                        break;
+                    }
+                    String m = "s:" + size + " b:" + readBefore + " x:" + x;
+                    assertTrue(m, hasNext);
+                    assertEquals(m, x, it.next().intValue());
+                }
+                String m = "s:" + size + " b:" + readBefore;
+                int max = timeout <= 0 ? 20 : 30;
+                if (size > max && readBefore <= size) {
+                    assertEquals(m, -1, it.size());
+                    // calling it twice must not change the result
+                    assertEquals(m, -1, it.size());
+                } else {
+                    assertEquals(m, size, it.size());
+                    // calling it twice must not change the result
+                    assertEquals(m, size, it.size());
+                }
+                for (int x : seq(readBefore, size)) {
+                    m = "s:" + size + " b:" + readBefore + " x:" + x;
+                    assertTrue(m, it.hasNext());
+                    assertEquals(m, x, it.next().intValue());
+                }
+                assertFalse(it.hasNext());
+                try {
+                    it.next();
+                    fail();
+                } catch (NoSuchElementException e) {
+                    // expected
+                }
+                try {
+                    it.remove();
+                    fail();
+                } catch (UnsupportedOperationException e) {
+                    // expected
+                }
+            }
+        }
+    }
+    
+    /**
+     * Create an integer sequence.
+     * 
+     * @param start the first value
+     * @param limit the last value + 1
+     * @return a sequence of the values [start .. limit-1]
+     */
+    private static Iterable<Integer> seq(final int start, final int limit) {
+        return seq(start, limit, 0);
+    }
+    
+    /**
+     * Create an integer sequence.
+     * 
+     * @param start the first value
+     * @param limit the last value + 1
+     * @param sleep the time to wait for each element
+     * @return a sequence of the values [start .. limit-1]
+     */
+    private static Iterable<Integer> seq(final int start, final int limit, final int
sleep) {
+        return new Iterable<Integer>() {
+            @Override
+            public Iterator<Integer> iterator() {
+                return new Iterator<Integer>() {
+                    int x = start;
+                    @Override
+                    public boolean hasNext() {
+                        return x < limit;
+                    }
+                    @Override
+                    public Integer next() {
+                        if (sleep > 0) {
+                            try {
+                                Thread.sleep(sleep);
+                            } catch (InterruptedException e) {
+                                // ignore
+                            }
+                        }
+                        return x++;
+                    }
+                    @Override
+                    public void remove() {
+                        throw new UnsupportedOperationException();
+                    }
+                };
+            }
+            @Override
+            public String toString() {
+                return "[" + start + ".." + (limit - 1) + "]";
+            }
+        };
+    }
+    
+}



Mime
View raw message