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 2015/06/03 16:22:04 UTC

svn commit: r1683343 - in /jackrabbit/oak/trunk: oak-core/src/main/java/org/apache/jackrabbit/oak/api/ oak-core/src/main/java/org/apache/jackrabbit/oak/query/ oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/ oak-core/src/main/java/org/apache...

Author: thomasm
Date: Wed Jun  3 14:22:03 2015
New Revision: 1683343

URL: http://svn.apache.org/r1683343
Log:
OAK-2926 Fast result size estimate

Added:
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/segment/SegmentIdTableBenchmark.java
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/UtilsTest.java
    jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/SizeEstimator.java
    jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/jcr/query/ResultSizeTest.java
Modified:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/Result.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/package-info.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/QueryImpl.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/UnionQueryImpl.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/package-info.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/query/Cursor.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/query/Cursors.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/query/package-info.java
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/AbstractQueryTest.java
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/query/CursorsTest.java
    jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/query/PrefetchIterator.java
    jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/query/QueryResultImpl.java
    jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/query/PrefetchIteratorTest.java
    jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndex.java
    jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LucenePropertyIndex.java
    jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/query/SolrQueryIndex.java

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/Result.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/Result.java?rev=1683343&r1=1683342&r2=1683343&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/Result.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/Result.java Wed Jun  3 14:22:03 2015
@@ -59,4 +59,43 @@ public interface Result {
      */
     long getSize();
 
+    /**
+     * Get the number of rows, if known. If the size is not known, -1 is
+     * returned.
+     * 
+     * @param precision the required precision
+     * @param max the maximum number that should be returned (Long.MAX_VALUE for
+     *            unlimited). For EXACT, the cost of the operation is at most
+     *            O(max). For approximations, the cost of the operation should
+     *            be at most O(log max).
+     * @return the (approximate) size. If an implementation does know the exact
+     *         value, it returns it (even if the value is higher than max). If
+     *         the implementation does not know the value, and the child node
+     *         count is higher than max, it returns Long.MAX_VALUE.
+     */
+    long getSize(SizePrecision precision, long max);
+    
+    enum SizePrecision {
+   
+        /**
+         * If the exact number is needed.
+         */
+        EXACT,
+        
+        /**
+         * If a good, and secure estimate is needed (the actual number can be
+         * lower or higher). This is supposed to be faster than exact count, but
+         * slower than a fast approximation.
+         */
+        APPROXIMATION,
+        
+        /**
+         * If a rough estimate is needed (the actual number can be lower or
+         * higher). This is supposed to be faster than a good approximation. It
+         * could be (for example) the expected cost of the query.
+         */
+        FAST_APPROXIMATION,
+        
+    }
+
 }

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/package-info.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/package-info.java?rev=1683343&r1=1683342&r2=1683343&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/package-info.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/package-info.java Wed Jun  3 14:22:03 2015
@@ -18,7 +18,7 @@
 /**
  * Oak repository API
  */
-@Version("1.0")
+@Version("2.0")
 @Export(optional = "provide:=true")
 package org.apache.jackrabbit.oak.api;
 

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=1683343&r1=1683342&r2=1683343&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 Wed Jun  3 14:22:03 2015
@@ -55,7 +55,21 @@ public interface Query {
 
     Iterator<ResultRowImpl> getRows();
 
+    /**
+     * Get the size if known.
+     * 
+     * @return the size, or -1 if unknown
+     */
     long getSize();
+    
+    /**
+     * Get the size if known.
+     * 
+     * @param precision the required precision
+     * @param max the maximum nodes read (for an exact size)
+     * @return the size, or -1 if unknown
+     */
+    long getSize(Result.SizePrecision precision, long max);
 
     void setExplain(boolean explain);
 

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryImpl.java?rev=1683343&r1=1683342&r2=1683343&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryImpl.java Wed Jun  3 14:22:03 2015
@@ -13,6 +13,7 @@
  */
 package org.apache.jackrabbit.oak.query;
 
+import java.math.BigInteger;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Comparator;
@@ -25,6 +26,7 @@ import java.util.Set;
 import org.apache.jackrabbit.oak.api.PropertyValue;
 import org.apache.jackrabbit.oak.api.Tree;
 import org.apache.jackrabbit.oak.api.Type;
+import org.apache.jackrabbit.oak.api.Result.SizePrecision;
 import org.apache.jackrabbit.oak.namepath.JcrPathParser;
 import org.apache.jackrabbit.oak.namepath.NamePathMapper;
 import org.apache.jackrabbit.oak.query.ast.AndImpl;
@@ -979,6 +981,12 @@ public class QueryImpl implements Query
     public long getSize() {
         return size;
     }
+    
+    @Override
+    public long getSize(SizePrecision precision, long max) {
+        // Note: DISTINCT is ignored
+        return Math.min(limit, source.getSize(precision, max));
+    }
 
     public String getStatement() {
         return statement;
@@ -996,5 +1004,20 @@ public class QueryImpl implements Query
     public ExecutionContext getExecutionContext() {
         return context;
     }
+    
+    /**
+     * Add two values, but don't let it overflow or underflow.
+     * 
+     * @param x the first value
+     * @param y the second value
+     * @return the sum, or Long.MIN_VALUE for underflow, or Long.MAX_VALUE for
+     *         overflow
+     */
+    public static long saturatedAdd(long x, long y) {
+        BigInteger min = BigInteger.valueOf(Long.MIN_VALUE);
+        BigInteger max = BigInteger.valueOf(Long.MAX_VALUE);
+        BigInteger sum = BigInteger.valueOf(x).add(BigInteger.valueOf(y));
+        return sum.min(max).max(min).longValue();
+    }
 
 }

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=1683343&r1=1683342&r2=1683343&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 Wed Jun  3 14:22:03 2015
@@ -80,4 +80,9 @@ public class ResultImpl implements Resul
         return query.getSize();
     }
 
+    @Override
+    public long getSize(SizePrecision precision, long max) {
+        return query.getSize(precision, max);
+    }
+
 }

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/UnionQueryImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/UnionQueryImpl.java?rev=1683343&r1=1683342&r2=1683343&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/UnionQueryImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/UnionQueryImpl.java Wed Jun  3 14:22:03 2015
@@ -22,6 +22,7 @@ import java.util.List;
 
 import org.apache.jackrabbit.oak.api.PropertyValue;
 import org.apache.jackrabbit.oak.api.Result;
+import org.apache.jackrabbit.oak.api.Result.SizePrecision;
 import org.apache.jackrabbit.oak.api.Tree;
 import org.apache.jackrabbit.oak.query.ast.ColumnImpl;
 import org.apache.jackrabbit.oak.query.ast.OrderingImpl;
@@ -144,7 +145,16 @@ public class UnionQueryImpl implements Q
     public long getSize() {
         return size;
     }
-
+    
+    @Override
+    public long getSize(SizePrecision precision, long max) {
+        // Note: this does not respect the "unionAll == false" case
+        // (this can result in a larger reported size, but it is not a security problem)
+        return QueryImpl.saturatedAdd(
+                left.getSize(precision, max),
+                right.getSize(precision, max));
+    }
+    
     @Override
     public void setExplain(boolean explain) {
         this.explain = explain;

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=1683343&r1=1683342&r2=1683343&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 Wed Jun  3 14:22:03 2015
@@ -16,6 +16,7 @@ package org.apache.jackrabbit.oak.query.
 import java.util.ArrayList;
 import java.util.List;
 
+import org.apache.jackrabbit.oak.api.Result.SizePrecision;
 import org.apache.jackrabbit.oak.query.plan.ExecutionPlan;
 import org.apache.jackrabbit.oak.query.plan.JoinExecutionPlan;
 import org.apache.jackrabbit.oak.spi.query.Filter;
@@ -266,4 +267,10 @@ public class JoinImpl extends SourceImpl
         return left.isOuterJoinRightHandSide() || right.isOuterJoinRightHandSide();
     }
 
+    @Override
+    public long getSize(SizePrecision precision, long max) {
+        // we don't know
+        return -1;
+    }
+
 }

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=1683343&r1=1683342&r2=1683343&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 Wed Jun  3 14:22:03 2015
@@ -41,6 +41,7 @@ import javax.annotation.Nonnull;
 
 import org.apache.jackrabbit.oak.api.PropertyState;
 import org.apache.jackrabbit.oak.api.PropertyValue;
+import org.apache.jackrabbit.oak.api.Result.SizePrecision;
 import org.apache.jackrabbit.oak.api.Tree;
 import org.apache.jackrabbit.oak.api.Type;
 import org.apache.jackrabbit.oak.commons.PathUtils;
@@ -752,4 +753,12 @@ public class SelectorImpl extends Source
         return query;
     }
 
+    @Override
+    public long getSize(SizePrecision precision, long max) {
+        if (cursor == null) {
+            return -1;
+        }
+        return cursor.getSize(precision, max);
+    }
+    
 }

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=1683343&r1=1683342&r2=1683343&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 Wed Jun  3 14:22:03 2015
@@ -21,6 +21,7 @@ package org.apache.jackrabbit.oak.query.
 import java.util.Collections;
 import java.util.List;
 
+import org.apache.jackrabbit.oak.api.Result.SizePrecision;
 import org.apache.jackrabbit.oak.query.plan.ExecutionPlan;
 import org.apache.jackrabbit.oak.spi.query.Filter;
 import org.apache.jackrabbit.oak.spi.state.NodeState;
@@ -153,4 +154,13 @@ public abstract class SourceImpl extends
      */
     public abstract boolean isOuterJoinRightHandSide();
 
+    /**
+     * Get the size if known.
+     * 
+     * @param precision the required precision
+     * @param max the maximum nodes read (for an exact size)
+     * @return the size, or -1 if unknown
+     */
+    public abstract long getSize(SizePrecision precision, long max);
+
 }

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/package-info.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/package-info.java?rev=1683343&r1=1683342&r2=1683343&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/package-info.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/package-info.java Wed Jun  3 14:22:03 2015
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-@Version("1.0")
+@Version("2.0")
 @Export(optional = "provide:=true")
 package org.apache.jackrabbit.oak.query;
 

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/query/Cursor.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/query/Cursor.java?rev=1683343&r1=1683342&r2=1683343&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/query/Cursor.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/query/Cursor.java Wed Jun  3 14:22:03 2015
@@ -20,6 +20,8 @@ package org.apache.jackrabbit.oak.spi.qu
 
 import java.util.Iterator;
 
+import org.apache.jackrabbit.oak.api.Result.SizePrecision;
+
 /**
  * A cursor to read a number of nodes sequentially.
  */
@@ -50,5 +52,14 @@ public interface Cursor extends Iterator
      */
     @Override
     IndexRow next();
+
+    /**
+     * Get the size if known.
+     * 
+     * @param precision the required precision
+     * @param max the maximum nodes read (for an exact size)
+     * @return the size, or -1 if unknown
+     */
+    long getSize(SizePrecision precision, long max);
     
 }

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=1683343&r1=1683342&r2=1683343&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 Wed Jun  3 14:22:03 2015
@@ -24,6 +24,7 @@ import java.util.List;
 
 import javax.annotation.Nullable;
 
+import org.apache.jackrabbit.oak.api.Result.SizePrecision;
 import org.apache.jackrabbit.oak.commons.PathUtils;
 import org.apache.jackrabbit.oak.plugins.memory.MemoryChildNodeEntry;
 import org.apache.jackrabbit.oak.query.FilterIterators;
@@ -124,6 +125,11 @@ public class Cursors {
             throw new UnsupportedOperationException();
         }
         
+        @Override
+        public long getSize(SizePrecision precision, long max) {
+            return -1;
+        }
+
     }
 
     /**

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/query/package-info.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/query/package-info.java?rev=1683343&r1=1683342&r2=1683343&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/query/package-info.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/query/package-info.java Wed Jun  3 14:22:03 2015
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-@Version("1.0.1")
+@Version("2.0.0")
 @Export(optional = "provide:=true")
 package org.apache.jackrabbit.oak.spi.query;
 

Added: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/segment/SegmentIdTableBenchmark.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/segment/SegmentIdTableBenchmark.java?rev=1683343&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/segment/SegmentIdTableBenchmark.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/segment/SegmentIdTableBenchmark.java Wed Jun  3 14:22:03 2015
@@ -0,0 +1,122 @@
+/*
+ * 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.plugins.segment;
+
+import java.lang.ref.WeakReference;
+import java.util.Random;
+
+import org.apache.jackrabbit.oak.plugins.segment.memory.MemoryStore;
+
+public class SegmentIdTableBenchmark {
+    public static void main(String... args) {
+        test();
+        test();
+        test();
+        test();
+        test();
+        test();
+    }
+
+    private static void test() {
+        long time;
+        int repeat = 10000;
+        int count = 10000;
+        
+        long[] array = new long[count];
+        Random r = new Random(1);
+        for (int i = 0; i < array.length; i++) {
+            array[i] = r.nextLong();
+        }
+        
+        time = System.currentTimeMillis();
+        SegmentTracker tracker = new MemoryStore().getTracker();
+        final SegmentIdTable tbl = new SegmentIdTable(tracker);
+        for (int i = 0; i < repeat; i++) {
+            for (int j = 0; j < count; j++) {
+                tbl.getSegmentId(j, array[j]);
+            }
+        }
+        time = System.currentTimeMillis() - time;
+        System.out.println("SegmentIdTable: " + time);
+        
+        time = System.currentTimeMillis();
+        ConcurrentTable cm = new ConcurrentTable(tracker, 16 * 1024);
+        for (int i = 0; i < repeat; i++) {
+            for (int j = 0; j < count; j++) {
+                cm.getSegmentId(j, array[j]);
+            }
+        }
+        time = System.currentTimeMillis() - time;
+        System.out.println("ConcurrentTable: " + time);
+        
+//        time = System.currentTimeMillis();
+//        WeakHashMap<SegmentId, SegmentId> map = new WeakHashMap<SegmentId, SegmentId>(count);
+//        for (int i = 0; i < repeat; i++) {
+//            for (int j = 0; j < count; j++) {
+//                SegmentId id = new SegmentId(tracker, j, j);
+//                if (map.get(id) == null) {
+//                    map.put(id, id);
+//                }
+//            }
+//        }
+//        time = System.currentTimeMillis() - time;
+//        System.out.println("WeakHashMap: " + time);
+    }
+    
+    static class ConcurrentTable {
+        private final SegmentTracker tracker;
+        volatile WeakReference<SegmentId>[] map;
+        @SuppressWarnings("unchecked")
+        ConcurrentTable(SegmentTracker tracker, int size) {
+            this.tracker = tracker;
+            map = (WeakReference<SegmentId>[]) new WeakReference[size];
+        }
+        SegmentId getSegmentId(long a, long b) {
+            outer:
+            while (true) {
+                int increment = 1;
+                WeakReference<SegmentId>[] m = map;
+                int length = m.length;
+                int index = (int) (b & (length - 1));
+                while (true) {
+                    WeakReference<SegmentId> ref = m[index];
+                    if (ref == null) {
+                        SegmentId id = new SegmentId(tracker, a, b);
+                        ref = new WeakReference<SegmentId>(id);
+                        m[index] = ref;
+                        if (m != map) {
+                            continue outer;
+                        }
+                        return id;
+                    }
+                    SegmentId id = ref.get();
+                    if (id != null) {
+                        if (id.getMostSignificantBits() == a && id.getLeastSignificantBits() == b) {
+                            return id;
+                        }
+                    }
+                    index = (index + increment) & (length - 1);
+                    increment += increment;
+                    if (increment > 100) {
+                        System.out.println("inc " + increment);
+                    }
+                }
+            }
+        }
+    }
+
+}

Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/AbstractQueryTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/AbstractQueryTest.java?rev=1683343&r1=1683342&r2=1683343&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/AbstractQueryTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/AbstractQueryTest.java Wed Jun  3 14:22:03 2015
@@ -39,6 +39,7 @@ import org.apache.jackrabbit.oak.api.Pro
 import org.apache.jackrabbit.oak.api.PropertyValue;
 import org.apache.jackrabbit.oak.api.QueryEngine;
 import org.apache.jackrabbit.oak.api.Result;
+import org.apache.jackrabbit.oak.api.Result.SizePrecision;
 import org.apache.jackrabbit.oak.api.ResultRow;
 import org.apache.jackrabbit.oak.api.Root;
 import org.apache.jackrabbit.oak.api.Tree;
@@ -265,6 +266,23 @@ public abstract class AbstractQueryTest
     protected List<String> assertQuery(String sql, List<String> expected) {
         return assertQuery(sql, SQL2, expected);
     }
+    
+    protected void assertResultSize(String query, String language, long expected) {
+        long time = System.currentTimeMillis();
+        try {
+            Result result = executeQuery(query, language, NO_BINDINGS);
+            // currently needed to iterate to really execute the query
+            result.getRows().iterator().hasNext();
+            long got = result.getSize(SizePrecision.APPROXIMATION, 0);
+            assertEquals(expected, got);
+        } catch (ParseException e) {
+            throw new RuntimeException(e);
+        }
+        time = System.currentTimeMillis() - time;
+        if (time > 10000 && !isDebugModeEnabled()) {
+            fail("Query took too long: " + query + " took " + time + " ms");
+        }
+    }
 
     protected List<String> assertQuery(String sql, String language,
             List<String> expected) {

Added: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/UtilsTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/UtilsTest.java?rev=1683343&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/UtilsTest.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/UtilsTest.java Wed Jun  3 14:22:03 2015
@@ -0,0 +1,61 @@
+/*
+ * 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.query;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.Random;
+
+import org.junit.Test;
+
+public class UtilsTest {
+
+    @Test
+    public void saturatedAdd() {
+        assertEquals(3, QueryImpl.saturatedAdd(1, 2));
+        assertEquals(Long.MAX_VALUE, QueryImpl.saturatedAdd(1, Long.MAX_VALUE));
+        assertEquals(Long.MAX_VALUE, QueryImpl.saturatedAdd(Long.MAX_VALUE, 1));
+        assertEquals(Long.MAX_VALUE, QueryImpl.saturatedAdd(Long.MAX_VALUE, Long.MAX_VALUE));
+        long[] test = {Long.MIN_VALUE, Long.MIN_VALUE + 1, Long.MIN_VALUE + 10, 
+            -1000, -10, -1, 0, 1, 3, 10000,
+            Long.MAX_VALUE - 20, Long.MAX_VALUE - 1, Long.MAX_VALUE};
+        Random r = new Random(1);
+        for (int i = 0; i < 10000; i++) {
+            long x = r.nextBoolean() ? test[r.nextInt(test.length)] : r
+                    .nextLong();
+            long y = r.nextBoolean() ? test[r.nextInt(test.length)] : r
+                    .nextLong();
+            long alt = altSaturatedAdd(x, y);
+            long got = QueryImpl.saturatedAdd(x, y);
+            assertEquals(x + "+" + y, alt, got);
+        }
+    }
+
+    private static long altSaturatedAdd(long x, long y) {
+        // see also http://stackoverflow.com/questions/2632392/saturated-addition-of-two-signed-java-long-values
+        if (x > 0 != y > 0) {
+            // different signs
+            return x + y;
+        } else if (x > 0) {
+            // can overflow
+            return Long.MAX_VALUE - x < y ? Long.MAX_VALUE : x + y;
+        } else {
+            // can underflow
+            return Long.MIN_VALUE - x > y ? Long.MIN_VALUE : x + y;
+        }
+    }
+}

Modified: 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=1683343&r1=1683342&r2=1683343&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/query/CursorsTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/query/CursorsTest.java Wed Jun  3 14:22:03 2015
@@ -24,6 +24,7 @@ import java.util.ArrayList;
 import java.util.Iterator;
 
 import org.apache.jackrabbit.oak.api.PropertyValue;
+import org.apache.jackrabbit.oak.api.Result.SizePrecision;
 import org.apache.jackrabbit.oak.query.QueryEngineSettings;
 import org.junit.Test;
 
@@ -99,6 +100,11 @@ public class CursorsTest {
         public IndexRow next() {
             return rows.next();
         }
+
+        @Override
+        public long getSize(SizePrecision precision, long max) {
+            return -1;
+        }
         
     }
     

Modified: 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=1683343&r1=1683342&r2=1683343&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/query/PrefetchIterator.java (original)
+++ jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/query/PrefetchIterator.java Wed Jun  3 14:22:03 2015
@@ -22,6 +22,9 @@ import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.NoSuchElementException;
 
+import org.apache.jackrabbit.oak.api.Result;
+import org.apache.jackrabbit.oak.api.Result.SizePrecision;
+
 /**
  * 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,
@@ -33,7 +36,11 @@ import java.util.NoSuchElementException;
  * @param <K> the iterator data type
  */
 public class PrefetchIterator<K> implements Iterator<K> {
-
+    
+    private final boolean fastSize = Boolean.getBoolean("oak.fastQuerySize");
+    
+    private final Result result;
+    
     private final Iterator<K> it;
     private final long minPrefetch, timeout, maxPrefetch;
     private boolean prefetchDone;
@@ -48,13 +55,19 @@ public class PrefetchIterator<K> impleme
      * @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)
+     * @param result (optional) the result to get the size from
      */
-    PrefetchIterator(Iterator<K> it, long min, long timeout, long max, long size) {
+    PrefetchIterator(Iterator<K> it, long min, long timeout, long max, 
+            long size, Result result) {
         this.it = it;
         this.minPrefetch = min;
+        if (fastSize) {
+            timeout = 0;
+        }
         this.timeout = timeout;
         this.maxPrefetch = max;
         this.size = size;
+        this.result = result;
     }
 
     @Override
@@ -97,9 +110,14 @@ public class PrefetchIterator<K> impleme
      * @return the size, or -1 if unknown
      */
     public long size() {
-        if (size != -1 || prefetchDone || position > maxPrefetch) {
+        if (size != -1) {
             return size;
         }
+        if (!fastSize) {
+            if (prefetchDone || position > maxPrefetch) {
+                return -1;
+            }
+        }
         prefetchDone = true;
         ArrayList<K> list = new ArrayList<K>();
         long end;
@@ -126,6 +144,11 @@ public class PrefetchIterator<K> impleme
             prefetchIterator = list.iterator();
             position -= list.size();
         }
+        if (size == -1 && fastSize) {
+            if (result != null) {
+                size = result.getSize(SizePrecision.EXACT, Long.MAX_VALUE);
+            }
+        }
         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=1683343&r1=1683342&r2=1683343&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 Jun  3 14:22:03 2015
@@ -137,7 +137,7 @@ public class QueryResultImpl implements
         final PrefetchIterator<RowImpl> prefIt = new  PrefetchIterator<RowImpl>(
                 sessionDelegate.sync(rowIterator),
                 PREFETCH_MIN, PREFETCH_TIMEOUT, PREFETCH_MAX, 
-                result.getSize());
+                result.getSize(), result);
         return new RowIteratorAdapter(prefIt) {
             @Override
             public long getSize() {
@@ -151,9 +151,8 @@ public class QueryResultImpl implements
         if (tree != null && tree.exists()) {
             NodeDelegate node = new NodeDelegate(sessionDelegate, tree);
             return NodeImpl.createNode(node, sessionContext);
-        } else {
-            return null;
         }
+        return null;
     }
 
     @Override
@@ -217,8 +216,8 @@ public class QueryResultImpl implements
         };
         final PrefetchIterator<NodeImpl<? extends NodeDelegate>> prefIt = new  PrefetchIterator<NodeImpl<? extends NodeDelegate>>(
                 sessionDelegate.sync(nodeIterator),
-                PREFETCH_MIN, PREFETCH_TIMEOUT, PREFETCH_MAX,
-                result.getSize());
+                PREFETCH_MIN, PREFETCH_TIMEOUT, PREFETCH_MAX, 
+                result.getSize(), result);
         return new NodeIteratorAdapter(prefIt) {
             @Override
             public long getSize() {

Modified: 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=1683343&r1=1683342&r2=1683343&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/query/PrefetchIteratorTest.java (original)
+++ jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/query/PrefetchIteratorTest.java Wed Jun  3 14:22:03 2015
@@ -36,7 +36,7 @@ public class PrefetchIteratorTest {
         Iterable<Integer> s;
         PrefetchIterator<Integer> it;
         s = seq(0, 100);
-        it = new PrefetchIterator<Integer>(s.iterator(), 5, 0, 10, 200);
+        it = new PrefetchIterator<Integer>(s.iterator(), 5, 0, 10, 200, null);
         // reports the 'wrong' value as it was set manually
         assertEquals(200, it.size());
     }
@@ -49,12 +49,12 @@ public class PrefetchIteratorTest {
         // long delay (10 ms per row)
         long timeout = 10;
         s = seq(0, 100, 10);
-        it = new PrefetchIterator<Integer>(s.iterator(), 5, timeout, 1000, -1);
+        it = new PrefetchIterator<Integer>(s.iterator(), 5, timeout, 1000, -1, null);
         assertEquals(-1, it.size());
 
         // no delay
         s = seq(0, 100);
-        it = new PrefetchIterator<Integer>(s.iterator(), 5, timeout, 1000, -1);
+        it = new PrefetchIterator<Integer>(s.iterator(), 5, timeout, 1000, -1, null);
         assertEquals(100, it.size());
     }
 
@@ -68,7 +68,7 @@ public class PrefetchIteratorTest {
                 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);
+                        new PrefetchIterator<Integer>(s.iterator(), 20, timeout, 30, -1, null);
                 for (int x : seq(0, readBefore)) {
                     boolean hasNext = it.hasNext();
                     if (!hasNext) {

Modified: jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndex.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndex.java?rev=1683343&r1=1683342&r2=1683343&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndex.java (original)
+++ jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndex.java Wed Jun  3 14:22:03 2015
@@ -56,6 +56,7 @@ import com.google.common.collect.Sets;
 
 import org.apache.jackrabbit.JcrConstants;
 import org.apache.jackrabbit.oak.api.PropertyValue;
+import org.apache.jackrabbit.oak.api.Result.SizePrecision;
 import org.apache.jackrabbit.oak.plugins.index.aggregate.NodeAggregator;
 import org.apache.jackrabbit.oak.plugins.index.lucene.IndexDefinition.IndexingRule;
 import org.apache.jackrabbit.oak.plugins.index.lucene.util.MoreLikeThisHelper;
@@ -1132,6 +1133,12 @@ public class LuceneIndex implements Adva
 
             };
         }
+
+        @Override
+        public long getSize(SizePrecision precision, long max) {
+            // not yet supported
+            return -1;
+        }
     }
 
     private static class PathStoredFieldVisitor extends StoredFieldVisitor {

Modified: jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LucenePropertyIndex.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LucenePropertyIndex.java?rev=1683343&r1=1683342&r2=1683343&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LucenePropertyIndex.java (original)
+++ jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LucenePropertyIndex.java Wed Jun  3 14:22:03 2015
@@ -38,6 +38,7 @@ import com.google.common.collect.Lists;
 import com.google.common.collect.Queues;
 import com.google.common.collect.Sets;
 import org.apache.jackrabbit.oak.api.PropertyValue;
+import org.apache.jackrabbit.oak.api.Result.SizePrecision;
 import org.apache.jackrabbit.oak.api.Type;
 import org.apache.jackrabbit.oak.commons.PathUtils;
 import org.apache.jackrabbit.oak.plugins.index.aggregate.NodeAggregator;
@@ -92,6 +93,7 @@ import org.apache.lucene.search.SortFiel
 import org.apache.lucene.search.TermQuery;
 import org.apache.lucene.search.TermRangeQuery;
 import org.apache.lucene.search.TopDocs;
+import org.apache.lucene.search.TotalHitCountCollector;
 import org.apache.lucene.search.WildcardQuery;
 import org.apache.lucene.search.spell.SuggestWord;
 import org.apache.lucene.search.suggest.Lookup;
@@ -449,7 +451,31 @@ public class LucenePropertyIndex impleme
                 this.lastSearchIndexerVersion = currentVersion;
             }
         };
-        return new LucenePathCursor(itr, plan, settings);
+        SizeEstimator sizeEstimator = new SizeEstimator() {
+            @Override
+            public long getSize() {
+                IndexNode indexNode = acquireIndexNode(plan);
+                checkState(indexNode != null);
+                try {
+                    IndexSearcher searcher = indexNode.getSearcher();
+                    LuceneRequestFacade luceneRequestFacade = getLuceneRequest(plan, searcher.getIndexReader());
+                    if (luceneRequestFacade.getLuceneRequest() instanceof Query) {
+                        Query query = (Query) luceneRequestFacade.getLuceneRequest();
+                        LOG.debug("estimate size for query " + query);
+                        TotalHitCountCollector collector = new TotalHitCountCollector();
+                        searcher.search(query, collector);
+                        return collector.getTotalHits();
+                    }
+                    LOG.debug("estimate size: not a Query: " + luceneRequestFacade.getLuceneRequest());
+                } catch (IOException e) {
+                    LOG.warn("query via {} failed.", LucenePropertyIndex.this, e);
+                } finally {
+                    indexNode.release();
+                }
+                return -1;
+            }
+        };
+        return new LucenePathCursor(itr, plan, settings, sizeEstimator);
     }
 
     @Override
@@ -1169,9 +1195,12 @@ public class LucenePropertyIndex impleme
         private final Cursor pathCursor;
         private final String pathPrefix;
         LuceneResultRow currentRow;
+        private final SizeEstimator sizeEstimator;
+        private long estimatedSize;
 
-        LucenePathCursor(final Iterator<LuceneResultRow> it, final IndexPlan plan, QueryEngineSettings settings) {
+        LucenePathCursor(final Iterator<LuceneResultRow> it, final IndexPlan plan, QueryEngineSettings settings, SizeEstimator sizeEstimator) {
             pathPrefix = plan.getPathPrefix();
+            this.sizeEstimator = sizeEstimator;
             Iterator<String> pathIterator = new Iterator<String>() {
 
                 @Override
@@ -1234,6 +1263,15 @@ public class LucenePropertyIndex impleme
 
             };
         }
+
+
+        @Override
+        public long getSize(SizePrecision precision, long max) {
+            if (estimatedSize != 0) {
+                return estimatedSize;
+            }
+            return estimatedSize = sizeEstimator.getSize();
+        }
     }
 
     private static class PathStoredFieldVisitor extends StoredFieldVisitor {

Added: jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/SizeEstimator.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/SizeEstimator.java?rev=1683343&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/SizeEstimator.java (added)
+++ jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/SizeEstimator.java Wed Jun  3 14:22:03 2015
@@ -0,0 +1,30 @@
+/*
+ * 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.plugins.index.lucene;
+
+public interface SizeEstimator {
+
+    /**
+     * Get the estimated size, or -1 if not known.
+     * 
+     * @return the size
+     */
+    long getSize();
+    
+}

Added: jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/jcr/query/ResultSizeTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/jcr/query/ResultSizeTest.java?rev=1683343&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/jcr/query/ResultSizeTest.java (added)
+++ jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/jcr/query/ResultSizeTest.java Wed Jun  3 14:22:03 2015
@@ -0,0 +1,62 @@
+/*
+ * 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 javax.jcr.Node;
+import javax.jcr.Session;
+import javax.jcr.query.Query;
+import javax.jcr.query.QueryManager;
+
+import org.apache.jackrabbit.core.query.AbstractQueryTest;
+
+public class ResultSizeTest extends AbstractQueryTest {
+
+    public void testResultSize() throws Exception {
+        Session session = superuser;
+        QueryManager qm = session.getWorkspace().getQueryManager();
+        for (int i = 0; i < 200; i++) {
+            Node n = testRootNode.addNode("node" + i);
+            n.setProperty("text", "Hello World");
+        }
+        session.save();
+
+        String xpath = "/jcr:root//*[jcr:contains(@text, 'Hello World')]";
+        
+        Query q;
+        long result;
+        
+        // fast (insecure) case
+        System.setProperty("oak.fastQuerySize", "true");
+        q = qm.createQuery(xpath, "xpath");
+        result = q.execute().getRows().getSize();
+        assertTrue("size: " + result, result > 150 && result < 250);
+        
+        q = qm.createQuery(xpath, "xpath");
+        q.setLimit(90);
+        assertEquals(90, q.execute().getRows().getSize());
+        
+        // default (secure) case
+        System.clearProperty("oak.fastQuerySize");
+        q = qm.createQuery(xpath, "xpath");
+        result = q.execute().getRows().getSize();
+        assertEquals(-1, q.execute().getRows().getSize());
+
+    }
+    
+}
\ No newline at end of file

Modified: jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/query/SolrQueryIndex.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/query/SolrQueryIndex.java?rev=1683343&r1=1683342&r2=1683343&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/query/SolrQueryIndex.java (original)
+++ jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/query/SolrQueryIndex.java Wed Jun  3 14:22:03 2015
@@ -32,6 +32,7 @@ import com.google.common.collect.Iterabl
 import com.google.common.collect.Queues;
 import com.google.common.collect.Sets;
 import org.apache.jackrabbit.oak.api.PropertyValue;
+import org.apache.jackrabbit.oak.api.Result.SizePrecision;
 import org.apache.jackrabbit.oak.plugins.index.aggregate.NodeAggregator;
 import org.apache.jackrabbit.oak.plugins.index.solr.configuration.OakSolrConfiguration;
 import org.apache.jackrabbit.oak.query.QueryEngineSettings;
@@ -541,6 +542,12 @@ public class SolrQueryIndex implements F
 
             };
         }
+
+
+        @Override
+        public long getSize(SizePrecision precision, long max) {
+            return -1;
+        }
     }
 
     @Override