blob: 0d0790c63a0cc2e457702493e19c38fd493e0e97 [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.internal;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.util.Iterator;
import java.util.List;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.apache.geode.cache.Region;
import org.apache.geode.cache.query.CacheUtils;
import org.apache.geode.cache.query.IndexType;
import org.apache.geode.cache.query.QueryService;
import org.apache.geode.cache.query.data.Portfolio;
import org.apache.geode.cache.query.internal.index.IndexData;
import org.apache.geode.cache.query.internal.index.IndexManager;
import org.apache.geode.cache.query.internal.index.IndexUtils;
import org.apache.geode.test.junit.categories.OQLIndexTest;
@Category({OQLIndexTest.class})
public class IndexManagerJUnitTest {
@Before
public void setUp() throws 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 Exception {
CacheUtils.closeCache();
}
/**
* This test is for a fix for #47475 We added a way to determine whether to reevaluate an entry
* for query execution The method is to keep track of the delta and current time in a single long
* value The value is then used by the query to determine if a region entry needs to be
* reevaluated based on subtracting the value with the query execution time. This provides a delta
* + some false positive time If the delta + last modified time of the region entry is > query
* start time, we can assume that it needs to be reevaluated
*/
@Test
public void testSafeQueryTime() throws Exception {
IndexManager.resetIndexBufferTime();
// fake entry update at LMT of 0 and actual time of 10
// safe query time set in index manager is going to be 20
IndexManager.setIndexBufferTime(0, 10);
// fake query start at actual time of 9, 10, 11 and using the fake LMT of 0
assertTrue(IndexManager.needsRecalculation(9, 0));
assertTrue(IndexManager.needsRecalculation(10, 0));
assertFalse(IndexManager.needsRecalculation(11, 0));
assertFalse(IndexManager.needsRecalculation(9, -3)); // old enough updates shouldn't trigger a
// recalc
assertTrue(IndexManager.needsRecalculation(9, -2)); // older updates but falls within the delta
// (false positive)
assertTrue(IndexManager.needsRecalculation(10, 5));
// This should eval to true only because of false positives.
assertTrue(IndexManager.needsRecalculation(11, 5));
// Now let's assume a new update has occurred, this update delta and time combo still is not
// larger
IndexManager.setIndexBufferTime(0, 9);
IndexManager.setIndexBufferTime(1, 10);
// Now let's assume a new update has occurred where the time is larger (enough to roll off the
// large delta)
// but the delta is smaller
IndexManager.setIndexBufferTime(30, 30);
// Now that we have a small delta, let's see if a query that was "stuck" would reevaluate
// appropriately
assertTrue(IndexManager.needsRecalculation(9, 0));
}
// Let's test for negative delta's or a system that is slower than others in the cluster
@Test
public void testSafeQueryTimeForASlowNode() throws Exception {
IndexManager.resetIndexBufferTime();
// fake entry update at LMT of 0 and actual time of 10
// safe query time set in index manager is going to be -10
IndexManager.setIndexBufferTime(210, 200);
assertFalse(IndexManager.needsRecalculation(200, 190));
assertFalse(IndexManager.needsRecalculation(200, 200));
assertTrue(IndexManager.needsRecalculation(200, 210));
assertTrue(IndexManager.needsRecalculation(200, 220));
assertTrue(IndexManager.needsRecalculation(200, 221));
// now lets say an entry updates with no delta
IndexManager.setIndexBufferTime(210, 210);
assertTrue(IndexManager.needsRecalculation(200, 190));
assertTrue(IndexManager.needsRecalculation(200, 200));
assertTrue(IndexManager.needsRecalculation(200, 210));
assertTrue(IndexManager.needsRecalculation(200, 220));
assertTrue(IndexManager.needsRecalculation(200, 221));
assertTrue(IndexManager.needsRecalculation(210, 211));
assertFalse(IndexManager.needsRecalculation(212, 210));
}
@Test
public void testBestIndexPick() throws Exception {
QueryService qs;
qs = CacheUtils.getQueryService();
qs.createIndex("statusIndex", IndexType.FUNCTIONAL, "status", "/portfolios, positions");
QCompiler compiler = new QCompiler();
List list = compiler.compileFromClause("/portfolios pf");
ExecutionContext context = new QueryExecutionContext(null, CacheUtils.getCache());
context.newScope(context.associateScopeID());
Iterator iter = list.iterator();
while (iter.hasNext()) {
CompiledIteratorDef iterDef = (CompiledIteratorDef) iter.next();
context.addDependencies(new CompiledID("dummy"), iterDef.computeDependencies(context));
RuntimeIterator rIter = iterDef.getRuntimeIterator(context);
context.bindIterator(rIter);
context.addToIndependentRuntimeItrMap(iterDef);
}
CompiledPath cp = new CompiledPath(new CompiledID("pf"), "status");
// TASK ICM1
String[] defintions = {"/portfolios", "index_iter1.positions"};
IndexData id = IndexUtils.findIndex("/portfolios", defintions, cp, "*", CacheUtils.getCache(),
true, context);
Assert.assertEquals(id.getMatchLevel(), 0);
Assert.assertEquals(id.getMapping()[0], 1);
Assert.assertEquals(id.getMapping()[1], 2);
String[] defintions1 = {"/portfolios"};
IndexData id1 = IndexUtils.findIndex("/portfolios", defintions1, cp, "*", CacheUtils.getCache(),
true, context);
Assert.assertEquals(id1.getMatchLevel(), -1);
Assert.assertEquals(id1.getMapping()[0], 1);
String[] defintions2 = {"/portfolios", "index_iter1.positions", "index_iter1.coll1"};
IndexData id2 = IndexUtils.findIndex("/portfolios", defintions2, cp, "*", CacheUtils.getCache(),
true, context);
Assert.assertEquals(id2.getMatchLevel(), 1);
Assert.assertEquals(id2.getMapping()[0], 1);
Assert.assertEquals(id2.getMapping()[1], 2);
Assert.assertEquals(id2.getMapping()[2], 0);
}
}