You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@geode.apache.org by mk...@apache.org on 2021/11/15 07:09:19 UTC

[geode] branch develop updated: GEODE-9632: Allow INDEX_THRESHOLD_SIZE System property to override CompiledValue.RESULT_LIMIT (#7010)

This is an automated email from the ASF dual-hosted git repository.

mkevo pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/geode.git


The following commit(s) were added to refs/heads/develop by this push:
     new 67359dc  GEODE-9632: Allow INDEX_THRESHOLD_SIZE System property to override CompiledValue.RESULT_LIMIT (#7010)
67359dc is described below

commit 67359dcd3eb0f0ea00ea751f7770ecb3b1750386
Author: Mario Kevo <48...@users.noreply.github.com>
AuthorDate: Mon Nov 15 08:08:09 2021 +0100

    GEODE-9632: Allow INDEX_THRESHOLD_SIZE System property to override CompiledValue.RESULT_LIMIT (#7010)
    
    * GEODE-9632: fix output for the range query with wildcard character
---
 .../query/functional/LimitClauseJUnitTest.java     |  20 +-
 .../NonDistinctOrderByReplicatedJUnitTest.java     |   2 +-
 .../functional/OrderByReplicatedJUnitTest.java     |   2 +-
 .../internal/AbstractGroupOrRangeJunction.java     |   4 -
 .../geode/cache/query/internal/QueryUtils.java     |   5 +
 .../query/internal/index/CompactRangeIndex.java    |   9 +
 .../cache/query/internal/index/HashIndex.java      |   4 +
 .../cache/query/internal/index/IndexManager.java   |   2 +
 .../query/internal/index/PrimaryKeyIndex.java      |   8 +
 .../cache/query/internal/index/RangeIndex.java     |   4 +
 .../query/dunit/QueryWithRangeIndexDUnitTest.java  | 206 +++++++++++++++++++++
 11 files changed, 250 insertions(+), 16 deletions(-)

diff --git a/geode-core/src/integrationTest/java/org/apache/geode/cache/query/functional/LimitClauseJUnitTest.java b/geode-core/src/integrationTest/java/org/apache/geode/cache/query/functional/LimitClauseJUnitTest.java
index 6dc3392..688069a 100644
--- a/geode-core/src/integrationTest/java/org/apache/geode/cache/query/functional/LimitClauseJUnitTest.java
+++ b/geode-core/src/integrationTest/java/org/apache/geode/cache/query/functional/LimitClauseJUnitTest.java
@@ -673,7 +673,7 @@ public class LimitClauseJUnitTest {
       assertEquals(5, result.size());
       SelectResults wrapper = (SelectResults) result;
       assertEquals(5, wrapper.asSet().size());
-      assertTrue(observer.limitAppliedAtIndex);
+      assertFalse(observer.limitAppliedAtIndex);
     } catch (Exception e) {
       CacheUtils.getLogger().error(e);
       fail(e.toString());
@@ -710,7 +710,7 @@ public class LimitClauseJUnitTest {
       assertEquals(5, result.size());
       SelectResults wrapper = (SelectResults) result;
       assertEquals(5, wrapper.asSet().size());
-      assertTrue(observer.limitAppliedAtIndex);
+      assertFalse(observer.limitAppliedAtIndex);
     } catch (Exception e) {
       CacheUtils.getLogger().error(e);
       fail(e.toString());
@@ -754,7 +754,7 @@ public class LimitClauseJUnitTest {
       assertEquals(5, result.size());
       SelectResults wrapper = (SelectResults) result;
       assertEquals(5, wrapper.asSet().size());
-      assertTrue(observer.limitAppliedAtIndex);
+      assertFalse(observer.limitAppliedAtIndex);
     } catch (Exception e) {
       CacheUtils.getLogger().error(e);
       fail(e.toString());
@@ -799,7 +799,7 @@ public class LimitClauseJUnitTest {
       assertEquals(5, result.size());
       SelectResults wrapper = (SelectResults) result;
       assertEquals(5, wrapper.asSet().size());
-      assertTrue(observer.limitAppliedAtIndex);
+      assertFalse(observer.limitAppliedAtIndex);
     } catch (Exception e) {
       CacheUtils.getLogger().error(e);
       fail(e.toString());
@@ -837,7 +837,7 @@ public class LimitClauseJUnitTest {
       SelectResults wrapper = (SelectResults) result;
       assertEquals(5, wrapper.asSet().size());
       assertTrue(wrapper.getCollectionType().getElementType() instanceof StructType);
-      assertTrue(observer.limitAppliedAtIndex);
+      assertFalse(observer.limitAppliedAtIndex);
     } catch (Exception e) {
       CacheUtils.getLogger().error(e);
       fail(e.toString());
@@ -919,7 +919,7 @@ public class LimitClauseJUnitTest {
       assertEquals(5, result.size());
       SelectResults wrapper = (SelectResults) result;
       assertEquals(5, wrapper.asSet().size());
-      assertTrue(observer.limitAppliedAtIndex);
+      assertFalse(observer.limitAppliedAtIndex);
     } catch (Exception e) {
       CacheUtils.getLogger().error(e);
       fail(e.toString());
@@ -1051,7 +1051,7 @@ public class LimitClauseJUnitTest {
       SelectResults wrapper = (SelectResults) result;
       assertEquals(10, wrapper.asSet().size());
       assertFalse(observer.limitAppliedAtIndex && observer.indexName.equals("idIndex"));
-      assertTrue(observer.limitAppliedAtIndex && observer.indexName.equals("statusIndex"));
+      assertFalse(observer.limitAppliedAtIndex && observer.indexName.equals("statusIndex"));
     } catch (Exception e) {
       CacheUtils.getLogger().error(e);
       fail(e.toString());
@@ -1130,7 +1130,7 @@ public class LimitClauseJUnitTest {
         query = qs.newQuery(qstr);
         result = (SelectResults) query.execute();
         assertEquals(10, result.size());
-        assertTrue(observer.limitAppliedAtIndex && observer.indexName.equals("statusIndex"));
+        assertFalse(observer.limitAppliedAtIndex && observer.indexName.equals("statusIndex"));
       }
     } catch (Exception e) {
       CacheUtils.getLogger().error(e);
@@ -1528,7 +1528,7 @@ public class LimitClauseJUnitTest {
 
     assertNotNull(idIndex);
     SelectResults resultsWithIndex = (SelectResults) query.execute();
-    assertTrue(observer.limitAppliedAtIndex);
+    assertFalse(observer.limitAppliedAtIndex);
     assertEquals(5, resultsWithIndex.size());
   }
 
@@ -1753,7 +1753,7 @@ public class LimitClauseJUnitTest {
 
     assertNotNull(idIndex);
     SelectResults resultsWithIndex = (SelectResults) query.execute();
-    assertTrue(observer.limitAppliedAtIndex);
+    assertFalse(observer.limitAppliedAtIndex);
     assertEquals(5, resultsWithIndex.size());
   }
 
diff --git a/geode-core/src/integrationTest/java/org/apache/geode/cache/query/functional/NonDistinctOrderByReplicatedJUnitTest.java b/geode-core/src/integrationTest/java/org/apache/geode/cache/query/functional/NonDistinctOrderByReplicatedJUnitTest.java
index adf16e6..6dbf923 100644
--- a/geode-core/src/integrationTest/java/org/apache/geode/cache/query/functional/NonDistinctOrderByReplicatedJUnitTest.java
+++ b/geode-core/src/integrationTest/java/org/apache/geode/cache/query/functional/NonDistinctOrderByReplicatedJUnitTest.java
@@ -190,7 +190,7 @@ public class NonDistinctOrderByReplicatedJUnitTest extends NonDistinctOrderByTes
 
     Region r1 = this.createRegion("portfolio1", Portfolio.class);
 
-    for (int i = 0; i < 50; i++) {
+    for (int i = 0; i < 200; i++) {
       r1.put(i + "", new Portfolio(i));
     }
 
diff --git a/geode-core/src/integrationTest/java/org/apache/geode/cache/query/functional/OrderByReplicatedJUnitTest.java b/geode-core/src/integrationTest/java/org/apache/geode/cache/query/functional/OrderByReplicatedJUnitTest.java
index 1f9241d..16fbf13 100644
--- a/geode-core/src/integrationTest/java/org/apache/geode/cache/query/functional/OrderByReplicatedJUnitTest.java
+++ b/geode-core/src/integrationTest/java/org/apache/geode/cache/query/functional/OrderByReplicatedJUnitTest.java
@@ -433,7 +433,7 @@ public class OrderByReplicatedJUnitTest extends OrderByTestImplementation {
 
     Region r1 = createRegion("portfolio1", Portfolio.class);
 
-    for (int i = 0; i < 50; i++) {
+    for (int i = 0; i < 200; i++) {
       r1.put(i + "", new Portfolio(i));
     }
 
diff --git a/geode-core/src/main/java/org/apache/geode/cache/query/internal/AbstractGroupOrRangeJunction.java b/geode-core/src/main/java/org/apache/geode/cache/query/internal/AbstractGroupOrRangeJunction.java
index f0090ae..832f7c0 100644
--- a/geode-core/src/main/java/org/apache/geode/cache/query/internal/AbstractGroupOrRangeJunction.java
+++ b/geode-core/src/main/java/org/apache/geode/cache/query/internal/AbstractGroupOrRangeJunction.java
@@ -35,15 +35,11 @@ import org.apache.geode.cache.query.internal.parse.OQLLexerTokenTypes;
 import org.apache.geode.cache.query.internal.types.StructTypeImpl;
 import org.apache.geode.cache.query.types.ObjectType;
 import org.apache.geode.internal.Assert;
-import org.apache.geode.util.internal.GeodeGlossary;
 
 public abstract class AbstractGroupOrRangeJunction extends AbstractCompiledValue
     implements Filter, OQLLexerTokenTypes {
   /** left operand */
   final CompiledValue[] _operands;
-  private static final int INDEX_RESULT_THRESHOLD_DEFAULT = 100;
-  public static final String INDX_THRESHOLD_PROP_STR =
-      GeodeGlossary.GEMFIRE_PREFIX + "Query.INDEX_THRESHOLD_SIZE";
   private static final int indexThresholdSize =
       Integer.getInteger(INDX_THRESHOLD_PROP_STR, INDEX_RESULT_THRESHOLD_DEFAULT).intValue();
   private int _operator = 0;
diff --git a/geode-core/src/main/java/org/apache/geode/cache/query/internal/QueryUtils.java b/geode-core/src/main/java/org/apache/geode/cache/query/internal/QueryUtils.java
index 70e956c..d57277f 100644
--- a/geode-core/src/main/java/org/apache/geode/cache/query/internal/QueryUtils.java
+++ b/geode-core/src/main/java/org/apache/geode/cache/query/internal/QueryUtils.java
@@ -14,6 +14,8 @@
  */
 package org.apache.geode.cache.query.internal;
 
+import static org.apache.geode.cache.query.internal.CompiledValue.indexThresholdSize;
+
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashSet;
@@ -669,6 +671,9 @@ public class QueryUtils {
       limit = context.cacheGet(CompiledValue.RESULT_LIMIT) != null
           ? (Integer) context.cacheGet(CompiledValue.RESULT_LIMIT) : -1;
     }
+    if (limit != -1 && limit < indexThresholdSize) {
+      limit = indexThresholdSize;
+    }
     return limit;
   }
 
diff --git a/geode-core/src/main/java/org/apache/geode/cache/query/internal/index/CompactRangeIndex.java b/geode-core/src/main/java/org/apache/geode/cache/query/internal/index/CompactRangeIndex.java
index 632ea0c..db4b9a09 100644
--- a/geode-core/src/main/java/org/apache/geode/cache/query/internal/index/CompactRangeIndex.java
+++ b/geode-core/src/main/java/org/apache/geode/cache/query/internal/index/CompactRangeIndex.java
@@ -14,6 +14,8 @@
  */
 package org.apache.geode.cache.query.internal.index;
 
+import static org.apache.geode.cache.query.internal.CompiledValue.indexThresholdSize;
+
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashSet;
@@ -95,6 +97,7 @@ public class CompactRangeIndex extends AbstractIndex {
 
   private IndexStore indexStore;
 
+
   @MutableForTesting
   static boolean TEST_ALWAYS_UPDATE_IN_PROGRESS = false;
 
@@ -483,6 +486,9 @@ public class CompactRangeIndex extends AbstractIndex {
     Boolean applyLimit = (Boolean) context.cacheGet(CompiledValue.CAN_APPLY_LIMIT_AT_INDEX);
     if (applyLimit != null && applyLimit) {
       limit = (Integer) context.cacheGet(CompiledValue.RESULT_LIMIT);
+      if (limit < indexThresholdSize) {
+        limit = indexThresholdSize;
+      }
     }
 
     Boolean orderByClause = (Boolean) context.cacheGet(CompiledValue.CAN_APPLY_ORDER_BY_AT_INDEX);
@@ -517,6 +523,9 @@ public class CompactRangeIndex extends AbstractIndex {
     Boolean applyLimit = (Boolean) context.cacheGet(CompiledValue.CAN_APPLY_LIMIT_AT_INDEX);
     if (applyLimit != null && applyLimit) {
       limit = (Integer) context.cacheGet(CompiledValue.RESULT_LIMIT);
+      if (limit != -1 && limit < indexThresholdSize) {
+        limit = indexThresholdSize;
+      }
     }
     Boolean orderByClause = (Boolean) context.cacheGet(CompiledValue.CAN_APPLY_ORDER_BY_AT_INDEX);
 
diff --git a/geode-core/src/main/java/org/apache/geode/cache/query/internal/index/HashIndex.java b/geode-core/src/main/java/org/apache/geode/cache/query/internal/index/HashIndex.java
index 1bc2591..984a25f 100755
--- a/geode-core/src/main/java/org/apache/geode/cache/query/internal/index/HashIndex.java
+++ b/geode-core/src/main/java/org/apache/geode/cache/query/internal/index/HashIndex.java
@@ -14,6 +14,7 @@
  */
 package org.apache.geode.cache.query.internal.index;
 
+import static org.apache.geode.cache.query.internal.CompiledValue.indexThresholdSize;
 import static org.apache.geode.internal.lang.SystemUtils.getLineSeparator;
 
 import java.util.ArrayList;
@@ -494,6 +495,9 @@ public class HashIndex extends AbstractIndex {
     Boolean applyLimit = (Boolean) context.cacheGet(CompiledValue.CAN_APPLY_LIMIT_AT_INDEX);
     if (applyLimit != null && applyLimit) {
       limit = (Integer) context.cacheGet(CompiledValue.RESULT_LIMIT);
+      if (limit != -1 && limit < indexThresholdSize) {
+        limit = indexThresholdSize;
+      }
     }
 
     Boolean orderByClause = (Boolean) context.cacheGet(CompiledValue.CAN_APPLY_ORDER_BY_AT_INDEX);
diff --git a/geode-core/src/main/java/org/apache/geode/cache/query/internal/index/IndexManager.java b/geode-core/src/main/java/org/apache/geode/cache/query/internal/index/IndexManager.java
index e366102..a38d473 100644
--- a/geode-core/src/main/java/org/apache/geode/cache/query/internal/index/IndexManager.java
+++ b/geode-core/src/main/java/org/apache/geode/cache/query/internal/index/IndexManager.java
@@ -87,6 +87,8 @@ public class IndexManager {
   public static final int RECREATE_INDEX = 4;
   private final InternalCache cache;
   protected final Region region;
+  String indexThresholdSize =
+      System.getProperty(GeodeGlossary.GEMFIRE_PREFIX + "Query.INDEX_THRESHOLD_SIZE");
 
   private final boolean isOverFlowToDisk;
   private final boolean offHeap;
diff --git a/geode-core/src/main/java/org/apache/geode/cache/query/internal/index/PrimaryKeyIndex.java b/geode-core/src/main/java/org/apache/geode/cache/query/internal/index/PrimaryKeyIndex.java
index 6edcc59..c54aeb2 100644
--- a/geode-core/src/main/java/org/apache/geode/cache/query/internal/index/PrimaryKeyIndex.java
+++ b/geode-core/src/main/java/org/apache/geode/cache/query/internal/index/PrimaryKeyIndex.java
@@ -14,6 +14,8 @@
  */
 package org.apache.geode.cache.query.internal.index;
 
+import static org.apache.geode.cache.query.internal.CompiledValue.indexThresholdSize;
+
 import java.util.Collection;
 import java.util.Iterator;
 import java.util.List;
@@ -105,6 +107,9 @@ public class PrimaryKeyIndex extends AbstractIndex {
     Boolean applyLimit = (Boolean) context.cacheGet(CompiledValue.CAN_APPLY_LIMIT_AT_INDEX);
     if (applyLimit != null && applyLimit) {
       limit = (Integer) context.cacheGet(CompiledValue.RESULT_LIMIT);
+      if (limit != -1 && limit < indexThresholdSize) {
+        limit = indexThresholdSize;
+      }
     }
     QueryObserver observer = QueryObserverHolder.getInstance();
     if (limit != -1 && results.size() == limit) {
@@ -184,6 +189,9 @@ public class PrimaryKeyIndex extends AbstractIndex {
 
     if (applyLimit != null && applyLimit.booleanValue()) {
       limit = ((Integer) context.cacheGet(CompiledValue.RESULT_LIMIT)).intValue();
+      if (limit != -1 && limit < indexThresholdSize) {
+        limit = indexThresholdSize;
+      }
     }
     if (limit != -1 && results.size() == limit) {
       observer.limitAppliedAtIndexLevel(this, limit, results);
diff --git a/geode-core/src/main/java/org/apache/geode/cache/query/internal/index/RangeIndex.java b/geode-core/src/main/java/org/apache/geode/cache/query/internal/index/RangeIndex.java
index 5970ec8..c6723bf 100644
--- a/geode-core/src/main/java/org/apache/geode/cache/query/internal/index/RangeIndex.java
+++ b/geode-core/src/main/java/org/apache/geode/cache/query/internal/index/RangeIndex.java
@@ -16,6 +16,7 @@ package org.apache.geode.cache.query.internal.index;
 
 import static java.lang.Integer.MAX_VALUE;
 import static java.lang.Integer.valueOf;
+import static org.apache.geode.cache.query.internal.CompiledValue.indexThresholdSize;
 
 import java.util.ArrayList;
 import java.util.Collection;
@@ -1195,6 +1196,9 @@ public class RangeIndex extends AbstractIndex {
     Boolean applyLimit = (Boolean) context.cacheGet(CompiledValue.CAN_APPLY_LIMIT_AT_INDEX);
     if (applyLimit != null && applyLimit) {
       limit = (Integer) context.cacheGet(CompiledValue.RESULT_LIMIT);
+      if (limit != -1 && limit < indexThresholdSize) {
+        limit = indexThresholdSize;
+      }
     }
 
     Boolean orderByClause = (Boolean) context.cacheGet(CompiledValue.CAN_APPLY_ORDER_BY_AT_INDEX);
diff --git a/geode-cq/src/distributedTest/java/org/apache/geode/cache/query/dunit/QueryWithRangeIndexDUnitTest.java b/geode-cq/src/distributedTest/java/org/apache/geode/cache/query/dunit/QueryWithRangeIndexDUnitTest.java
new file mode 100644
index 0000000..3ca054c
--- /dev/null
+++ b/geode-cq/src/distributedTest/java/org/apache/geode/cache/query/dunit/QueryWithRangeIndexDUnitTest.java
@@ -0,0 +1,206 @@
+/*
+ * 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.geode.cache.query.dunit;
+
+import static org.apache.geode.cache.Region.SEPARATOR;
+import static org.apache.geode.distributed.ConfigurationProperties.HTTP_SERVICE_PORT;
+import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER;
+import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_PORT;
+import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_START;
+import static org.apache.geode.distributed.ConfigurationProperties.LOCATORS;
+import static org.apache.geode.internal.AvailablePortHelper.getRandomAvailableTCPPorts;
+import static org.apache.geode.internal.lang.SystemPropertyHelper.GEMFIRE_PREFIX;
+import static org.apache.geode.test.awaitility.GeodeAwaitility.await;
+import static org.apache.geode.test.dunit.VM.getVM;
+import static org.apache.geode.test.dunit.VM.getVMId;
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.io.File;
+import java.io.Serializable;
+import java.util.HashMap;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import org.apache.geode.cache.Cache;
+import org.apache.geode.cache.CacheFactory;
+import org.apache.geode.cache.Region;
+import org.apache.geode.cache.query.QueryService;
+import org.apache.geode.cache.query.data.Portfolio;
+import org.apache.geode.distributed.LocatorLauncher;
+import org.apache.geode.distributed.ServerLauncher;
+import org.apache.geode.distributed.internal.InternalLocator;
+import org.apache.geode.test.dunit.VM;
+import org.apache.geode.test.dunit.rules.DistributedRule;
+import org.apache.geode.test.junit.rules.GfshCommandRule;
+import org.apache.geode.test.junit.rules.serializable.SerializableTemporaryFolder;
+
+@SuppressWarnings("ALL")
+public class QueryWithRangeIndexDUnitTest implements Serializable {
+
+  @Rule
+  public transient GfshCommandRule gfsh = new GfshCommandRule();
+
+  @Rule
+  public DistributedRule distributedRule = new DistributedRule();
+
+  @Rule
+  public SerializableTemporaryFolder temporaryFolder = new SerializableTemporaryFolder();
+
+  private static final String locatorName = "locator";
+  private static final String serverName = "server";
+
+  private File locatorDir;
+  private File serverDir;
+
+  private int locatorPort;
+  private int locatorJmxPort;
+  private int serverPort;
+
+  private String locators;
+
+  private VM server;
+
+  private static final String regionName = "exampleRegion";
+
+  @Before
+  public void setUp() throws Exception {
+    VM locator = getVM(0);
+    server = getVM(1);
+
+    locatorDir = temporaryFolder.newFolder(locatorName);
+    serverDir = temporaryFolder.newFolder(serverName);
+
+    int[] port = getRandomAvailableTCPPorts(3);
+    locatorPort = port[0];
+    locatorJmxPort = port[1];
+    serverPort = port[2];
+
+    locators = "localhost[" + locatorPort + "]";
+
+    locator.invoke(() -> startLocator(locatorDir, locatorPort, locatorJmxPort));
+
+    gfsh.connectAndVerify(locatorJmxPort, GfshCommandRule.PortType.jmxManager);
+
+    server.invoke(() -> startServer(serverDir, serverPort, locators));
+  }
+
+  @Test
+  public void testQueryWithWildcardAndIndexOnAttributeFromHashMap() {
+    gfsh.executeAndAssertThat("create region --name=" + regionName + " --type=PARTITION")
+        .statusIsSuccess();
+
+    server.invoke(() -> {
+      Cache cache = CacheFactory.getAnyInstance();
+      QueryService cacheQS = cache.getQueryService();
+      cacheQS.createIndex("IdIndex", "value.positions['SUN']",
+          SEPARATOR + regionName + ".entrySet");
+      Region<Integer, Portfolio> region =
+          cache.getRegion(regionName);
+
+      for (int i = 1; i < 10001; i++) {
+        Portfolio p1 = new Portfolio(i, i);
+        p1.positions = new HashMap<>();
+        p1.positions.put("IBM", "something");
+        if (i == 1) {
+          p1.positions.put("SUN", "something");
+        } else {
+          p1.positions.put("SUN", "some");
+        }
+        region.put(i, p1);
+      }
+    });
+
+    String query = "query --query=\"<trace> select e.key, e.value from " +
+        SEPARATOR + regionName + ".entrySet e where e.value.positions['SUN'] like 'somethin%'\"";
+
+    String cmdResult = String.valueOf(gfsh.executeAndAssertThat(query).getResultModel());
+    assertThat(cmdResult).contains("\"Rows\":\"1\"");
+    assertThat(cmdResult).contains("indexesUsed(1):IdIndex(Results: 10000)");
+  }
+
+  @Test
+  public void testLimitIsAppliedOnlyOnQueryResults() {
+    gfsh.executeAndAssertThat("create region --name=" + regionName + " --type=PARTITION")
+        .statusIsSuccess();
+
+    server.invoke(() -> {
+      Cache cache = CacheFactory.getAnyInstance();
+      QueryService cacheQS = cache.getQueryService();
+      cacheQS.createIndex("IdIndex", "value.positions['SUN']",
+          SEPARATOR + regionName + ".entrySet");
+      Region<Integer, Portfolio> region =
+          cache.getRegion(regionName);
+
+      for (int i = 1; i < 10001; i++) {
+        Portfolio p1 = new Portfolio(i, i);
+        p1.positions = new HashMap<>();
+        p1.positions.put("IBM", "something");
+        if (i % 2 == 0) {
+          p1.positions.put("SUN", "something");
+        } else {
+          p1.positions.put("SUN", "some");
+        }
+        region.put(i, p1);
+      }
+    });
+
+    String query = "query --query=\"<trace> select e.key, e.value from " +
+        SEPARATOR + regionName
+        + ".entrySet e where e.value.positions['SUN'] like 'somethin%' limit 5\"";
+
+    String cmdResult = String.valueOf(gfsh.executeAndAssertThat(query).getResultModel());
+    assertThat(cmdResult).contains("\"Rows\":\"5\"");
+    assertThat(cmdResult).contains("indexesUsed(1):IdIndex(Results: 10000)");
+  }
+
+  private static void startLocator(File workingDirectory, int locatorPort,
+      int jmxPort) {
+    LocatorLauncher locatorLauncher = new LocatorLauncher.Builder()
+        .setMemberName(locatorName)
+        .setPort(locatorPort)
+        .setWorkingDirectory(workingDirectory.getAbsolutePath())
+        .set(JMX_MANAGER, "true")
+        .set(JMX_MANAGER_PORT, String.valueOf(jmxPort))
+        .set(JMX_MANAGER_START, "true")
+        .build();
+
+    locatorLauncher.start();
+
+    await().untilAsserted(() -> {
+      InternalLocator locator = (InternalLocator) locatorLauncher.getLocator();
+      assertThat(locator.isSharedConfigurationRunning())
+          .as("Locator shared configuration is running on locator" + getVMId())
+          .isTrue();
+    });
+  }
+
+  private static void startServer(File workingDirectory, int serverPort,
+      String locators) {
+    System.setProperty(GEMFIRE_PREFIX + "Query.INDEX_THRESHOLD_SIZE", "10000");
+    ServerLauncher serverLauncher = new ServerLauncher.Builder()
+        .setDeletePidFileOnStop(Boolean.TRUE)
+        .setMemberName(serverName)
+        .setServerPort(serverPort)
+        .setWorkingDirectory(workingDirectory.getAbsolutePath())
+        .set(HTTP_SERVICE_PORT, "0")
+        .set(LOCATORS, locators)
+        .build();
+
+    serverLauncher.start();
+  }
+}