blob: 1c22e11ad606cee2dd5936b5960942bdf18405d1 [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.
*/
package org.apache.geode.cache.query.dunit;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.stream.IntStream;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.apache.geode.cache.Cache;
import org.apache.geode.cache.DataPolicy;
import org.apache.geode.cache.PartitionAttributesFactory;
import org.apache.geode.cache.Region;
import org.apache.geode.cache.query.Index;
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.internal.QueryObserverAdapter;
import org.apache.geode.cache.query.internal.QueryObserverHolder;
import org.apache.geode.test.dunit.cache.internal.JUnit4CacheTestCase;
import org.apache.geode.test.junit.categories.OQLIndexTest;
@Category({OQLIndexTest.class})
public class CorruptedIndexIntegrationTest extends JUnit4CacheTestCase {
@Test
public void putMustSucceedAndIndexInvalidatedWhenAPutCorruptsAnIndex() throws Exception {
String queryString = "SELECT * FROM /REGION_NAME WHERE ID = 3";
String regionName = "REGION_NAME";
Cache cache = getCache();
Region region =
cache.createRegionFactory().setDataPolicy(DataPolicy.PARTITION).create(regionName);
QueryService queryService = cache.getQueryService();
Index idIndex = queryService.createIndex("idIndex", "ID", "/" + regionName);
Index exceptionIndex =
queryService.createIndex("exceptionIndex", "throwExceptionMethod", "/" + regionName);
IntStream.rangeClosed(1, 3).forEach(i -> region.put(i, new Portfolio(i)));
assertEquals("Uncorrupted index must have all the entries", 3,
idIndex.getStatistics().getNumberOfValues());
assertEquals("Corrupted index should not have indexed any entries", 0,
exceptionIndex.getStatistics().getNumberOfValues());
SelectResults results = (SelectResults) queryService.newQuery(queryString).execute();
assertEquals("Query execution must be successful ", 1, results.size());
}
@Test
public void indexCreationMustFailIfRegionEntriesAreNotCompatible() throws Exception {
String queryString = "SELECT * FROM /REGION_NAME WHERE ID = 3";
String regionName = "REGION_NAME";
Cache cache = getCache();
Region region =
cache.createRegionFactory().setDataPolicy(DataPolicy.PARTITION).create(regionName);
QueryService queryService = cache.getQueryService();
IntStream.rangeClosed(1, 3).forEach(i -> region.put(i, new Portfolio(i)));
Index idIndex = queryService.createIndex("idIndex", "ID", "/" + regionName);
try {
queryService.createIndex("exceptionIndex", "throwExceptionMethod", "/" + regionName);
fail();
} catch (Exception exception) {
System.out.println("Exception expected!");
}
assertEquals("Uncorrupted index must have all the entries ", 3,
idIndex.getStatistics().getNumberOfValues());
SelectResults results = (SelectResults) queryService.newQuery(queryString).execute();
assertEquals("Query execution must be successful ", 1, results.size());
}
class QueryObserverImpl extends QueryObserverAdapter {
boolean isIndexesUsed = false;
final 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;
}
}
public void reset() {
this.isIndexesUsed = false;
this.indexesUsed.clear();
}
}
@Test
public void putMustSucceedWhenTheRangeIndexIsCorrupted() throws Exception {
String regionName = "portfolio";
String INDEX_NAME = "key_index1";
PartitionAttributesFactory partitionAttributes = new PartitionAttributesFactory();
partitionAttributes.setTotalNumBuckets(1);
Cache cache = getCache();
Region region = cache.createRegionFactory().setDataPolicy(DataPolicy.PARTITION)
.setPartitionAttributes(partitionAttributes.create()).create(regionName);
Portfolio p = new Portfolio(1, 2);
HashMap map1 = new HashMap();
map1.put("SUN", 1);
map1.put("IBM", 2);
map1.put("AOL", 4);
p.positions = map1;
region.put(1, p);
QueryService queryService = cache.getQueryService();
Index keyIndex1 = queryService.createIndex(INDEX_NAME, "positions[*]", "/portfolio");
Portfolio p2 = new Portfolio(3, 4);
HashMap map2 = new HashMap();
map2.put("APPL", 3);
map2.put("AOL", "hello");
p2.positions = map2;
region.put(2, p2);
assertEquals("Put must be successful", 2, region.size());
assertEquals("Index must be invalid at this point ", false, keyIndex1.isValid());
QueryObserverImpl observer = new QueryObserverImpl();
QueryObserverHolder.setInstance(observer);
SelectResults results = (SelectResults) queryService
.newQuery(
"select * from /portfolio p where p.positions['AOL'] = 'hello' OR p.positions['IBM'] = 2")
.execute();
assertEquals("Correct results expected from the query execution ", 2, results.size());
assertEquals("No index must be used while executing the query ", 0,
observer.indexesUsed.size());
}
@Test
public void putMustSucceedButShouldNotbeAddedtoIndexWhenTheRangeIndexIsCorrupted()
throws Exception {
String regionName = "portfolio";
String INDEX_NAME = "key_index1";
PartitionAttributesFactory partitionAttributes = new PartitionAttributesFactory();
partitionAttributes.setTotalNumBuckets(1);
Cache cache = getCache();
Region region = cache.createRegionFactory().setDataPolicy(DataPolicy.PARTITION)
.setPartitionAttributes(partitionAttributes.create()).create(regionName);
Portfolio p = new Portfolio(1, 2);
HashMap map1 = new HashMap();
map1.put("SUN", 1);
map1.put("IBM", 2);
map1.put("AOL", 4);
p.positions = map1;
region.put(1, p);
QueryService queryService = cache.getQueryService();
Index keyIndex1 = queryService.createIndex(INDEX_NAME, "positions[*]", "/portfolio");
Portfolio p2 = new Portfolio(3, 4);
HashMap map2 = new HashMap();
map2.put("APPL", 3);
map2.put("AOL", "hello");
p2.positions = map2;
region.put(2, p2);
Portfolio p3 = new Portfolio(5, 6);
HashMap map3 = new HashMap();
map3.put("APPL", 4);
map3.put("AOL", "world");
p3.positions = map3;
region.put(3, p3);
assertEquals("Put must be successful", 3, region.size());
assertEquals("Index must be invalid at this point ", false, keyIndex1.isValid());
assertEquals("No new entries must be added to the corrupted index", 4,
keyIndex1.getStatistics().getNumberOfValues());
QueryObserverImpl observer = new QueryObserverImpl();
QueryObserverHolder.setInstance(observer);
SelectResults results = (SelectResults) queryService
.newQuery(
"select * from /portfolio p where p.positions['AOL'] = 'hello' OR p.positions['IBM'] = 2")
.execute();
assertEquals("Correct results expected from the query execution ", 2, results.size());
assertEquals("No index must be used while executing the query ", 0,
observer.indexesUsed.size());
}
@Test
public void rangeIndexCreationMustFailIfRegionEntriesAreNotCompatible() throws Exception {
String regionName = "portfolio";
String INDEX_NAME = "key_index1";
PartitionAttributesFactory partitionAttributes = new PartitionAttributesFactory();
partitionAttributes.setTotalNumBuckets(1);
Cache cache = getCache();
Region region = cache.createRegionFactory().setDataPolicy(DataPolicy.PARTITION)
.setPartitionAttributes(partitionAttributes.create()).create(regionName);
Portfolio p = new Portfolio(1, 2);
HashMap map1 = new HashMap();
map1.put("SUN", 1);
map1.put("IBM", 2);
map1.put("AOL", 4);
p.positions = map1;
region.put(1, p);
Portfolio p2 = new Portfolio(3, 4);
HashMap map2 = new HashMap();
map2.put("APPL", 3);
map2.put("AOL", "hello");
p2.positions = map2;
region.put(2, p2);
assertEquals("Put must be successful", 2, region.size());
QueryService queryService = cache.getQueryService();
try {
queryService.createIndex(INDEX_NAME, "positions[*]", "/portfolio");
fail();
} catch (Exception exception) {
System.out.println("Expected Exception " + exception);
}
assertEquals("There should be no index present", null,
queryService.getIndex(region, INDEX_NAME));
QueryObserverImpl observer = new QueryObserverImpl();
QueryObserverHolder.setInstance(observer);
SelectResults results = (SelectResults) queryService
.newQuery(
"select * from /portfolio p where p.positions['AOL'] = 'hello' OR p.positions['IBM'] = 2")
.execute();
assertEquals("Current results expected from the query execution ", 2, results.size());
assertEquals("No index must be used while executing the query ", 0,
observer.indexesUsed.size());
}
@Test
public void rangeIndexCreationMustPassIfEntriesArePresentInDifferentBucketsAndQueriesMustUseThem()
throws Exception {
String regionName = "portfolio";
String INDEX_NAME = "key_index1";
Cache cache = getCache();
Region region =
cache.createRegionFactory().setDataPolicy(DataPolicy.PARTITION).create(regionName);
Portfolio p = new Portfolio(1, 2);
HashMap map1 = new HashMap();
map1.put("SUN", 1);
map1.put("IBM", 2);
map1.put("AOL", 4);
p.positions = map1;
region.put(1, p);
Portfolio p2 = new Portfolio(3, 4);
HashMap map2 = new HashMap();
map2.put("APPL", 3);
map2.put("AOL", "hello");
p2.positions = map2;
region.put(2, p2);
assertEquals("Put must be successful", 2, region.size());
QueryService queryService = cache.getQueryService();
Index keyIndex1 = queryService.createIndex(INDEX_NAME, "positions[*]", "/portfolio");
assertEquals("Index must be valid", true, keyIndex1.isValid());
QueryObserverImpl observer = new QueryObserverImpl();
QueryObserverHolder.setInstance(observer);
SelectResults results = (SelectResults) queryService
.newQuery(
"select * from /portfolio p where p.positions['AOL'] = 'hello' OR p.positions['IBM'] = 2")
.execute();
assertEquals("Current results expected from the query execution ", 2, results.size());
assertEquals("Index must be used while executing the query ", 2, observer.indexesUsed.size());
}
}