blob: 0187cd3f27e4c4446191405c12abd57e74333333 [file] [log] [blame]
/*
* 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.CACHE_XML_FILE;
import static org.apache.geode.distributed.ConfigurationProperties.ENABLE_TIME_STATISTICS;
import static org.apache.geode.distributed.ConfigurationProperties.MCAST_PORT;
import static org.apache.geode.distributed.ConfigurationProperties.NAME;
import static org.apache.geode.distributed.ConfigurationProperties.STATISTIC_SAMPLING_ENABLED;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
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 java.util.stream.IntStream;
import org.apache.commons.io.FileUtils;
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.RegionShortcut;
import org.apache.geode.cache.query.CacheUtils;
import org.apache.geode.cache.query.Index;
import org.apache.geode.cache.query.IndexInvalidException;
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.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.cache.LocalRegion;
import org.apache.geode.test.junit.categories.OQLIndexTest;
@Category({OQLIndexTest.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 exceptionoccurred = 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();
FileUtils.deleteDirectory(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();
FileUtils.deleteDirectory(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();
FileUtils.deleteDirectory(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();
FileUtils.deleteDirectory(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());
}
@Test
public void failedIndexCreationCorrectlyRemovesItself() throws Exception {
QueryService qs;
qs = CacheUtils.getQueryService();
Cache cache = CacheUtils.getCache();
cache.createRegionFactory(RegionShortcut.PARTITION).create("portfoliosInPartitionedRegion");
Region region = CacheUtils.getCache().getRegion("/portfoliosInPartitionedRegion");
IntStream.range(0, 3).forEach((i) -> {
region.put(i, new Portfolio(i));
});
Index i1 = qs.createIndex("statusIndex", "secId",
"/portfoliosInPartitionedRegion p, p.positions pos, pos.secId secId");
try {
Index i2 =
qs.createIndex("anotherIndex", "secId", "/portfoliosInPartitionedRegion p, p.positions");
// index should fail to create
fail();
} catch (IndexInvalidException e) {
}
qs.removeIndex(i1);
// This test should not throw an exception if i2 was properly cleaned up.
Index i3 = qs.createIndex("anotherIndex", "secType",
"/portfoliosInPartitionedRegion p, p.positions pos, pos.secType secType");
assertNotNull(i3);
}
private static class QueryObserverImpl extends QueryObserverAdapter {
boolean isIndexesUsed = false;
ArrayList indexesUsed = new ArrayList();
@Override
public void beforeIndexLookup(Index index, int oper, Object key) {
indexesUsed.add(index.getName());
}
@Override
public void afterIndexLookup(Collection results) {
if (results != null) {
isIndexesUsed = true;
}
}
}
}