/* * 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. */ /* * IndexCreationJUnitTest.java * * Created on April 13, 2005, 4:16 PM Added a Test Case for testing the Task, IUM10 : May 16, 2005, * 2:45 PM */ /** */ package org.apache.geode.cache.query.functional; import static org.apache.geode.distributed.ConfigurationProperties.*; import static org.junit.Assert.*; import java.io.File; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.Properties; import java.util.Set; import org.junit.After; import org.junit.Before; import org.junit.Ignore; 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.CacheFactory; import org.apache.geode.cache.EvictionAction; import org.apache.geode.cache.EvictionAttributes; import org.apache.geode.cache.Region; import org.apache.geode.cache.query.CacheUtils; import org.apache.geode.cache.query.Index; import org.apache.geode.cache.query.IndexStatistics; import org.apache.geode.cache.query.IndexType; import org.apache.geode.cache.query.Query; import org.apache.geode.cache.query.QueryInvalidException; import org.apache.geode.cache.query.QueryService; import org.apache.geode.cache.query.SelectResults; import org.apache.geode.cache.query.Utils; import org.apache.geode.cache.query.data.ComparableWrapper; import org.apache.geode.cache.query.data.Portfolio; import org.apache.geode.cache.query.internal.DefaultQueryService; import org.apache.geode.cache.query.internal.QueryObserverAdapter; import org.apache.geode.cache.query.internal.QueryObserverHolder; import org.apache.geode.cache.query.internal.index.CompactMapRangeIndex; import org.apache.geode.cache.query.internal.index.CompactRangeIndex; import org.apache.geode.cache.query.internal.index.IndexProtocol; import org.apache.geode.cache.query.internal.index.RangeIndex; import org.apache.geode.cache.query.internal.types.ObjectTypeImpl; import org.apache.geode.cache.query.internal.types.StructTypeImpl; import org.apache.geode.cache.query.types.ObjectType; import org.apache.geode.cache.query.types.StructType; import org.apache.geode.distributed.DistributedSystem; import org.apache.geode.distributed.internal.InternalDistributedSystem; import org.apache.geode.internal.FileUtil; import org.apache.geode.internal.cache.LocalRegion; import org.apache.geode.test.junit.categories.IntegrationTest; @Category(IntegrationTest.class) public class IndexCreationJUnitTest { private ObjectType resType1 = null; private ObjectType resType2 = null; private int resSize1 = 0; private int resSize2 = 0; private Iterator itert1 = null; private Iterator itert2 = null; private Set set1 = null; private Set set2 = null; private String s1; private String s2; @Before public void setUp() throws java.lang.Exception { CacheUtils.startCache(); Region region = CacheUtils.createRegion("portfolios", Portfolio.class); for (int i = 0; i < 4; i++) { region.put("" + i, new Portfolio(i)); } } @After public void tearDown() throws java.lang.Exception { CacheUtils.closeCache(); } @Test public void testIndexCreation() throws Exception { QueryService qs; qs = CacheUtils.getQueryService(); Index i1 = qs.createIndex("statusIndex", IndexType.FUNCTIONAL, "status", "/portfolios, positions"); // TASK ICM1 Index i2 = qs.createIndex("secIdIndex", IndexType.FUNCTIONAL, "b.secId", "/portfolios pf, pf.positions.values b"); // TASK ICM2 Index i5 = qs.createIndex("intFunctionIndex", IndexType.FUNCTIONAL, "intFunction(pf.getID)", "/portfolios pf, pf.positions b"); Index i6 = qs.createIndex("statusIndex6", IndexType.FUNCTIONAL, "a.status", "/portfolios.values.toArray a, positions"); Index i7 = qs.createIndex("statusIndex7", IndexType.FUNCTIONAL, "a.status", "/portfolios.getValues().asList() a, positions"); Index i8 = qs.createIndex("statusIndex8", IndexType.FUNCTIONAL, "a.status", "/portfolios.values.asSet a, positions"); // TASK ICM6 Object indices[] = {i1, i2, i5, i6, i7, i8}; // remove any commented Index // from Array for (int j = 0; j < indices.length; j++) { CacheUtils.log(((IndexProtocol) indices[j]).isValid()); boolean r = ((IndexProtocol) indices[j]).isValid(); assertTrue("Test: testIndexCreation FAILED", r); CacheUtils.log(((IndexProtocol) indices[j]).getName()); CacheUtils.log("Test: testIndexCreation PASS"); } } @Test public void testIndexCreationWithImports() throws Exception { // Task ID ICM 16 QueryService qs; qs = CacheUtils.getQueryService(); Index idx; try { idx = qs.createIndex("importsIndex", IndexType.FUNCTIONAL, "status", "/portfolios, (map<string,Position>)positions"); fail("Should have thrown a QueryInvalidException"); // can't find type // Position } catch (QueryInvalidException e) { // pass } idx = qs.createIndex("importsIndex", IndexType.FUNCTIONAL, "status", "/portfolios, (map<string,Position>)positions", "import org.apache.geode.cache.\"query\".data.Position"); qs.removeIndex(idx); idx = qs.createIndex("importsIndex2", IndexType.FUNCTIONAL, "status", "/portfolios, positions TYPE Position", "import org.apache.geode.cache.\"query\".data.Position"); } @Test public void testSimilarIndexCreation() throws Exception { // Task ID: ICM17 QueryService qs; qs = CacheUtils.getQueryService(); // boolean exceptionoccured = true; qs.createIndex("statusIndex", IndexType.FUNCTIONAL, "status", "/portfolios, positions"); qs.createIndex("secIdIndex", IndexType.FUNCTIONAL, "b.secId", "/portfolios pf, pf.positions.values b"); try { qs.createIndex("secIdIndexDuplicate", IndexType.FUNCTIONAL, "b.secId", "/portfolios pf, pf.positions.values b"); fail("testSimilarIndexCreation: Allowed duplicate index creation"); } catch (Exception e) { // testSimilarIndexCreation: Exception if duplicate index is // created with diffrenet name but same from clause & expression } try { qs.createIndex("secIdIndexDuplicate", IndexType.FUNCTIONAL, "b1.secId", "/portfolios pf1, pf1.positions.values b1"); fail("testSimilarIndexCreation: Allowed duplicate index creation"); } catch (Exception e) { // testSimilarIndexCreation: Exception if duplicate index is // created with diffrenet name but same from clause & expression } // org.apache.geode.cache.query.IndexExistsException: Similar Index // Exists try { qs.createIndex("statusIndexDuplicate", IndexType.FUNCTIONAL, "b.status", "/portfolios b, positions"); fail("testSimilarIndexCreation: Allowed duplicate index creation"); } catch (Exception e) { // testSimilarIndexCreation: Exception if duplicate index is // created with diffrenet name but same from clause & expression } } @Test public void testInvalidImportsIndexCreation() throws Exception { // Task ID: Invalid Indexes: ICM15 QueryService qs; qs = CacheUtils.getQueryService(); try { qs.createIndex("typeIndex", IndexType.FUNCTIONAL, "\"type\"", "/portfolios pf, pf.positions b", "pf.position1"); // projection attributes are not yet implemented // last parameter is the imports statement, so this is a syntax // error fail("Should have thrown an exception since imports are invalid"); // TASK ICM7 } catch (QueryInvalidException e) { // pass } } @Ignore("TODO: disabled and has no assertions") @Test public void testElementIndexCreation() throws Exception { QueryService qs; qs = CacheUtils.getQueryService(); qs.createIndex("funcReturnSecIdIndex", IndexType.FUNCTIONAL, "pf.funcReturnSecId(element(select distinct pos from /portfolios pf, pf.positions.values as pos where pos.sharesOutstanding = 5000))", "/portfolios pf, pf.positions b"); // TASK ICM8: InvalidIndexCreation // Query q = qs.newQuery("(element(select distinct pos from // /portfolios pf, pf.positions.values as pos where // pos.sharesOutstanding = 5000))"); // Object r=q.execute(); // CacheUtils.log(Utils.printResult(r)); } @Test public void testIndexCreationOnNVLFunction() throws Exception { QueryService qs; qs = CacheUtils.getQueryService(); Query query = null; qs.createIndex("NVLIndex1", IndexType.FUNCTIONAL, "nvl(pf.position2, pf.position1).secId", "/portfolios pf"); query = CacheUtils.getQueryService().newQuery( "select distinct * from /portfolios pf where nvl(pf.position2, pf.position1).secId = 'SUN'"); QueryObserverImpl observer = new QueryObserverImpl(); QueryObserverHolder.setInstance(observer); query.execute(); if (!observer.isIndexesUsed) { fail("NO INDEX USED"); } query = CacheUtils.getQueryService().newQuery( "select distinct nvl(pf.position2, 'inProjection') from /portfolios pf where nvl(pf.position2, pf.position1).secId = 'SUN'"); observer = new QueryObserverImpl(); QueryObserverHolder.setInstance(observer); query.execute(); if (!observer.isIndexesUsed && observer.indexesUsed.size() != 1) { fail("NO INDEX USED"); } } @Test public void testIndexCreationWithImport() throws Exception { // Task ID: ICM16 QueryService qs; qs = CacheUtils.getQueryService(); Index i3 = qs.createIndex("typeIndex", IndexType.FUNCTIONAL, "\"type\"", "/portfolios type Portfolio, positions b", "IMPORT org.apache.geode.cache.\"query\".data.Portfolio"); // TASK ICM3 Region 'IMPORT' not found:....[BUG : Verified Fixed ] // Index i4=(Index)qs.createIndex("boolFunctionIndex", // IndexType.FUNCTIONAL,"boolFunction(pf.status)","/portfolios pf, // pf.positions.values b"); // TASK ICM5 org.apache.geode.cache.query.IndexInvalidException Object indices[] = {i3}; // remove any commented Index from Array for (int j = 0; j < indices.length; j++) { CacheUtils.log(((IndexProtocol) indices[j]).isValid()); boolean r = ((IndexProtocol) indices[j]).isValid(); if (r == true) { CacheUtils.log(((IndexProtocol) indices[j]).getName()); CacheUtils.log("Test: testIndexCreation PASS"); } else { fail("Test: testIndexCreation FAILED"); } } } @Test public void testComparisonBetnWithAndWithoutIndexCreationComparableObject() throws Exception { // Task ID IUM10 SelectResults r[][] = new SelectResults[4][2]; QueryService qs; qs = CacheUtils.getQueryService(); String queries[] = {"select distinct * from /portfolios pf where pf.getCW(pf.ID) = $1", "select distinct * from /portfolios pf where pf.getCW(pf.ID) > $1", "select distinct * from /portfolios pf where pf.getCW(pf.ID) < $1", "select distinct * from /portfolios pf where pf.getCW(pf.ID) != $1" // TASK IUM 10 }; for (int i = 0; i < queries.length; i++) { Query q = null; q = CacheUtils.getQueryService().newQuery(queries[i]); Object params[] = new Object[1]; params[0] = new ComparableWrapper(1); QueryObserverImpl observer = new QueryObserverImpl(); QueryObserverHolder.setInstance(observer); r[i][0] = (SelectResults) q.execute(params); resType1 = (r[i][0]).getCollectionType().getElementType(); resSize1 = ((r[i][0]).size()); set1 = ((r[i][0]).asSet()); // Iterator iter=set1.iterator(); } // Create an Index on status and execute the same query again. qs = CacheUtils.getQueryService(); qs.createIndex("cIndex", IndexType.FUNCTIONAL, "pf.getCW(pf.ID)", "/portfolios pf"); for (int i = 0; i < queries.length; i++) { Query q = null; q = CacheUtils.getQueryService().newQuery(queries[i]); Object params[] = new Object[1]; params[0] = new ComparableWrapper(1); QueryObserverImpl observer2 = new QueryObserverImpl(); QueryObserverHolder.setInstance(observer2); r[i][1] = (SelectResults) q.execute(params); if (!observer2.isIndexesUsed) { fail("FAILED: Index NOT Used"); } resType2 = (r[i][1]).getCollectionType().getElementType(); resSize2 = ((r[i][1]).size()); set2 = ((r[i][1]).asSet()); } CacheUtils.compareResultsOfWithAndWithoutIndex(r, this); } @Test public void testIndexCreationWithIndexOperatorUsage() throws Exception { // Task ID : ICM 18 QueryService qs; qs = CacheUtils.getQueryService(); String[] queries = { "select distinct * from /portfolios pf where pf.collectionHolderMap[(pf.ID).toString()].arr[pf.ID] != -1"}; Object r[][] = new Object[queries.length][2]; for (int i = 0; i < queries.length; i++) { Query q = null; q = qs.newQuery(queries[i]); CacheUtils.getLogger().info("Executing query: " + queries[i]); r[i][0] = q.execute(); CacheUtils.log("Executed query:" + queries[i]); } Index i1 = qs.createIndex("fIndex", IndexType.FUNCTIONAL, "sIter", "/portfolios pf, pf.collectionHolderMap[(pf.ID).toString()].arr sIter"); Index i2 = qs.createIndex("cIndex", IndexType.FUNCTIONAL, "pf.collectionHolderMap[(pf.ID).toString()].arr[pf.ID]", "/portfolios pf"); // BUG # 32498 // Index i3 = qs.createIndex("nIndex", IndexType.FUNCTIONAL, // "pf.collectionHolderMap[((pf.ID%2)).toString()].arr[pf.ID]","/portfolios // pf"); for (int i = 0; i < queries.length; i++) { Query q = null; q = qs.newQuery(queries[i]); CacheUtils.getLogger().info("Executing query: " + queries[i]); QueryObserverImpl observer = new QueryObserverImpl(); QueryObserverHolder.setInstance(observer); r[i][1] = q.execute(); SelectResults results = (SelectResults) r[i][1]; assertTrue(results.size() > 0); CacheUtils.log("Executing query: " + queries[i] + " with index created"); if (!observer.isIndexesUsed) { fail("Index is NOT uesd"); } Iterator itr = observer.indexesUsed.iterator(); assertTrue(itr.hasNext()); String temp = itr.next().toString(); assertEquals(temp, "cIndex"); } CacheUtils.log(((RangeIndex) i1).dump()); CacheUtils.log(((CompactRangeIndex) i2).dump()); StructSetOrResultsSet ssOrrs = new StructSetOrResultsSet(); ssOrrs.CompareQueryResultsWithoutAndWithIndexes(r, queries.length, queries); // CacheUtils.log(((RangeIndex)i3).dump()); // Index i3 = // qs.createIndex("Task6Index",IndexType.FUNCTIONAL,"pos.secId","/portfolios // pf, pf.positions.values pos"); } @Test public void testIndexCreationOnKeys() throws Exception { // Task ID : ICM 9 QueryService qs; qs = CacheUtils.getQueryService(); Index i1 = qs.createIndex("kIndex", IndexType.FUNCTIONAL, "pf", "/portfolios.keys pf"); Index i2 = qs.createIndex("k1Index", IndexType.FUNCTIONAL, "key", "/portfolios.entries"); Index i3 = qs.createIndex("k2Index", IndexType.FUNCTIONAL, "pf", "/portfolios.keys.toArray pf"); // Index i4 = qs.createIndex("k3Index", IndexType.FUNCTIONAL, // "pf","/portfolios.keys().toArray() pf"); Index i5 = qs.createIndex("k4Index", IndexType.FUNCTIONAL, "pf", "/portfolios.getKeys.asList pf"); // Index i5 = qs.createIndex("k5Index", IndexType.FUNCTIONAL, // "pf","/portfolios.getKeys.asList() pf"); Index i6 = qs.createIndex("k5Index", IndexType.FUNCTIONAL, "pf", "/portfolios.getKeys.asSet() pf"); // Index i5 = qs.createIndex("k5Index", IndexType.FUNCTIONAL, // "pf","/portfolios.getKeys.asSet pf"); CacheUtils.log(((CompactRangeIndex) i1).dump()); CacheUtils.log(((CompactRangeIndex) i2).dump()); CacheUtils.log(((CompactRangeIndex) i3).dump()); CacheUtils.log(((CompactRangeIndex) i5).dump()); CacheUtils.log(((CompactRangeIndex) i6).dump()); } @Test public void testIndexCreationOnRegionEntry() throws Exception { // Task ID : ICM11 QueryService qs; qs = CacheUtils.getQueryService(); Index i1 = qs.createIndex("r1Index", IndexType.FUNCTIONAL, "secId", "/portfolios.values['1'].positions.values"); qs.createIndex("r12Index", IndexType.FUNCTIONAL, "secId", "/portfolios['1'].positions.values"); CacheUtils.log(((CompactRangeIndex) i1).dump()); // CacheUtils.log(((RangeIndex)i2).dump()); } /** * Creation of index on a path derived from Region.Entry object obtained via entrySet , fails as * that function was not supported in the QRegion & DummyQRegion */ @Test public void testBug36823() throws Exception { QueryService qs; qs = CacheUtils.getQueryService(); qs.createIndex("entryIndex", IndexType.FUNCTIONAL, "value.getID()", "/portfolios.entrySet pf"); Region rgn = CacheUtils.getRegion("/portfolios"); rgn.put("4", new Portfolio(4)); rgn.put("5", new Portfolio(5)); Query qr = qs.newQuery("Select distinct * from /portfolios.entrySet pf where pf.value.getID() = 4"); SelectResults sr = (SelectResults) qr.execute(); assertEquals(sr.size(), 1); } /** * Creation of index on key path derived from Region.Entry object obtained via keySet , fails as * that function was not supported in the QRegion & DummyQRegion */ @Test public void testBug36590() throws Exception { QueryService qs; qs = CacheUtils.getQueryService(); qs.createIndex("keyIndex", IndexType.FUNCTIONAL, "keys", "/portfolios.keySet keys"); Region rgn = CacheUtils.getRegion("/portfolios"); rgn.put("4", new Portfolio(4)); rgn.put("5", new Portfolio(5)); Query qr = qs.newQuery("Select distinct * from /portfolios.keySet keys where keys = '4'"); SelectResults sr = (SelectResults) qr.execute(); assertEquals(sr.size(), 1); } /** * The Index maintenance has a bug as it does not re-evaluate the index maintenance collection in * the IMQEvaluator when an entry gets modified & so the index resultset is messed up */ @Test public void testBug36591() throws Exception { QueryService qs; qs = CacheUtils.getQueryService(); Index i1 = qs.createIndex("keyIndex", IndexType.FUNCTIONAL, "ks.hashCode", "/portfolios.keys ks"); Region rgn = CacheUtils.getRegion("/portfolios"); rgn.put("4", new Portfolio(4)); rgn.put("5", new Portfolio(5)); CacheUtils.log(((CompactRangeIndex) i1).dump()); Query qr = qs.newQuery("Select distinct * from /portfolios.keys keys where keys.hashCode >= $1"); SelectResults sr = (SelectResults) qr.execute(new Object[] {new Integer(-1)}); assertEquals(6, sr.size()); } /** * Creation of index on a path derived from Region.Entry object obtained via entrySet , fails as * that function was not supported in the QRegion & DummyQRegion */ @Test public void testBug43519() throws Exception { QueryService qs; qs = CacheUtils.getQueryService(); Index index = qs.createIndex("shortIndex", IndexType.FUNCTIONAL, "p.shortID", "/portfolios p"); Region rgn = CacheUtils.getRegion("/portfolios"); for (int i = 1; i <= 10; i++) { String key = "" + i; Portfolio p = new Portfolio(i); p.shortID = new Short(key); // addToIndex rgn.put(key, p); // updateIndex rgn.put(key, p); if (i % 2 == 0) { // destroy from index. rgn.destroy(key); } } Query qr = qs.newQuery("Select p.shortID from /portfolios p where p.shortID < 5"); SelectResults sr = (SelectResults) qr.execute(); assertEquals(sr.size(), 2); } /** * Test the Index maiantenance as it may use the method keys() of QRegion instead of DummyQRegion * while running an IndexMaintenanceQuery */ @Test public void testIMQFailureAsMethodKeysNAInDummyQRegion() throws Exception { QueryService qs; qs = CacheUtils.getQueryService(); Index i1 = qs.createIndex("keyIndex", IndexType.FUNCTIONAL, "ks.hashCode", "/portfolios.keys() ks"); Region rgn = CacheUtils.getRegion("/portfolios"); rgn.put("4", new Portfolio(4)); rgn.put("5", new Portfolio(5)); CacheUtils.log(((CompactRangeIndex) i1).dump()); Query qr = qs.newQuery( "Select distinct keys.hashCode from /portfolios.keys() keys where keys.hashCode >= $1"); SelectResults sr = (SelectResults) qr.execute(new Object[] {new Integer(-1)}); assertEquals(6, sr.size()); } @Test public void testIndexCreationWithFunctions() throws Exception { // Task ID : ICM14 QueryService qs; qs = CacheUtils.getQueryService(); Index i1 = qs.createIndex("SetSecIDIndex1", IndexType.FUNCTIONAL, "b.secId", "/portfolios.asSet pf, pf.positions.values b"); Index i2 = qs.createIndex("ListSecIDIndex2", IndexType.FUNCTIONAL, "b.secId", "/portfolios.asList pf, pf.positions.values b"); Index i3 = qs.createIndex("ArraySecIDIndex3", IndexType.FUNCTIONAL, "b.secId", "/portfolios.toArray pf, pf.positions.values b"); CacheUtils.log(((RangeIndex) i1).dump()); CacheUtils.log(((RangeIndex) i2).dump()); CacheUtils.log(((RangeIndex) i3).dump()); } @Test public void testInvalidIndexes() throws Exception { // Task ID: ICM15 QueryService qs; qs = CacheUtils.getQueryService(); try { Index i1 = qs.createIndex("r1Index", IndexType.FUNCTIONAL, "secId", "/portfolios.toArray[1].positions.values"); CacheUtils.log(((RangeIndex) i1).dump()); fail("Index creation should have failed"); } catch (Exception e) { } try { Index i2 = qs.createIndex("r12Index", IndexType.FUNCTIONAL, "secId", "/portfolios.asList[1].positions.values"); CacheUtils.log(((RangeIndex) i2).dump()); fail("Index creation should have failed"); } catch (Exception e) { } } @Test public void testIndexCreationWithFunctionsinFromClause() throws Exception { // Task ID: ICM13 QueryService qs; qs = CacheUtils.getQueryService(); // BUG #32586 : FIXED Index i1 = qs.createIndex("Index11", IndexType.FUNCTIONAL, "status", "/portfolios.values.toArray()"); Index i2 = qs.createIndex("Index12", IndexType.FUNCTIONAL, "ID", "/portfolios.values.asSet"); Index i3 = qs.createIndex("Index13", IndexType.FUNCTIONAL, "ID", "/portfolios.values.asList"); qs.createIndex("Index14", IndexType.FUNCTIONAL, "value.ID", "/portfolios.entries.toArray()"); qs.createIndex("Index15", IndexType.FUNCTIONAL, "value.ID", "/portfolios.entries.asSet"); qs.createIndex("Index16", IndexType.FUNCTIONAL, "value.ID", "/portfolios.entries.asList"); // BUG #32586 : FIXED qs.createIndex("Index17", IndexType.FUNCTIONAL, "kIter", "/portfolios.keys.toArray() kIter"); qs.createIndex("Index18", IndexType.FUNCTIONAL, "kIter", "/portfolios.keys.asSet kIter"); qs.createIndex("Index19", IndexType.FUNCTIONAL, "kIter", "/portfolios.keys.asList kIter"); CacheUtils.log(((CompactRangeIndex) i1).dump()); CacheUtils.log(((CompactRangeIndex) i2).dump()); CacheUtils.log(((CompactRangeIndex) i3).dump()); } @Test public void testIndexObjectTypeWithRegionConstraint() throws Exception { QueryService qs; qs = CacheUtils.getQueryService(); Index i1 = qs.createIndex("Index1", IndexType.FUNCTIONAL, "b.secId", "/portfolios pf, pf.positions.values b"); ObjectType type = ((IndexProtocol) i1).getResultSetType(); String fieldNames[] = {"index_iter1", "index_iter2"}; ObjectType fieldTypes[] = {new ObjectTypeImpl(Portfolio.class), new ObjectTypeImpl(Object.class)}; // ObjectType expectedType = new StructTypeImpl( fieldNames,fieldTypes); ObjectType expectedType = new StructTypeImpl(fieldNames, fieldTypes); if (!(type instanceof StructType && type.equals(expectedType))) { fail( "The ObjectType obtained from index is not of the expected type. Type obtained from index=" + type); } Index i2 = qs.createIndex("Index2", IndexType.FUNCTIONAL, "pf.ID", "/portfolios.values pf"); type = ((IndexProtocol) i2).getResultSetType(); expectedType = new ObjectTypeImpl(Portfolio.class); if (!type.equals(expectedType)) { fail( "The ObjectType obtained from index is not of the expected type. Type obtained from index=" + type); } Index i3 = qs.createIndex("Index3", IndexType.FUNCTIONAL, "pos.secId", "/portfolios['0'].positions.values pos"); type = ((IndexProtocol) i3).getResultSetType(); expectedType = new ObjectTypeImpl(Object.class); if (!type.equals(expectedType)) { fail( "The ObjectType obtained from index is not of the expected type. Type obtained from index=" + type); } Index i4 = qs.createIndex("Index4", IndexType.PRIMARY_KEY, "ID", "/portfolios"); type = ((IndexProtocol) i4).getResultSetType(); expectedType = new ObjectTypeImpl(Portfolio.class); if (!type.equals(expectedType)) { fail( "The ObjectType obtained from index is not of the expected type. Type obtained from index=" + type); } } @Test public void testIndexOnOverflowRegion() throws Exception { String regionName = "portfolios_overflow"; // overflow region. AttributesFactory attributesFactory = new AttributesFactory(); attributesFactory.setValueConstraint(Portfolio.class); attributesFactory.setEvictionAttributes( EvictionAttributes.createLRUEntryAttributes(1, EvictionAction.OVERFLOW_TO_DISK)); Region region = CacheUtils.createRegion(regionName, attributesFactory.create(), true); for (int i = 0; i < 4; i++) { region.put(new Portfolio(i), new Portfolio(i)); } QueryService qs = CacheUtils.getQueryService(); // Currently supported with compact range-index. Index i1 = qs.createIndex("idIndex", IndexType.FUNCTIONAL, "pf.ID", "/portfolios_overflow pf"); Index i2 = qs.createIndex("keyIdIndex", IndexType.FUNCTIONAL, "key.ID", "/portfolios_overflow.keys key"); // Not yet supported with range-index. try { Index i3 = qs.createIndex("idIndex2", IndexType.FUNCTIONAL, "pf.ID", "/portfolios_overflow pf, pf.positions pos"); fail("Range index not supported on overflow region."); } catch (UnsupportedOperationException ex) { // Expected. } // Execute query. String[] queryStr = new String[] {"Select * from /portfolios_overflow pf where pf.ID = 2", "Select * from /portfolios_overflow.keys key where key.ID = 2", "Select * from /portfolios_overflow pf where pf.ID > 1", "Select * from /portfolios_overflow pf where pf.ID < 2",}; int[] resultSize = new int[] {1, 1, 2, 2}; for (int i = 0; i < queryStr.length; i++) { Query q = qs.newQuery(queryStr[i]); QueryObserverImpl observer = new QueryObserverImpl(); QueryObserverHolder.setInstance(observer); SelectResults results = (SelectResults) q.execute(); if (!observer.isIndexesUsed) { fail("Index not used for query. " + queryStr[i]); } assertEquals(results.size(), resultSize[i]); } for (int i = 0; i < 10; i++) { region.put(new Portfolio(i), new Portfolio(i)); } // Persistent overflow region. } @Test public void testMapKeyIndexCreation_1_NonCompactType() throws Exception { QueryService qs; qs = CacheUtils.getQueryService(); Index i1 = qs.createIndex("Index1", IndexType.FUNCTIONAL, "pf.positions[*]", "/portfolios pf"); assertEquals(i1.getCanonicalizedIndexedExpression(), "index_iter1.positions[*]"); assertTrue(i1 instanceof CompactMapRangeIndex); } @Test public void testMapKeyIndexCreation_2_NonCompactType() throws Exception { QueryService qs; qs = CacheUtils.getQueryService(); Index i1 = qs.createIndex("Index1", IndexType.FUNCTIONAL, "pf.positions['key1','key2','key3']", "/portfolios pf"); assertEquals(i1.getCanonicalizedIndexedExpression(), "index_iter1.positions['key1','key2','key3']"); assertTrue(i1 instanceof CompactMapRangeIndex); CompactMapRangeIndex mri = (CompactMapRangeIndex) i1; Object mapKeys[] = mri.getMapKeysForTesting(); assertEquals(mapKeys.length, 3); Set<String> keys = new HashSet<String>(); keys.add("key1"); keys.add("key2"); keys.add("key3"); for (Object key : mapKeys) { keys.remove(key); } assertTrue(keys.isEmpty()); String[] patterns = mri.getPatternsForTesting(); assertEquals(patterns.length, 3); Set<String> patternsSet = new HashSet<String>(); patternsSet.add("index_iter1.positions['key1']"); patternsSet.add("index_iter1.positions['key2']"); patternsSet.add("index_iter1.positions['key3']"); for (String ptrn : patterns) { patternsSet.remove(ptrn); } assertTrue(patternsSet.isEmpty()); assertEquals(mri.getIndexedExpression(), "pf.positions['key1','key2','key3']"); } /** * Test for bug 46872, make sure we recover the index correctly if the cache.xml changes for a * persistent region. */ @Test public void testIndexCreationFromXML() throws Exception { InternalDistributedSystem.getAnyInstance().disconnect(); File file = new File("persistData0"); file.mkdir(); { Properties props = new Properties(); props.setProperty(NAME, "test"); props.setProperty(MCAST_PORT, "0"); props.setProperty(CACHE_XML_FILE, getClass().getResource("index-creation-with-eviction.xml").toURI().getPath()); DistributedSystem ds = DistributedSystem.connect(props); // Create the cache which causes the cache-xml-file to be parsed Cache cache = CacheFactory.create(ds); QueryService qs = cache.getQueryService(); Region region = cache.getRegion("mainReportRegion"); for (int i = 0; i < 100; i++) { Portfolio pf = new Portfolio(i); pf.setCreateTime(i); region.put("" + i, pf); } // verify that a query on the creation time works as expected SelectResults results = (SelectResults) qs .newQuery( "<trace>SELECT * FROM /mainReportRegion.entrySet mr Where mr.value.createTime > 1L and mr.value.createTime < 3L") .execute(); assertEquals("OQL index results did not match", 1, results.size()); cache.close(); ds.disconnect(); } { Properties props = new Properties(); props.setProperty(NAME, "test"); props.setProperty(MCAST_PORT, "0"); // Using a different cache.xml that changes some region properties // That will force the disk code to copy the region entries. props.setProperty(CACHE_XML_FILE, getClass().getResource("index-creation-without-eviction.xml").toURI().getPath()); DistributedSystem ds = DistributedSystem.connect(props); Cache cache = CacheFactory.create(ds); QueryService qs = cache.getQueryService(); Region region = cache.getRegion("mainReportRegion"); // verify that a query on the creation time works as expected SelectResults results = (SelectResults) qs .newQuery( "<trace>SELECT * FROM /mainReportRegion.entrySet mr Where mr.value.createTime > 1L and mr.value.createTime < 3L") .execute(); assertEquals("OQL index results did not match", 1, results.size()); ds.disconnect(); FileUtil.delete(file); } } @Test public void testIndexCreationFromXMLForLocalScope() throws Exception { InternalDistributedSystem.getAnyInstance().disconnect(); File file = new File("persistData0"); file.mkdir(); Properties props = new Properties(); props.setProperty(NAME, "test"); props.setProperty(MCAST_PORT, "0"); props.setProperty(CACHE_XML_FILE, getClass().getResource("index-creation-without-eviction.xml").toURI().getPath()); DistributedSystem ds = DistributedSystem.connect(props); Cache cache = CacheFactory.create(ds); Region localRegion = cache.getRegion("localRegion"); for (int i = 0; i < 100; i++) { Portfolio pf = new Portfolio(i); localRegion.put("" + i, pf); } QueryService qs = cache.getQueryService(); Index ind = qs.getIndex(localRegion, "localIndex"); assertNotNull("Index localIndex should have been created ", ind); // verify that a query on the creation time works as expected SelectResults results = (SelectResults) qs .newQuery("<trace>SELECT * FROM " + localRegion.getFullPath() + " Where ID > 0").execute(); assertEquals("OQL index results did not match", 99, results.size()); ds.disconnect(); FileUtil.delete(file); } @Test public void testIndexCreationFromXMLForDiskLocalScope() throws Exception { InternalDistributedSystem.getAnyInstance().disconnect(); File file = new File("persistData0"); // TODO: use TemporaryFolder file.mkdir(); Properties props = new Properties(); props.setProperty(NAME, "test"); props.setProperty(MCAST_PORT, "0"); props.setProperty(CACHE_XML_FILE, getClass().getResource("index-creation-without-eviction.xml").toURI().getPath()); DistributedSystem ds = DistributedSystem.connect(props); Cache cache = CacheFactory.create(ds); Region localDiskRegion = cache.getRegion("localDiskRegion"); for (int i = 0; i < 100; i++) { Portfolio pf = new Portfolio(i); localDiskRegion.put("" + i, pf); } QueryService qs = cache.getQueryService(); Index ind = qs.getIndex(localDiskRegion, "localDiskIndex"); assertNotNull("Index localIndex should have been created ", ind); // verify that a query on the creation time works as expected SelectResults results = (SelectResults) qs .newQuery( "<trace>SELECT * FROM " + localDiskRegion.getFullPath() + " Where status = 'active'") .execute(); assertEquals("OQL index results did not match", 50, results.size()); ds.disconnect(); FileUtil.delete(file); } @Test public void testIndexInitializationForOverFlowRegions() throws Exception { InternalDistributedSystem.getAnyInstance().disconnect(); File file = new File("persistData0"); file.mkdir(); { Properties props = new Properties(); props.setProperty(NAME, "test"); props.setProperty(MCAST_PORT, "0"); props.setProperty(STATISTIC_SAMPLING_ENABLED, "true"); props.setProperty(ENABLE_TIME_STATISTICS, "true"); props.setProperty(CACHE_XML_FILE, getClass().getResource("index-recovery-overflow.xml").toURI().getPath()); DistributedSystem ds = DistributedSystem.connect(props); // Create the cache which causes the cache-xml-file to be parsed Cache cache = CacheFactory.create(ds); QueryService qs = cache.getQueryService(); Region region = cache.getRegion("mainReportRegion"); for (int i = 0; i < 100; i++) { Portfolio pf = new Portfolio(i); pf.setCreateTime(i); region.put("" + i, pf); } IndexStatistics is1 = qs.getIndex(region, "status").getStatistics(); assertEquals(2, is1.getNumberOfKeys()); assertEquals(100, is1.getNumberOfValues()); IndexStatistics is2 = qs.getIndex(region, "ID").getStatistics(); assertEquals(100, is2.getNumberOfKeys()); assertEquals(100, is2.getNumberOfValues()); // verify that a query on the creation time works as expected SelectResults results = (SelectResults) qs .newQuery( "<trace>SELECT * FROM /mainReportRegion.entrySet mr Where mr.value.createTime > 1L and mr.value.createTime < 3L") .execute(); assertEquals("OQL index results did not match", 1, results.size()); cache.close(); ds.disconnect(); } { Properties props = new Properties(); props.setProperty(NAME, "test"); props.setProperty(MCAST_PORT, "0"); props.setProperty(STATISTIC_SAMPLING_ENABLED, "true"); props.setProperty(ENABLE_TIME_STATISTICS, "true"); props.setProperty(CACHE_XML_FILE, getClass().getResource("index-recovery-overflow.xml").toURI().getPath()); DistributedSystem ds = DistributedSystem.connect(props); Cache cache = CacheFactory.create(ds); QueryService qs = cache.getQueryService(); Region region = cache.getRegion("mainReportRegion"); assertTrue("Index initialization time should not be 0.", ((LocalRegion) region).getCachePerfStats().getIndexInitializationTime() > 0); IndexStatistics is1 = qs.getIndex(region, "status").getStatistics(); assertEquals(2, is1.getNumberOfKeys()); assertEquals(100, is1.getNumberOfValues()); IndexStatistics is2 = qs.getIndex(region, "ID").getStatistics(); assertEquals(100, is2.getNumberOfKeys()); assertEquals(100, is2.getNumberOfValues()); // verify that a query on the creation time works as expected SelectResults results = (SelectResults) qs .newQuery( "<trace>SELECT * FROM /mainReportRegion.entrySet mr Where mr.value.createTime > 1L and mr.value.createTime < 3L") .execute(); assertEquals("OQL index results did not match", 1, results.size()); ds.disconnect(); FileUtil.delete(file); } } @Test public void testIndexCreationWithoutLoadingData() throws Exception { QueryService qs; qs = CacheUtils.getQueryService(); Index i1 = ((DefaultQueryService) qs).createIndex("statusIndex", IndexType.FUNCTIONAL, "status", "/portfolios", null, false); Index i2 = ((DefaultQueryService) qs).createIndex("secIndex", IndexType.FUNCTIONAL, "pos.secId", "/portfolios p, p.positions.values pos", null, false); Index i3 = ((DefaultQueryService) qs).createIndex("statusHashIndex", IndexType.HASH, "status", "/portfolios", null, false); assertEquals("Index should have been empty ", 0, i1.getStatistics().getNumberOfKeys()); assertEquals("Index should have been empty ", 0, i1.getStatistics().getNumberOfValues()); assertEquals("Index should have been empty ", 0, i2.getStatistics().getNumberOfKeys()); assertEquals("Index should have been empty ", 0, i2.getStatistics().getNumberOfValues()); assertEquals("Index should have been empty ", 0, i3.getStatistics().getNumberOfKeys()); assertEquals("Index should have been empty ", 0, i3.getStatistics().getNumberOfValues()); qs.removeIndexes(); i1 = ((DefaultQueryService) qs).createIndex("statusIndex", IndexType.FUNCTIONAL, "status", "/portfolios", null, true); i2 = ((DefaultQueryService) qs).createIndex("secIndex", IndexType.FUNCTIONAL, "pos.secId", "/portfolios p, p.positions.values pos", null, true); i3 = ((DefaultQueryService) qs).createIndex("statusHashIndex", IndexType.HASH, "status", "/portfolios", null, true); assertEquals("Index should not have been empty ", 2, i1.getStatistics().getNumberOfKeys()); assertEquals("Index should not have been empty ", 4, i1.getStatistics().getNumberOfValues()); assertEquals("Index should not have been empty ", 8, i2.getStatistics().getNumberOfKeys()); assertEquals("Index should not have been empty ", 8, i2.getStatistics().getNumberOfValues()); assertEquals("Index should not have been empty ", 0, i3.getStatistics().getNumberOfKeys()); // hash // index // does // not // have // keys assertEquals("Index should not have been empty ", 4, i3.getStatistics().getNumberOfValues()); } private 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; } } } }