Repository: incubator-geode
Updated Branches:
  refs/heads/develop 4265fa593 -> a64f7f60e


http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/a64f7f60/geode-core/src/test/java/org/apache/geode/cache/query/dunit/PortfolioPdxVersion.java
----------------------------------------------------------------------
diff --git 
a/geode-core/src/test/java/org/apache/geode/cache/query/dunit/PortfolioPdxVersion.java
 
b/geode-core/src/test/java/org/apache/geode/cache/query/dunit/PortfolioPdxVersion.java
new file mode 100644
index 0000000..5a61c64
--- /dev/null
+++ 
b/geode-core/src/test/java/org/apache/geode/cache/query/dunit/PortfolioPdxVersion.java
@@ -0,0 +1,103 @@
+/*
+ * 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 java.util.HashMap;
+
+import org.apache.geode.cache.query.data.CollectionHolder;
+import org.apache.geode.internal.Assert;
+import org.apache.geode.pdx.PdxInstance;
+import org.apache.geode.pdx.PdxInstanceFactory;
+
+
+public class PortfolioPdxVersion {
+
+  private int ID;
+  public String pkid;
+  public PositionPdxVersion position1;
+  public PositionPdxVersion position2;
+  public Object[] position3;
+  public String description;
+  public long createTime;
+  public HashMap positions = new HashMap();
+  public HashMap collectionHolderMap = new HashMap();
+  String type;
+  public String status;
+  public String[] names = {"aaa", "bbb", "ccc", "ddd"};
+  public String unicodeṤtring;
+
+  public static String secIds[] = {"SUN", "IBM", "YHOO", "GOOG", "MSFT", 
"AOL", "APPL", "ORCL",
+      "SAP", "DELL", "RHAT", "NOVL", "HP"};
+
+  public PortfolioPdxVersion(int i) {
+    ID = i;
+    if (i % 2 == 0) {
+      description = null;
+    } else {
+      description = "XXXX";
+    }
+    pkid = "" + i;
+    status = i % 2 == 0 ? "active" : "inactive";
+    type = "type" + (i % 3);
+    position1 = new PositionPdxVersion(secIds[PositionPdxVersion.cnt % 
secIds.length],
+        PositionPdxVersion.cnt * 1000);
+    if (i % 2 != 0) {
+      position2 = new PositionPdxVersion(secIds[PositionPdxVersion.cnt % 
secIds.length],
+          PositionPdxVersion.cnt * 1000);
+    } else {
+      position2 = null;
+    }
+
+    positions.put(secIds[PositionPdxVersion.cnt % secIds.length], new 
PositionPdxVersion(
+        secIds[PositionPdxVersion.cnt % secIds.length], PositionPdxVersion.cnt 
* 1000));
+    positions.put(secIds[PositionPdxVersion.cnt % secIds.length], new 
PositionPdxVersion(
+        secIds[PositionPdxVersion.cnt % secIds.length], PositionPdxVersion.cnt 
* 1000));
+
+    collectionHolderMap.put("0", new CollectionHolder());
+    collectionHolderMap.put("1", new CollectionHolder());
+
+    unicodeṤtring = i % 2 == 0 ? "ṤṶẐ" : "ṤẐṶ";
+    Assert.assertTrue(unicodeṤtring.length() == 3);
+  }
+
+  public PortfolioPdxVersion(int i, int j) {
+    this(i);
+    this.position1.portfolioId = j;
+    this.position3 = new Object[3];
+    for (int k = 0; k < position3.length; k++) {
+      PositionPdxVersion p = new PositionPdxVersion(secIds[k], (k + 1) * 1000);
+      p.portfolioId = (k + 1);
+      this.position3[k] = p;
+    }
+  }
+
+  public PdxInstance createPdxInstance(PdxInstanceFactory pdxFactory) {
+    pdxFactory.writeInt("ID", this.ID);
+    pdxFactory.writeString("pkid", this.pkid);
+    pdxFactory.writeObject("position1", this.position1);
+    pdxFactory.writeObject("position2", this.position2);
+    pdxFactory.writeObject("positions", this.positions);
+    pdxFactory.writeObject("collectionHolderMap", this.collectionHolderMap);
+    pdxFactory.writeString("type", this.type);
+    pdxFactory.writeString("status", this.status);
+    pdxFactory.writeStringArray("names", this.names);
+    pdxFactory.writeString("description", this.description);
+    pdxFactory.writeLong("createTime", this.createTime);
+    pdxFactory.writeObjectArray("position3", this.position3);
+
+    return pdxFactory.create();
+
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/a64f7f60/geode-core/src/test/java/org/apache/geode/cache/query/dunit/PositionPdxVersion.java
----------------------------------------------------------------------
diff --git 
a/geode-core/src/test/java/org/apache/geode/cache/query/dunit/PositionPdxVersion.java
 
b/geode-core/src/test/java/org/apache/geode/cache/query/dunit/PositionPdxVersion.java
new file mode 100644
index 0000000..f41bbe4
--- /dev/null
+++ 
b/geode-core/src/test/java/org/apache/geode/cache/query/dunit/PositionPdxVersion.java
@@ -0,0 +1,163 @@
+/*
+ * 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 java.io.*;
+import java.util.HashSet;
+import java.util.Set;
+import org.apache.geode.*;
+import org.apache.geode.internal.cache.GemFireCacheImpl;
+import org.apache.geode.pdx.PdxReader;
+import org.apache.geode.pdx.PdxSerializable;
+import org.apache.geode.pdx.PdxWriter;
+
+
+public class PositionPdxVersion implements Serializable, PdxSerializable, 
Comparable {
+  private long avg20DaysVol = 0;
+  private String bondRating;
+  private double convRatio;
+  private String country;
+  private double delta;
+  private long industry;
+  private long issuer;
+  private double mktValue;
+  private double qty;
+  public String secId;
+  private String secLinks;
+  public String secType;
+  private double sharesOutstanding;
+  public String underlyer;
+  private long volatility;
+  private int pid;
+  public static int cnt = 0;
+  public int portfolioId = 0;
+
+
+  /* public no-arg constructor required for DataSerializable */
+  public PositionPdxVersion() {}
+
+  public PositionPdxVersion(String id, double out) {
+    secId = id;
+    sharesOutstanding = out;
+    secType = "a";
+    pid = cnt++;
+    this.mktValue = cnt;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (!(o instanceof PositionPdxVersion)) {
+      return false;
+    }
+    return this.secId.equals(((PositionPdxVersion) o).secId);
+  }
+
+  @Override
+  public int hashCode() {
+    return this.secId.hashCode();
+  }
+
+
+  public static void resetCounter() {
+    cnt = 0;
+  }
+
+  public double getMktValue() {
+    return this.mktValue;
+  }
+
+  public String getSecId() {
+    return secId;
+  }
+
+  public int getId() {
+    return pid;
+  }
+
+  public double getSharesOutstanding() {
+    return sharesOutstanding;
+  }
+
+  public String toString() {
+    return this.getClass().getName() + "[secId=" + this.secId + " out=" + 
this.sharesOutstanding
+        + " type=" + this.secType + " id=" + this.pid + " mktValue=" + 
this.mktValue + "]";
+  }
+
+  public Set getSet(int size) {
+    Set set = new HashSet();
+    for (int i = 0; i < size; i++) {
+      set.add("" + i);
+    }
+    return set;
+  }
+
+  public Set getCol() {
+    Set set = new HashSet();
+    for (int i = 0; i < 2; i++) {
+      set.add("" + i);
+    }
+    return set;
+  }
+
+  public void fromData(PdxReader in) {
+    this.avg20DaysVol = in.readLong("avg20DaysVol");
+    this.bondRating = in.readString("bondRating");
+    this.convRatio = in.readDouble("convRatio");
+    this.country = in.readString("country");
+    this.delta = in.readDouble("delta");
+    this.industry = in.readLong("industry");
+    this.issuer = in.readLong("issuer");
+    this.mktValue = in.readDouble("mktValue");
+    this.qty = in.readDouble("qty");
+    this.secId = in.readString("secId");
+    this.secLinks = in.readString("secLinks");
+    this.sharesOutstanding = in.readDouble("sharesOutstanding");
+    this.underlyer = in.readString("underlyer");
+    this.volatility = in.readLong("volatility");
+    this.pid = in.readInt("pid");
+    this.portfolioId = in.readInt("portfolioId");
+  }
+
+  public void toData(PdxWriter out) {
+    out.writeLong("avg20DaysVol", this.avg20DaysVol);
+    out.writeString("bondRating", this.bondRating);
+    out.writeDouble("convRatio", this.convRatio);
+    out.writeString("country", this.country);
+    out.writeDouble("delta", this.delta);
+    out.writeLong("industry", this.industry);
+    out.writeLong("issuer", this.issuer);
+    out.writeDouble("mktValue", this.mktValue);
+    out.writeDouble("qty", this.qty);
+    out.writeString("secId", this.secId);
+    out.writeString("secLinks", this.secLinks);
+    out.writeDouble("outStanding", this.sharesOutstanding);
+    out.writeString("underLyer", this.underlyer);
+    out.writeLong("volatility", this.volatility);
+    out.writeInt("pid", this.pid);
+    out.writeInt("portfolioId", this.portfolioId);
+  }
+
+
+  public int compareTo(Object o) {
+    if (o == this) {
+      return 0;
+    } else {
+      return this.pid < ((PositionPdxVersion) o).pid ? -1 : 1;
+    }
+
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/a64f7f60/geode-core/src/test/java/org/apache/geode/cache/query/dunit/QueryIndexDUnitTest.java
----------------------------------------------------------------------
diff --git 
a/geode-core/src/test/java/org/apache/geode/cache/query/dunit/QueryIndexDUnitTest.java
 
b/geode-core/src/test/java/org/apache/geode/cache/query/dunit/QueryIndexDUnitTest.java
new file mode 100644
index 0000000..2938800
--- /dev/null
+++ 
b/geode-core/src/test/java/org/apache/geode/cache/query/dunit/QueryIndexDUnitTest.java
@@ -0,0 +1,1331 @@
+/*
+ * 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.junit.Assert.*;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+
+import org.apache.logging.log4j.Logger;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import org.apache.geode.cache.AttributesFactory;
+import org.apache.geode.cache.Cache;
+import org.apache.geode.cache.CacheException;
+import org.apache.geode.cache.DataPolicy;
+import org.apache.geode.cache.EvictionAction;
+import org.apache.geode.cache.EvictionAttributes;
+import org.apache.geode.cache.Region;
+import org.apache.geode.cache.RegionAttributes;
+import org.apache.geode.cache.Scope;
+import org.apache.geode.cache.query.Index;
+import org.apache.geode.cache.query.IndexExistsException;
+import org.apache.geode.cache.query.IndexNameConflictException;
+import org.apache.geode.cache.query.IndexType;
+import org.apache.geode.cache.query.Query;
+import org.apache.geode.cache.query.QueryException;
+import org.apache.geode.cache.query.QueryService;
+import org.apache.geode.cache.query.SelectResults;
+import org.apache.geode.cache.query.data.Portfolio;
+import org.apache.geode.cache.query.functional.StructSetOrResultsSet;
+import org.apache.geode.cache.query.internal.QueryObserverAdapter;
+import org.apache.geode.cache.query.internal.QueryObserverHolder;
+import org.apache.geode.cache.query.internal.index.IndexManager;
+import org.apache.geode.cache30.CacheSerializableRunnable;
+import org.apache.geode.internal.logging.LogService;
+import org.apache.geode.test.dunit.Assert;
+import org.apache.geode.test.dunit.AsyncInvocation;
+import org.apache.geode.test.dunit.Host;
+import org.apache.geode.test.dunit.LogWriterUtils;
+import org.apache.geode.test.dunit.SerializableRunnable;
+import org.apache.geode.test.dunit.ThreadUtils;
+import org.apache.geode.test.dunit.VM;
+import org.apache.geode.test.dunit.cache.internal.JUnit4CacheTestCase;
+import org.apache.geode.test.junit.categories.DistributedTest;
+
+
+@Category(DistributedTest.class)
+public class QueryIndexDUnitTest extends JUnit4CacheTestCase {
+  public static final Logger logger = LogService.getLogger();
+
+  public QueryIndexDUnitTest() {
+    super();
+  }
+
+  @Override
+  public final void postSetUp() throws Exception {
+    int hostCount = Host.getHostCount();
+    SerializableRunnable createRegion = new 
SerializableRunnable("createRegion") {
+      public void run() {
+        Cache cache = getCache();
+        Region region = cache.getRegion("portfolios");
+        if (region == null) {
+          AttributesFactory attributesFactory = new AttributesFactory();
+          attributesFactory.setValueConstraint(Portfolio.class);
+          attributesFactory.setDataPolicy(DataPolicy.REPLICATE);
+          attributesFactory.setIndexMaintenanceSynchronous(true);
+          attributesFactory.setScope(Scope.GLOBAL);
+          RegionAttributes regionAttributes = attributesFactory.create();
+          region = cache.createRegion("portfolios", regionAttributes);
+          region.put("0", new Portfolio(0));
+        }
+      }
+    };
+    logger.info("Number of hosts = " + hostCount);
+    for (int i = 0; i < hostCount; i++) {
+      Host host = Host.getHost(i);
+      int vmCount = host.getVMCount();
+      logger.info("Host number :" + i + "contains " + vmCount + "Vms");
+
+      for (int j = 0; j < vmCount; j++) {
+        VM vm = host.getVM(j);
+        vm.invoke(createRegion);
+      }
+    }
+  }
+
+  private static void doPut() {
+    Region region = basicGetCache().getRegion("portfolios");
+    if (region == null) {
+      logger.info("REGION IS NULL");
+    }
+    try {
+      region.put("1", new Portfolio(1));
+      region.put("2", new Portfolio(2));
+      region.put("3", new Portfolio(3));
+      region.put("4", new Portfolio(4));
+    } catch (Exception e) {
+      Assert.fail("Caught exception while trying to do put operation", e);
+    }
+  }
+
+  private static void doDestroy() {
+    Region region = basicGetCache().getRegion("portfolios");
+    if (region == null) {
+      logger.info("REGION IS NULL");
+    }
+    try {
+      region.destroy("2");
+      region.destroy("3");
+      region.destroy("4");
+    } catch (Exception e) {
+      Assert.fail("Caught exception while trying to do put operation", e);
+    }
+  }
+
+  private static void doInPlaceUpdate(String str) {
+    Region region = basicGetCache().getRegion("portfolios");
+    Portfolio p = null;
+    if (region == null) {
+      logger.info("REGION IS NULL");
+    }
+    try {
+      for (int i = 0; i <= 4; i++) {
+
+        p = (Portfolio) region.get("" + i);
+        p.status = "active";
+        region.put("" + i, p);
+      }
+    } catch (Exception e) {
+      Assert.fail("Caught exception while trying to do put operation", e);
+    }
+  }
+
+  @Test
+  public void createIndexesAndUpdatesAndThenValidate() throws 
InterruptedException {
+    Integer[] intArr = new Integer[2];
+    Host host = Host.getHost(0);
+    VM vm0 = host.getVM(0);
+
+    AsyncInvocation ai1 = null;
+    AsyncInvocation ai2 = null;
+
+    vm0.invoke(() -> QueryIndexDUnitTest.createIndex());
+    vm0.invoke(() -> QueryIndexDUnitTest.validateIndexUsage());
+    VM vm3 = host.getVM(3);
+
+
+    vm0.invoke(() -> QueryIndexDUnitTest.removeIndex());
+    ai1 = vm3.invokeAsync(() -> QueryIndexDUnitTest.doPut());
+    ai2 = vm0.invokeAsync(() -> QueryIndexDUnitTest.createIndex());
+    ThreadUtils.join(ai1, 30 * 1000);
+    ThreadUtils.join(ai2, 30 * 1000);
+    intArr[0] = new Integer(3);
+    intArr[1] = new Integer(2);
+    vm0.invoke(() -> validateIndexUpdate(intArr[0], intArr[1]));
+
+
+    vm0.invoke(() -> QueryIndexDUnitTest.removeIndex());
+    ai1 = vm0.invokeAsync(() -> QueryIndexDUnitTest.doDestroy());
+    ai2 = vm0.invokeAsync(() -> QueryIndexDUnitTest.createIndex());
+    ThreadUtils.join(ai1, 30 * 1000);
+    ThreadUtils.join(ai2, 30 * 1000);
+    intArr[0] = new Integer(1);
+    intArr[1] = new Integer(1);
+    vm0.invoke(() -> validateIndexUpdate(intArr[0], intArr[1]));
+
+
+    vm0.invoke(() -> QueryIndexDUnitTest.removeIndex());
+    ai1 = vm0.invokeAsync(() -> QueryIndexDUnitTest.doPut());
+    ai2 = vm0.invokeAsync(() -> QueryIndexDUnitTest.createIndex());
+    ThreadUtils.join(ai1, 30 * 1000);
+    ThreadUtils.join(ai2, 30 * 1000);
+    intArr[0] = new Integer(3);
+    intArr[1] = new Integer(2);
+    vm0.invoke(() -> validateIndexUpdate(intArr[0], intArr[1]));
+
+
+    vm0.invoke(() -> QueryIndexDUnitTest.removeIndex());
+    ai1 = vm3.invokeAsync(() -> QueryIndexDUnitTest.doDestroy());
+    ai2 = vm0.invokeAsync(() -> QueryIndexDUnitTest.createIndex());
+    ThreadUtils.join(ai1, 30 * 1000);
+    ThreadUtils.join(ai2, 30 * 1000);
+    intArr[0] = new Integer(1);
+    intArr[1] = new Integer(1);
+    vm0.invoke(() -> validateIndexUpdate(intArr[0], intArr[1]));
+
+    // Test for in-place update.
+    vm0.invoke(() -> QueryIndexDUnitTest.removeIndex());
+    ai1 = vm0.invokeAsync(() -> QueryIndexDUnitTest.doPut());
+    ai2 = vm0.invokeAsync(() -> QueryIndexDUnitTest.createIndex());
+    ThreadUtils.join(ai1, 30 * 1000);
+    ThreadUtils.join(ai2, 30 * 1000);
+    intArr[0] = new Integer(3);
+    intArr[1] = new Integer(2);
+    vm0.invoke(() -> validateIndexUpdate(intArr[0], intArr[1]));
+
+    try {
+      Thread.sleep(2000);
+    } catch (Exception ex) {
+    }
+    // Do an in-place update of the region entries.
+    // This will set the Portfolio objects status to "active".
+    String str = "To get Update in synch thread."; // Else test was exiting 
before the validation
+                                                   // could finish.
+    vm0.invoke(() -> doInPlaceUpdate(str));
+    intArr[0] = new Integer(5);
+    intArr[1] = new Integer(0);
+    vm0.invoke(() -> validateIndexUpdate(intArr[0], intArr[1]));
+  }
+
+  @Test
+  public void createIndexOnOverflowRegionsAndExecuteQueries() throws 
InterruptedException {
+    Host host = Host.getHost(0);
+    VM[] vms = new VM[] {host.getVM(0), host.getVM(1), host.getVM(2), 
host.getVM(3),};
+
+    // Create and load regions on all vms.
+    for (int i = 0; i < vms.length; i++) {
+      int finalI = i;
+      vms[i].invoke(() -> 
QueryIndexDUnitTest.createAndLoadOverFlowRegions("testOf" + "vm" + finalI,
+          new Boolean(true), new Boolean(true)));
+    }
+
+    // Create index on the regions.
+    for (int i = 0; i < vms.length; i++) {
+      vms[i].invoke(() -> QueryIndexDUnitTest.createIndexOnOverFlowRegions());
+    }
+
+    // execute query.
+    for (int i = 0; i < vms.length; i++) {
+      vms[i].invoke(() -> 
QueryIndexDUnitTest.executeQueriesUsingIndexOnOverflowRegions());
+    }
+
+    // reload the regions after index creation.
+    for (int i = 0; i < vms.length; i++) {
+      int finalI = i;
+      vms[i].invoke(() -> 
QueryIndexDUnitTest.createAndLoadOverFlowRegions("testOf" + "vm" + finalI,
+          new Boolean(false), new Boolean(true)));
+    }
+
+    // reexecute the query.
+    for (int i = 0; i < vms.length; i++) {
+      vms[i].invoke(() -> 
QueryIndexDUnitTest.executeQueriesUsingIndexOnOverflowRegions());
+    }
+  }
+
+  @Test
+  public void createIndexOnOverflowRegionsAndValidateResults() throws 
Exception {
+    Host host = Host.getHost(0);
+    VM[] vms = new VM[] {host.getVM(0), host.getVM(1),};
+
+    // Create and load regions on all vms.
+    for (int i = 0; i < vms.length; i++) {
+      int finalI = i;
+      vms[i].invoke(() -> QueryIndexDUnitTest.createAndLoadOverFlowRegions(
+          "testOfValid" + "vm" + finalI, new Boolean(true), new 
Boolean(false)));
+    }
+
+    vms[0].invoke(new CacheSerializableRunnable("Execute query validate 
results") {
+      public void run2() throws CacheException {
+        Cache cache = basicGetCache();
+        String[] regionNames = new String[] {"replicateOverFlowRegion",
+            "replicatePersistentOverFlowRegion", "prOverFlowRegion", 
"prPersistentOverFlowRegion",};
+
+        QueryService qs = cache.getQueryService();
+        Region region = null;
+
+        int numObjects = 10;
+        // Update the region and re-execute the query.
+        // The index should get updated accordingly.
+        for (int i = 0; i < regionNames.length; i++) {
+          region = cache.getRegion(regionNames[i]);
+          for (int cnt = 1; cnt < numObjects; cnt++) {
+            region.put(new Portfolio(cnt), new Portfolio(cnt));
+          }
+        }
+
+        String[] qString = new String[] {"SELECT * FROM /REGION_NAME pf WHERE 
pf.ID = 1",
+            "SELECT ID FROM /REGION_NAME pf WHERE pf.ID = 1",
+            "SELECT * FROM /REGION_NAME pf WHERE pf.ID > 5",
+            "SELECT ID FROM /REGION_NAME pf WHERE pf.ID > 5",
+            "SELECT * FROM /REGION_NAME.keys key WHERE key.ID = 1",
+            "SELECT ID FROM /REGION_NAME.keys key WHERE key.ID = 1",
+            "SELECT * FROM /REGION_NAME.keys key WHERE key.ID > 5",
+            "SELECT ID FROM /REGION_NAME.keys key WHERE key.ID > 5",};
+
+        // Execute Query without index.
+        SelectResults[] srWithoutIndex = new SelectResults[qString.length * 
regionNames.length];
+        String[] queryString = new String[qString.length * regionNames.length];
+
+        int r = 0;
+        try {
+          for (int q = 0; q < qString.length; q++) {
+            for (int i = 0; i < regionNames.length; i++) {
+              String queryStr = qString[q].replace("REGION_NAME", 
regionNames[i]);
+              Query query = qs.newQuery(queryStr);
+              queryString[r] = queryStr;
+              srWithoutIndex[r] = (SelectResults) query.execute();
+              r++;
+            }
+          }
+        } catch (Exception ex) {
+          LogWriterUtils.getLogWriter().info("Failed to Execute query", ex);
+          fail("Failed to Execute query.");
+        }
+
+        // Create index.
+        try {
+          for (int i = 0; i < regionNames.length; i++) {
+            region = cache.getRegion(regionNames[i]);
+            String indexName = "idIndex" + regionNames[i];
+            cache.getLogger()
+                .fine("createIndexOnOverFlowRegions() checking for index: " + 
indexName);
+            try {
+              if (qs.getIndex(region, indexName) == null) {
+                cache.getLogger()
+                    .fine("createIndexOnOverFlowRegions() Index doesn't exist, 
creating index: "
+                        + indexName);
+                Index i1 = qs.createIndex(indexName, "pf.ID", "/" + 
regionNames[i] + " pf");
+              }
+              indexName = "keyIdIndex" + regionNames[i];
+              if (qs.getIndex(region, indexName) == null) {
+                cache.getLogger()
+                    .fine("createIndexOnOverFlowRegions() Index doesn't exist, 
creating index: "
+                        + indexName);
+                Index i2 = qs.createIndex(indexName, "key.ID", "/" + 
regionNames[i] + ".keys key");
+              }
+            } catch (IndexNameConflictException ice) {
+              // Ignore. The pr may have created the index through
+              // remote index create message from peer.
+            }
+          }
+        } catch (Exception ex) {
+          logger.info("Failed to create index", ex);
+          fail("Failed to create index.");
+        }
+
+        // Execute Query with index.
+        SelectResults[] srWithIndex = new SelectResults[qString.length * 
regionNames.length];
+        try {
+          r = 0;
+          for (int q = 0; q < qString.length; q++) {
+            for (int i = 0; i < regionNames.length; i++) {
+              QueryObserverImpl observer = new QueryObserverImpl();
+              QueryObserverHolder.setInstance(observer);
+              String queryStr = qString[q].replace("REGION_NAME", 
regionNames[i]);
+              Query query = qs.newQuery(queryStr);
+              srWithIndex[r++] = (SelectResults) query.execute();
+              if (!observer.isIndexesUsed) {
+                fail("Index not used for query. " + queryStr);
+              }
+            }
+          }
+        } catch (Exception ex) {
+          LogWriterUtils.getLogWriter().info("Failed to Execute query", ex);
+          fail("Failed to Execute query.");
+        }
+
+        // Compare results with and without index.
+        StructSetOrResultsSet ssORrs = new StructSetOrResultsSet();
+        SelectResults[][] sr = new SelectResults[1][2];
+
+        for (int i = 0; i < srWithIndex.length; i++) {
+          sr[0][0] = srWithoutIndex[i];
+          sr[0][1] = srWithIndex[i];
+          logger.info("Comparing the result for the query : " + queryString[i]
+              + " Index in ResultSet is: " + i);
+          ssORrs.CompareQueryResultsWithoutAndWithIndexes(sr, 1, queryString);
+        }
+
+        // Update the region and re-execute the query.
+        // The index should get updated accordingly.
+        for (int i = 0; i < regionNames.length; i++) {
+          region = cache.getRegion(regionNames[i]);
+          for (int cnt = 1; cnt < numObjects; cnt++) {
+            if (cnt % 2 == 0) {
+              region.destroy(new Portfolio(cnt));
+            }
+          }
+          for (int cnt = 10; cnt < numObjects; cnt++) {
+            if (cnt % 2 == 0) {
+              region.put(new Portfolio(cnt), new Portfolio(cnt));
+            }
+          }
+        }
+
+        // Execute Query with index.
+        srWithIndex = new SelectResults[qString.length * regionNames.length];
+        try {
+          r = 0;
+          for (int q = 0; q < qString.length; q++) {
+            for (int i = 0; i < regionNames.length; i++) {
+              QueryObserverImpl observer = new QueryObserverImpl();
+              QueryObserverHolder.setInstance(observer);
+              String queryStr = qString[q].replace("REGION_NAME", 
regionNames[i]);
+              Query query = qs.newQuery(queryStr);
+              srWithIndex[r++] = (SelectResults) query.execute();
+              if (!observer.isIndexesUsed) {
+                fail("Index not used for query. " + queryStr);
+              }
+            }
+          }
+        } catch (Exception ex) {
+          logger.info("Failed to Execute query", ex);
+          fail("Failed to Execute query.");
+        }
+
+      }
+    });
+  }
+
+  @Test
+  public void 
createIndexOnOverflowRegionsWithMultipleWhereClauseAndValidateResults()
+      throws Exception {
+    Host host = Host.getHost(0);
+    VM[] vms = new VM[] {host.getVM(0), host.getVM(1),};
+
+    // Create and load regions on all vms.
+    for (int i = 0; i < vms.length; i++) {
+      int finalI = i;
+      vms[i].invoke(() -> QueryIndexDUnitTest.createAndLoadOverFlowRegions(
+          "testOfValid2" + "vm" + finalI, new Boolean(true), new 
Boolean(false)));
+    }
+
+    vms[0].invoke(new CacheSerializableRunnable("Execute query validate 
results") {
+      public void run2() throws CacheException {
+        Cache cache = basicGetCache();
+        String[] regionNames = new String[] {"replicateOverFlowRegion",
+            "replicatePersistentOverFlowRegion", "prOverFlowRegion", 
"prPersistentOverFlowRegion",};
+
+        QueryService qs = cache.getQueryService();
+        Region region = null;
+
+        int numObjects = 10;
+        // Update the region and re-execute the query.
+        // The index should get updated accordingly.
+        for (int i = 0; i < regionNames.length; i++) {
+          region = cache.getRegion(regionNames[i]);
+          for (int cnt = 1; cnt < numObjects; cnt++) {
+            region.put(new Portfolio(cnt), new String("XX" + cnt));
+          }
+        }
+
+        String[] qString = new String[] {"SELECT * FROM /REGION_NAME pf WHERE 
pf = 'XX1'",
+            "SELECT * FROM /REGION_NAME pf WHERE pf IN SET( 'XX5', 'XX6', 
'XX7')",
+            "SELECT * FROM /REGION_NAME.values pf WHERE pf IN SET( 'XX5', 
'XX6', 'XX7')",
+            "SELECT * FROM /REGION_NAME.keys k WHERE k.ID = 1",
+            "SELECT key.ID FROM /REGION_NAME.keys key WHERE key.ID = 1",
+            "SELECT ID, status FROM /REGION_NAME.keys WHERE ID = 1",
+            "SELECT k.ID, k.status FROM /REGION_NAME.keys k WHERE k.ID = 1 and 
k.status = 'active'",
+            "SELECT * FROM /REGION_NAME.keys key WHERE key.ID > 5",
+            "SELECT key.ID FROM /REGION_NAME.keys key WHERE key.ID > 5 and 
key.status = 'active'",};
+
+        // Execute Query without index.
+        SelectResults[] srWithoutIndex = new SelectResults[qString.length * 
regionNames.length];
+        String[] queryString = new String[qString.length * regionNames.length];
+
+        int r = 0;
+        try {
+          for (int q = 0; q < qString.length; q++) {
+            for (int i = 0; i < regionNames.length; i++) {
+              String queryStr = qString[q].replace("REGION_NAME", 
regionNames[i]);
+              Query query = qs.newQuery(queryStr);
+              queryString[r] = queryStr;
+              srWithoutIndex[r] = (SelectResults) query.execute();
+              r++;
+            }
+          }
+        } catch (Exception ex) {
+          logger.info("Failed to Execute query", ex);
+          fail("Failed to Execute query.");
+        }
+
+        // Create index.
+        String indexName = "";
+        try {
+          for (int i = 0; i < regionNames.length; i++) {
+            region = cache.getRegion(regionNames[i]);
+            indexName = "idIndex" + regionNames[i];
+            cache.getLogger()
+                .fine("createIndexOnOverFlowRegions() checking for index: " + 
indexName);
+            try {
+              if (qs.getIndex(region, indexName) == null) {
+                cache.getLogger()
+                    .fine("createIndexOnOverFlowRegions() Index doesn't exist, 
creating index: "
+                        + indexName);
+                Index i1 = qs.createIndex(indexName, "pf", "/" + 
regionNames[i] + " pf");
+              }
+              indexName = "valueIndex" + regionNames[i];
+              if (qs.getIndex(region, indexName) == null) {
+                cache.getLogger()
+                    .fine("createIndexOnOverFlowRegions() Index doesn't exist, 
creating index: "
+                        + indexName);
+                Index i1 = qs.createIndex(indexName, "pf", "/" + 
regionNames[i] + ".values pf");
+              }
+              indexName = "keyIdIndex" + regionNames[i];
+              if (qs.getIndex(region, indexName) == null) {
+                cache.getLogger()
+                    .fine("createIndexOnOverFlowRegions() Index doesn't exist, 
creating index: "
+                        + indexName);
+                Index i2 = qs.createIndex(indexName, "key.ID", "/" + 
regionNames[i] + ".keys key");
+              }
+              indexName = "keyIdIndex2" + regionNames[i];
+
+
+            } catch (IndexNameConflictException ice) {
+              // Ignore. The pr may have created the index through
+              // remote index create message from peer.
+            }
+          }
+        } catch (Exception ex) {
+          logger.info("Failed to create index", ex);
+          fail("Failed to create index." + indexName);
+        }
+
+        // Execute Query with index.
+        SelectResults[] srWithIndex = new SelectResults[qString.length * 
regionNames.length];
+        try {
+          r = 0;
+          for (int q = 0; q < qString.length; q++) {
+            for (int i = 0; i < regionNames.length; i++) {
+              QueryObserverImpl observer = new QueryObserverImpl();
+              QueryObserverHolder.setInstance(observer);
+              String queryStr = qString[q].replace("REGION_NAME", 
regionNames[i]);
+              Query query = qs.newQuery(queryStr);
+              srWithIndex[r++] = (SelectResults) query.execute();
+              if (!observer.isIndexesUsed) {
+                fail("Index not used for query. " + queryStr);
+              }
+            }
+          }
+        } catch (Exception ex) {
+          logger.info("Failed to Execute query", ex);
+          fail("Failed to Execute query.");
+        }
+
+        // Compare results with and without index.
+        StructSetOrResultsSet ssORrs = new StructSetOrResultsSet();
+        SelectResults[][] sr = new SelectResults[1][2];
+
+        for (int i = 0; i < srWithIndex.length; i++) {
+          sr[0][0] = srWithoutIndex[i];
+          sr[0][1] = srWithIndex[i];
+          logger.info("Comparing the result for the query : " + queryString[i]
+              + " Index in ResultSet is: " + i);
+          ssORrs.CompareQueryResultsWithoutAndWithIndexes(sr, 1, queryString);
+        }
+
+        // Update the region and re-execute the query.
+        // The index should get updated accordingly.
+        for (int i = 0; i < regionNames.length; i++) {
+          region = cache.getRegion(regionNames[i]);
+          for (int cnt = 1; cnt < numObjects; cnt++) {
+            if (cnt % 2 == 0) {
+              region.destroy(new Portfolio(cnt));
+            }
+          }
+          for (int cnt = 10; cnt < numObjects; cnt++) {
+            if (cnt % 2 == 0) {
+              region.put(new Portfolio(cnt), new String("XX" + cnt));
+            }
+          }
+        }
+
+        // Execute Query with index.
+        srWithIndex = new SelectResults[qString.length * regionNames.length];
+        try {
+          r = 0;
+          for (int q = 0; q < qString.length; q++) {
+            for (int i = 0; i < regionNames.length; i++) {
+              QueryObserverImpl observer = new QueryObserverImpl();
+              QueryObserverHolder.setInstance(observer);
+              String queryStr = qString[q].replace("REGION_NAME", 
regionNames[i]);
+              Query query = qs.newQuery(queryStr);
+              srWithIndex[r++] = (SelectResults) query.execute();
+              if (!observer.isIndexesUsed) {
+                fail("Index not used for query. " + queryStr);
+              }
+            }
+          }
+        } catch (Exception ex) {
+          logger.info("Failed to Execute query", ex);
+          fail("Failed to Execute query.");
+        }
+
+      }
+    });
+  }
+
+  @Test
+  public void createIndexAndUpdatesOnOverflowRegionsAndValidateResults() 
throws Exception {
+    Host host = Host.getHost(0);
+    VM[] vms = new VM[] {host.getVM(0), host.getVM(1),};
+
+    // Create and load regions on all vms.
+    for (int i = 0; i < vms.length; i++) {
+      int finalI = i;
+      vms[i].invoke(() -> QueryIndexDUnitTest.createAndLoadOverFlowRegions(
+          "testOfValid3" + "vm" + finalI, new Boolean(true), new 
Boolean(true)));
+    }
+
+    vms[0].invoke(new CacheSerializableRunnable("Execute query validate 
results") {
+      public void run2() throws CacheException {
+        Cache cache = basicGetCache();
+        String[] regionNames = new String[] {"replicateOverFlowRegion",
+            "replicatePersistentOverFlowRegion", "prOverFlowRegion", 
"prPersistentOverFlowRegion",};
+
+        QueryService qs = cache.getQueryService();
+        Region region = null;
+
+
+        String[] qString = new String[] {"SELECT * FROM /REGION_NAME pf WHERE 
pf.ID = 1",
+            "SELECT ID FROM /REGION_NAME pf WHERE pf.ID = 1",
+            "SELECT * FROM /REGION_NAME pf WHERE pf.ID > 5",
+            "SELECT ID FROM /REGION_NAME pf WHERE pf.ID > 5",
+            "SELECT * FROM /REGION_NAME.keys key WHERE key.ID = 1",
+            "SELECT ID FROM /REGION_NAME.keys key WHERE key.ID = 1",
+            "SELECT * FROM /REGION_NAME.keys key WHERE key.ID > 5",
+            "SELECT ID FROM /REGION_NAME.keys key WHERE key.ID > 5",};
+
+        // Execute Query without index.
+        SelectResults[] srWithoutIndex = new SelectResults[qString.length * 
regionNames.length];
+        String[] queryString = new String[qString.length * regionNames.length];
+
+        int r = 0;
+        try {
+          for (int q = 0; q < qString.length; q++) {
+            for (int i = 0; i < regionNames.length; i++) {
+              String queryStr = qString[q].replace("REGION_NAME", 
regionNames[i]);
+              Query query = qs.newQuery(queryStr);
+              queryString[r] = queryStr;
+              srWithoutIndex[r] = (SelectResults) query.execute();
+              r++;
+            }
+          }
+        } catch (Exception ex) {
+          logger.info("Failed to Execute query", ex);
+          fail("Failed to Execute query.");
+        }
+
+        // Create index.
+        try {
+          for (int i = 0; i < regionNames.length; i++) {
+            region = cache.getRegion(regionNames[i]);
+            String indexName = "idIndex" + regionNames[i];
+            cache.getLogger()
+                .fine("createIndexOnOverFlowRegions() checking for index: " + 
indexName);
+            try {
+              if (qs.getIndex(region, indexName) == null) {
+                cache.getLogger()
+                    .fine("createIndexOnOverFlowRegions() Index doesn't exist, 
creating index: "
+                        + indexName);
+                Index i1 = qs.createIndex(indexName, "pf.ID", "/" + 
regionNames[i] + " pf");
+              }
+              indexName = "keyIdIndex" + regionNames[i];
+              if (qs.getIndex(region, indexName) == null) {
+                cache.getLogger()
+                    .fine("createIndexOnOverFlowRegions() Index doesn't exist, 
creating index: "
+                        + indexName);
+                Index i2 = qs.createIndex(indexName, "key.ID", "/" + 
regionNames[i] + ".keys key");
+              }
+            } catch (IndexNameConflictException ice) {
+              // Ignore. The pr may have created the index through
+              // remote index create message from peer.
+            }
+          }
+        } catch (Exception ex) {
+          logger.info("Failed to create index", ex);
+          fail("Failed to create index.");
+        }
+
+        int numObjects = 50;
+        // Update the region and re-execute the query.
+        // The index should get updated accordingly.
+
+        for (int i = 0; i < regionNames.length; i++) {
+          region = cache.getRegion(regionNames[i]);
+          for (int cnt = 0; cnt < numObjects; cnt++) {
+            region.put(new Portfolio(cnt), new Portfolio(cnt));
+          }
+        }
+
+        for (int i = 0; i < regionNames.length; i++) {
+          region = cache.getRegion(regionNames[i]);
+          String indexName = "idIndex" + regionNames[i];
+          Index i1, i2;
+          if ((i1 = qs.getIndex(region, indexName)) != null) {
+            assertEquals("Unexpected number of keys in the index ", numObjects,
+                i1.getStatistics().getNumberOfKeys());
+            assertEquals("Unexpected number of values in the index ", 
numObjects,
+                i1.getStatistics().getNumberOfValues());
+          }
+          indexName = "keyIdIndex" + regionNames[i];
+          if ((i2 = qs.getIndex(region, indexName)) != null) {
+            assertEquals("Unexpected number of keys in the index ", numObjects,
+                i2.getStatistics().getNumberOfKeys());
+            assertEquals("Unexpected number of values in the index ", 
numObjects,
+                i2.getStatistics().getNumberOfValues());
+          }
+        }
+
+        // Execute Query with index.
+        SelectResults[] srWithIndex = new SelectResults[qString.length * 
regionNames.length];
+        try {
+          r = 0;
+          for (int q = 0; q < qString.length; q++) {
+            for (int i = 0; i < regionNames.length; i++) {
+              QueryObserverImpl observer = new QueryObserverImpl();
+              QueryObserverHolder.setInstance(observer);
+              String queryStr = qString[q].replace("REGION_NAME", 
regionNames[i]);
+              Query query = qs.newQuery(queryStr);
+              srWithIndex[r++] = (SelectResults) query.execute();
+              if (!observer.isIndexesUsed) {
+                fail("Index not used for query. " + queryStr);
+              }
+            }
+          }
+        } catch (Exception ex) {
+          logger.info("Failed to Execute query", ex);
+          fail("Failed to Execute query.");
+        }
+
+        // Compare results with and without index.
+        StructSetOrResultsSet ssORrs = new StructSetOrResultsSet();
+        SelectResults[][] sr = new SelectResults[1][2];
+
+        for (int i = 0; i < srWithIndex.length; i++) {
+          sr[0][0] = srWithoutIndex[i];
+          sr[0][1] = srWithIndex[i];
+          logger.info("Comparing the result for the query : " + queryString[i]
+              + " Index in ResultSet is: " + i);
+          ssORrs.CompareQueryResultsWithoutAndWithIndexes(sr, 1, queryString);
+        }
+
+      }
+    });
+  }
+
+  @Test
+  public void createIndexOnOverflowRegionsAndValidateResultsUsingParams() 
throws Exception {
+    Host host = Host.getHost(0);
+    VM[] vms = new VM[] {host.getVM(0), host.getVM(1),};
+
+    // Create and load regions on all vms.
+    for (int i = 0; i < vms.length; i++) {
+      int finalI = i;
+      vms[i].invoke(() -> QueryIndexDUnitTest.createAndLoadOverFlowRegions(
+          "testOfValidUseParams" + "vm" + finalI, new Boolean(true), new 
Boolean(false)));
+    }
+
+    vms[0].invoke(new CacheSerializableRunnable("Execute query validate 
results") {
+      public void run2() throws CacheException {
+        Cache cache = basicGetCache();
+        String[] regionNames = new String[] {"replicateOverFlowRegion",
+            "replicatePersistentOverFlowRegion", "prOverFlowRegion", 
"prPersistentOverFlowRegion",};
+
+        QueryService qs = cache.getQueryService();
+        Region region = null;
+
+        int numObjects = 10;
+        // Update the region and re-execute the query.
+        // The index should get updated accordingly.
+        for (int i = 0; i < regionNames.length; i++) {
+          region = cache.getRegion(regionNames[i]);
+          for (int cnt = 1; cnt < numObjects; cnt++) {
+            region.put(new Portfolio(cnt), new Integer(cnt + 100));
+          }
+        }
+
+        String[] qString = new String[] {"SELECT * FROM /REGION_NAME pf WHERE 
pf = $1",
+            "SELECT * FROM /REGION_NAME pf WHERE pf > $1",
+            "SELECT * FROM /REGION_NAME.values pf WHERE pf < $1",
+            "SELECT * FROM /REGION_NAME.keys k WHERE k.ID = $1",
+            "SELECT key.ID FROM /REGION_NAME.keys key WHERE key.ID = $1",
+            "SELECT ID, status FROM /REGION_NAME.keys WHERE ID = $1",
+            "SELECT k.ID, k.status FROM /REGION_NAME.keys k WHERE k.ID = $1 
and k.status = $2",
+            "SELECT * FROM /REGION_NAME.keys key WHERE key.ID > $1",
+            "SELECT key.ID FROM /REGION_NAME.keys key WHERE key.ID > $1 and 
key.status = $2",};
+
+        // Execute Query without index.
+        SelectResults[] srWithoutIndex = new SelectResults[qString.length * 
regionNames.length];
+        String[] queryString = new String[qString.length * regionNames.length];
+
+        int r = 0;
+        try {
+          for (int q = 0; q < qString.length; q++) {
+            for (int i = 0; i < regionNames.length; i++) {
+              String queryStr = qString[q].replace("REGION_NAME", 
regionNames[i]);
+              Query query = qs.newQuery(queryStr);
+              queryString[r] = queryStr;
+              srWithoutIndex[r] =
+                  (SelectResults) query.execute(new Object[] {new Integer(5), 
"active"});
+              r++;
+            }
+          }
+        } catch (Exception ex) {
+          logger.info("Failed to Execute query", ex);
+          fail("Failed to Execute query.");
+        }
+
+        // Create index.
+        String indexName = "";
+        try {
+          for (int i = 0; i < regionNames.length; i++) {
+            region = cache.getRegion(regionNames[i]);
+            indexName = "idIndex" + regionNames[i];
+            cache.getLogger()
+                .fine("createIndexOnOverFlowRegions() checking for index: " + 
indexName);
+            try {
+              if (qs.getIndex(region, indexName) == null) {
+                cache.getLogger()
+                    .fine("createIndexOnOverFlowRegions() Index doesn't exist, 
creating index: "
+                        + indexName);
+                Index i1 = qs.createIndex(indexName, "pf", "/" + 
regionNames[i] + " pf");
+              }
+              indexName = "valueIndex" + regionNames[i];
+              if (qs.getIndex(region, indexName) == null) {
+                cache.getLogger()
+                    .fine("createIndexOnOverFlowRegions() Index doesn't exist, 
creating index: "
+                        + indexName);
+                Index i1 = qs.createIndex(indexName, "pf", "/" + 
regionNames[i] + ".values pf");
+              }
+              indexName = "keyIdIndex" + regionNames[i];
+              if (qs.getIndex(region, indexName) == null) {
+                cache.getLogger()
+                    .fine("createIndexOnOverFlowRegions() Index doesn't exist, 
creating index: "
+                        + indexName);
+                Index i2 = qs.createIndex(indexName, "key.ID", "/" + 
regionNames[i] + ".keys key");
+              }
+            } catch (IndexNameConflictException ice) {
+              // Ignore. The pr may have created the index through
+              // remote index create message from peer.
+            }
+          }
+        } catch (Exception ex) {
+          LogWriterUtils.getLogWriter().info("Failed to create index", ex);
+          fail("Failed to create index." + indexName);
+        }
+
+        // Execute Query with index.
+        SelectResults[] srWithIndex = new SelectResults[qString.length * 
regionNames.length];
+        try {
+          r = 0;
+          for (int q = 0; q < qString.length; q++) {
+            for (int i = 0; i < regionNames.length; i++) {
+              QueryObserverImpl observer = new QueryObserverImpl();
+              QueryObserverHolder.setInstance(observer);
+              String queryStr = qString[q].replace("REGION_NAME", 
regionNames[i]);
+              Query query = qs.newQuery(queryStr);
+              srWithIndex[r++] =
+                  (SelectResults) query.execute(new Object[] {new Integer(5), 
"active"});
+              if (!observer.isIndexesUsed) {
+                fail("Index not used for query. " + queryStr);
+              }
+            }
+          }
+        } catch (Exception ex) {
+          logger.info("Failed to Execute query", ex);
+          fail("Failed to Execute query.");
+        }
+
+        // Compare results with and without index.
+        StructSetOrResultsSet ssORrs = new StructSetOrResultsSet();
+        SelectResults[][] sr = new SelectResults[1][2];
+
+        for (int i = 0; i < srWithIndex.length; i++) {
+          sr[0][0] = srWithoutIndex[i];
+          sr[0][1] = srWithIndex[i];
+          logger.info("Comparing the result for the query : " + queryString[i]
+              + " Index in ResultSet is: " + i);
+          ssORrs.CompareQueryResultsWithoutAndWithIndexes(sr, 1, queryString);
+        }
+
+        // Update the region and re-execute the query.
+        // The index should get updated accordingly.
+        for (int i = 0; i < regionNames.length; i++) {
+          region = cache.getRegion(regionNames[i]);
+          for (int cnt = 1; cnt < numObjects; cnt++) {
+            if (cnt % 2 == 0) {
+              region.destroy(new Portfolio(cnt));
+            }
+          }
+          // Add destroyed entries
+          for (int cnt = 1; cnt < numObjects; cnt++) {
+            if (cnt % 2 == 0) {
+              region.put(new Portfolio(cnt), new Integer(cnt + 100));
+            }
+          }
+        }
+
+        // Execute Query with index.
+        srWithIndex = new SelectResults[qString.length * regionNames.length];
+        try {
+          r = 0;
+          for (int q = 0; q < qString.length; q++) {
+            for (int i = 0; i < regionNames.length; i++) {
+              QueryObserverImpl observer = new QueryObserverImpl();
+              QueryObserverHolder.setInstance(observer);
+              String queryStr = qString[q].replace("REGION_NAME", 
regionNames[i]);
+              Query query = qs.newQuery(queryStr);
+              srWithIndex[r++] =
+                  (SelectResults) query.execute(new Object[] {new Integer(5), 
"active"});
+              if (!observer.isIndexesUsed) {
+                fail("Index not used for query. " + queryStr);
+              }
+            }
+          }
+        } catch (Exception ex) {
+          logger.info("Failed to Execute query", ex);
+          fail("Failed to Execute query.");
+        }
+
+        // Compare results with and without index.
+        for (int i = 0; i < srWithIndex.length; i++) {
+          sr[0][0] = srWithoutIndex[i];
+          sr[0][1] = srWithIndex[i];
+          logger.info("Comparing the result for the query : " + queryString[i]
+              + " Index in ResultSet is: " + i);
+          ssORrs.CompareQueryResultsWithoutAndWithIndexes(sr, 1, queryString);
+        }
+      }
+    });
+  }
+
+  @Test
+  public void validateIndexesAfterInPlaceUpdates() throws CacheException {
+    final Host host = Host.getHost(0);
+    final VM server1 = host.getVM(1);
+    final VM server2 = host.getVM(2);
+    Integer[] intArr = new Integer[2];
+
+    // create indexes
+    server1.invoke(() -> QueryIndexDUnitTest.createIndex());
+    server2.invoke(() -> QueryIndexDUnitTest.createIndex());
+
+    // puts on server2
+    server2.invoke(() -> QueryIndexDUnitTest.doPut());
+    // Do an in-place update of the region entries on server1
+    // This will set the Portfolio objects status to "active".
+    String str = "To get Update in synch thread."; // Else test was exiting 
before the validation
+                                                   // could finish.
+    server1.invoke(() -> doInPlaceUpdate(str));
+    intArr[0] = new Integer(5);
+    intArr[1] = new Integer(0);
+    server1.invoke(() -> validateIndexUpdate(intArr[0], intArr[1]));
+  }
+
+  @Test
+  public void testInPlaceUpdatesWithNulls() throws CacheException {
+    final Host host = Host.getHost(0);
+    final VM server1 = host.getVM(1);
+    final VM server2 = host.getVM(2);
+
+    helpTestDoInplaceUpdates(server1, server2);
+    server1.invoke(() -> QueryIndexDUnitTest.setInPlaceUpdate());
+    server2.invoke(() -> QueryIndexDUnitTest.setInPlaceUpdate());
+    helpTestDoInplaceUpdates(server1, server2);
+  }
+
+  private void helpTestDoInplaceUpdates(VM server1, VM server2) {
+    // create indexes
+    server1.invoke(() -> QueryIndexDUnitTest.createIndex());
+    server2.invoke(() -> QueryIndexDUnitTest.createIndex());
+
+    Integer[] intArr = new Integer[2];
+    // puts on server2
+    server2.invoke(() -> QueryIndexDUnitTest.doPutNulls());
+    // Do an in-place update of the region entries on server1
+    // This will set the Portfolio objects status to "active".
+    String str = "To get Update in synch thread."; // Else test was exiting 
before the validation
+                                                   // could finish.
+    server1.invoke(() -> doInPlaceUpdate(str));
+    intArr[0] = new Integer(5);
+    intArr[1] = new Integer(0);
+    server1.invoke(() -> validateIndexUpdate(intArr[0], intArr[1]));
+
+    server2.invoke(() -> QueryIndexDUnitTest.doPutNulls());
+
+    intArr[0] = new Integer(0);
+    intArr[1] = new Integer(0);
+    server1.invoke(() -> validateIndexUpdate(intArr[0], intArr[1]));
+
+    // This will set the Portfolio objects status to null.
+    server1.invoke(() -> doInPlaceUpdateWithNulls(str));
+    intArr[0] = new Integer(0);
+    intArr[1] = new Integer(0);
+    server1.invoke(() -> validateIndexUpdate(intArr[0], intArr[1]));
+
+    // remove indexes
+    server1.invoke(() -> QueryIndexDUnitTest.removeIndex());
+    server2.invoke(() -> QueryIndexDUnitTest.removeIndex());
+
+  }
+
+  private static void doInPlaceUpdateWithNulls(String str) {
+    Region region = basicGetCache().getRegion("portfolios");
+    Portfolio p = null;
+    if (region == null) {
+      logger.info("REGION IS NULL");
+    }
+    try {
+      for (int i = 0; i <= 4; i++) {
+
+        p = (Portfolio) region.get("" + i);
+        p.status = null;
+        region.put("" + i, p);
+      }
+    } catch (Exception e) {
+      Assert.fail("Caught exception while trying to do put operation", e);
+    }
+  }
+
+  private static void setInPlaceUpdate() {
+    IndexManager.INPLACE_OBJECT_MODIFICATION_FOR_TEST = true;
+  }
+
+  private static void doPutNulls() {
+    Region region = basicGetCache().getRegion("portfolios");
+    if (region == null) {
+      logger.info("REGION IS NULL");
+    }
+    try {
+      for (int i = 0; i <= 4; i++) {
+        Portfolio p = new Portfolio(i);
+        p.status = null;
+        region.put("" + i, p);
+      }
+    } catch (Exception e) {
+      Assert.fail("Caught exception while trying to do put operation", e);
+    }
+  }
+
+  private static void executeQueriesUsingIndexOnOverflowRegions() throws 
Exception {
+    Cache cache = basicGetCache();
+    String[] regionNames = new String[] {"replicateOverFlowRegion",
+        "replicatePersistentOverFlowRegion", "prOverFlowRegion", 
"prPersistentOverFlowRegion",};
+
+
+    QueryService qs = cache.getQueryService();
+    Region region = null;
+
+    String[] qString = new String[] {"SELECT * FROM /REGION_NAME pf WHERE 
pf.ID = 1",
+        "SELECT ID FROM /REGION_NAME pf WHERE pf.ID = 1",
+        "SELECT * FROM /REGION_NAME pf WHERE pf.ID > 10",
+        "SELECT ID FROM /REGION_NAME pf WHERE pf.ID > 10",
+        "SELECT * FROM /REGION_NAME.keys key WHERE key.ID = 1",
+        "SELECT ID FROM /REGION_NAME.keys key WHERE key.ID = 1",
+        "SELECT * FROM /REGION_NAME.keys key WHERE key.ID > 10",
+        "SELECT ID FROM /REGION_NAME.keys key WHERE key.ID > 10",
+        "SELECT entry.value FROM /REGION_NAME.entries entry WHERE 
entry.value.ID = 1",
+        "SELECT entry.key FROM /REGION_NAME.entries entry WHERE entry.value.ID 
> 10",
+        "SELECT entry.getValue() FROM /REGION_NAME.entries entry WHERE 
entry.getValue().getID() = 1",
+        "SELECT entry.getKey() FROM /REGION_NAME.entries entry WHERE 
entry.getValue().getID() > 10",
+        "SELECT entry.getValue() FROM /REGION_NAME.entries entry WHERE 
entry.getValue().boolFunction('active') = false",};
+
+    for (int q = 0; q < qString.length; q++) {
+      for (int i = 0; i < regionNames.length; i++) {
+        QueryObserverImpl observer = new QueryObserverImpl();
+        QueryObserverHolder.setInstance(observer);
+        String queryStr = qString[q].replace("REGION_NAME", regionNames[i]);
+        Query query = qs.newQuery(queryStr);
+        SelectResults results = (SelectResults) query.execute();
+        logger.info("Executed query :" + queryStr + " Result size: " + 
results.asList().size());
+        if (!observer.isIndexesUsed) {
+          fail("Index not used for query. " + queryStr);
+        }
+      }
+    }
+  }
+
+  private static void createIndexOnOverFlowRegions() throws Exception {
+    Cache cache = basicGetCache();
+    String[] regionNames = new String[] {"replicateOverFlowRegion",
+        "replicatePersistentOverFlowRegion", "prOverFlowRegion", 
"prPersistentOverFlowRegion",};
+
+    cache.getLogger().fine("createIndexOnOverFlowRegions()");
+
+    QueryService qs = cache.getQueryService();
+    Region region = null;
+    for (int i = 0; i < regionNames.length; i++) {
+      region = cache.getRegion(regionNames[i]);
+      String indexName = "idIndex" + regionNames[i];
+      cache.getLogger().fine("createIndexOnOverFlowRegions() checking for 
index: " + indexName);
+      try {
+        if (qs.getIndex(region, indexName) == null) {
+          cache.getLogger().fine(
+              "createIndexOnOverFlowRegions() Index doesn't exist, creating 
index: " + indexName);
+          Index i1 = qs.createIndex(indexName, IndexType.FUNCTIONAL, "pf.ID",
+              "/" + regionNames[i] + " pf");
+        }
+        indexName = "keyIdIndex" + regionNames[i];
+        if (qs.getIndex(region, indexName) == null) {
+          cache.getLogger().fine(
+              "createIndexOnOverFlowRegions() Index doesn't exist, creating 
index: " + indexName);
+          Index i2 = qs.createIndex(indexName, IndexType.FUNCTIONAL, "key.ID",
+              "/" + regionNames[i] + ".keys key");
+        }
+        indexName = "entryIdIndex" + regionNames[i];
+        if (qs.getIndex(region, indexName) == null) {
+          cache.getLogger().fine(
+              "createIndexOnOverFlowRegions() Index doesn't exist, creating 
index: " + indexName);
+          Index i2 = qs.createIndex(indexName, IndexType.FUNCTIONAL, 
"entry.value.ID",
+              "/" + regionNames[i] + ".entries entry");
+        }
+        indexName = "entryMethodIndex" + regionNames[i];
+        if (qs.getIndex(region, indexName) == null) {
+          cache.getLogger().fine(
+              "createIndexOnOverFlowRegions() Index doesn't exist, creating 
index: " + indexName);
+          Index i2 = qs.createIndex(indexName, IndexType.FUNCTIONAL, 
"entry.getValue().getID()",
+              "/" + regionNames[i] + ".entries entry");
+        }
+        indexName = "entryMethodWithArgIndex" + regionNames[i];
+        if (qs.getIndex(region, indexName) == null) {
+          cache.getLogger().fine(
+              "createIndexOnOverFlowRegions() Index doesn't exist, creating 
index: " + indexName);
+          Index i2 = qs.createIndex(indexName, IndexType.FUNCTIONAL,
+              "entry.getValue().boolFunction('active')", "/" + regionNames[i] 
+ ".entries entry");
+        }
+      } catch (IndexNameConflictException ice) {
+        // Ignore. The pr may have created the index through
+        // remote index create message from peer.
+      }
+    }
+  }
+
+  private static void createAndLoadOverFlowRegions(String vmName, final 
Boolean createRegions,
+      final Boolean loadRegions) throws Exception {
+    Cache cache = basicGetCache();
+    String[] regionNames = new String[] {"replicateOverFlowRegion",
+        "replicatePersistentOverFlowRegion", "prOverFlowRegion", 
"prPersistentOverFlowRegion",};
+
+    logger.info("CreateAndLoadOverFlowRegions() with vmName " + vmName + " 
createRegions: "
+        + createRegions + " And LoadRegions: " + loadRegions);
+
+    if (createRegions.booleanValue()) {
+      for (int i = 0; i < regionNames.length; i++) {
+        logger.info("Started creating region :" + regionNames[i]);
+        String diskStore = regionNames[i] + vmName + "DiskStore";
+        logger.info("Setting disk store to: " + diskStore);
+        cache.createDiskStoreFactory().create(diskStore);
+        try {
+          AttributesFactory attributesFactory = new AttributesFactory();
+          attributesFactory.setDiskStoreName(diskStore);
+          attributesFactory.setEvictionAttributes(
+              EvictionAttributes.createLRUEntryAttributes(10, 
EvictionAction.OVERFLOW_TO_DISK));
+          if (i == 0) {
+            attributesFactory.setDataPolicy(DataPolicy.REPLICATE);
+          } else if (i == 1) {
+            attributesFactory.setDataPolicy(DataPolicy.PERSISTENT_REPLICATE);
+          } else if (i == 2) {
+            attributesFactory.setDataPolicy(DataPolicy.PARTITION);
+          } else {
+            attributesFactory.setDataPolicy(DataPolicy.PERSISTENT_REPLICATE);
+          }
+          cache.createRegion(regionNames[i], attributesFactory.create());
+          logger.info("Completed creating region :" + regionNames[i]);
+        } catch (Exception e) {
+          Assert.fail("Could not create region" + regionNames[i], e);
+        }
+      }
+    }
+    Region region = null;
+    int numObjects = 50;
+    if (loadRegions.booleanValue()) {
+      for (int i = 0; i < regionNames.length; i++) {
+        region = cache.getRegion(regionNames[i]);
+        // If its just load, try destroy some entries and reload.
+        if (!createRegions.booleanValue()) {
+          logger.info("Started destroying region entries:" + regionNames[i]);
+          for (int cnt = 0; cnt < numObjects / 3; cnt++) {
+            region.destroy(new Portfolio(cnt * 2));
+          }
+        }
+
+        logger.info("Started Loading region :" + regionNames[i]);
+        for (int cnt = 0; cnt < numObjects; cnt++) {
+          region.put(new Portfolio(cnt), new Portfolio(cnt));
+        }
+        logger.info("Completed loading region :" + regionNames[i]);
+      }
+    }
+  }
+
+  private static void validateIndexUpdate(Integer a, Integer b) {
+    QueryService qs = basicGetCache().getQueryService();
+    Query q = qs.newQuery("SELECT DISTINCT * FROM /portfolios where status = 
'active'");
+    QueryObserverImpl observer = new QueryObserverImpl();
+    QueryObserverHolder.setInstance(observer);
+    Object r;
+    try {
+      r = q.execute();
+      int actual = ((Collection) r).size();
+      if (actual != a.intValue()) {
+        fail("Active NOT of the expected size, found " + actual + ", expected 
" + a.intValue());
+      }
+    } catch (Exception e) {
+      Assert.fail("Caught exception while trying to query", e);
+    }
+    if (!observer.isIndexesUsed) {
+      fail("Index not used for query");
+    }
+
+    q = qs.newQuery("SELECT DISTINCT * FROM /portfolios where status = 
'inactive'");
+    observer = new QueryObserverImpl();
+    QueryObserverHolder.setInstance(observer);
+
+    try {
+      r = q.execute();
+      int actual = ((Collection) r).size();
+      if (actual != b.intValue()) {
+        fail("Inactive NOT of the expected size, found " + actual + ", 
expected " + b.intValue());
+      }
+    } catch (Exception e) {
+      Assert.fail("Caught exception while trying to query", e);
+    }
+    if (!observer.isIndexesUsed) {
+      fail("Index not used for query");
+    }
+  }
+
+  private static void createIndex() {
+    Region region = basicGetCache().getRegion("portfolios");
+    if (region == null) {
+      logger.info("The region is not created properly");
+    } else {
+      if (!region.isDestroyed()) {
+        logger.info("Obtained the region with name :" + "portfolios");
+        QueryService qs = basicGetCache().getQueryService();
+        if (qs != null) {
+          try {
+            qs.createIndex("statusIndex", "status", "/portfolios");
+            logger.info("Index statusIndex Created successfully");
+          } catch (IndexNameConflictException e) {
+            Assert.fail("Caught IndexNameConflictException", e);
+          } catch (IndexExistsException e) {
+            Assert.fail("Caught IndexExistsException", e);
+          } catch (QueryException e) {
+            Assert.fail("Caught exception while trying to create index", e);
+          }
+        } else {
+          fail("Could not obtain QueryService for the cache ");
+        }
+      } else {
+        fail("Region.isDestroyed() returned true for region : " + 
"/portfolios");
+      }
+    }
+  }
+
+  private static void validateIndexUsage() {
+    QueryService qs = basicGetCache().getQueryService();
+    Query q = qs.newQuery("SELECT DISTINCT * FROM /portfolios where status = 
'active'");
+    QueryObserverImpl observer = new QueryObserverImpl();
+    QueryObserverHolder.setInstance(observer);
+    Object r;
+    try {
+      r = q.execute();
+      int actual = ((Collection) r).size();
+      if (actual != 1) {
+        fail("Active NOT of the expected size, found " + actual + ", expected 
1");
+      }
+    } catch (Exception e) {
+      Assert.fail("Caught exception while trying to query", e);
+    }
+    if (!observer.isIndexesUsed) {
+      fail("Index not used for query");
+    }
+  }
+
+  private static void removeIndex() {
+    Region region = basicGetCache().getRegion("portfolios");
+    if (region == null) {
+      fail("The region is not created properly");
+    } else {
+      logger.info("Obtained the region with name :" + "portfolios");
+      QueryService qs = basicGetCache().getQueryService();
+      if (qs != null) {
+        try {
+          Collection indexes = qs.getIndexes(region);
+          if (indexes == null) {
+            return; // no IndexManager defined
+          }
+          if (indexes.size() == 0) {
+            return; // no indexes defined
+          }
+          Iterator iter = indexes.iterator();
+          if (iter.hasNext()) {
+            Index idx = (Index) (iter.next());
+            String name = idx.getName();
+            qs.removeIndex(idx);
+            logger.info("Index " + name + " removed successfully");
+          }
+        } catch (Exception e) {
+          Assert.fail("Caught exception while trying to remove index", e);
+        }
+      } else {
+        fail("Unable to obtain QueryService for the cache ");
+      }
+
+    }
+  }
+
+  public static class QueryObserverImpl extends QueryObserverAdapter {
+    boolean isIndexesUsed = false;
+    ArrayList indexesUsed = new ArrayList();
+
+    public void beforeIndexLookup(Index index, int oper, Object key) {
+      indexesUsed.add(index.getName());
+    }
+
+    public void afterIndexLookup(Collection results) {
+      if (results != null) {
+        isIndexesUsed = true;
+      }
+    }
+  }
+
+}

Reply via email to