com.hazelcast.simulator.tests.map.MapPredicateTest Maven / Gradle / Ivy
/*
* Copyright (c) 2008-2016, Hazelcast, Inc. All Rights Reserved.
*
* Licensed 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 com.hazelcast.simulator.tests.map;
import com.hazelcast.core.IList;
import com.hazelcast.core.IMap;
import com.hazelcast.query.EntryObject;
import com.hazelcast.query.PagingPredicate;
import com.hazelcast.query.Predicate;
import com.hazelcast.query.PredicateBuilder;
import com.hazelcast.query.Predicates;
import com.hazelcast.query.SqlPredicate;
import com.hazelcast.simulator.test.AbstractTest;
import com.hazelcast.simulator.test.annotations.RunWithWorker;
import com.hazelcast.simulator.test.annotations.Setup;
import com.hazelcast.simulator.test.annotations.Verify;
import com.hazelcast.simulator.test.annotations.Warmup;
import com.hazelcast.simulator.tests.map.helpers.Employee;
import com.hazelcast.simulator.tests.map.helpers.PredicateOperationCounter;
import com.hazelcast.simulator.worker.loadsupport.Streamer;
import com.hazelcast.simulator.worker.loadsupport.StreamerFactory;
import com.hazelcast.simulator.worker.selector.OperationSelectorBuilder;
import com.hazelcast.simulator.worker.tasks.AbstractWorker;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import static java.lang.String.format;
import static java.util.concurrent.TimeUnit.SECONDS;
import static org.junit.Assert.assertTrue;
/**
* In this test we are using different predicate methods to execute a query on a map of {@link Employee} objects.
*
* This test also concurrently updates and modifies the employee objects in the map while the predicate queries are executing. The
* test may also destroy the map while while predicate are executing. We verify the result of every query to ensure that the
* objects returned fit the requirements of the query.
*/
public class MapPredicateTest extends AbstractTest {
private enum Operation {
PREDICATE_BUILDER,
SQL_STRING,
PAGING_PREDICATE,
UPDATE_EMPLOYEE,
DESTROY_MAP
}
public int keyCount = 100;
public int pageSize = 5;
public double predicateBuilderProb = 0.2;
public double sqlStringProb = 0.2;
public double pagePredicateProb = 0.2;
public double updateEmployeeProb = 0.3;
public double destroyProb = 0.1;
private final OperationSelectorBuilder operationSelectorBuilder = new OperationSelectorBuilder();
private IMap map;
private IList operationCounterList;
private String baseAssertMessage;
@Setup
public void setUp() {
map = targetInstance.getMap(name);
operationCounterList = targetInstance.getList(name + "OperationCounter");
baseAssertMessage = format("%s: %%s not matching %%s", name);
operationSelectorBuilder.addOperation(Operation.PREDICATE_BUILDER, predicateBuilderProb)
.addOperation(Operation.SQL_STRING, sqlStringProb)
.addOperation(Operation.PAGING_PREDICATE, pagePredicateProb)
.addOperation(Operation.UPDATE_EMPLOYEE, updateEmployeeProb)
.addOperation(Operation.DESTROY_MAP, destroyProb);
}
@Warmup(global = true)
public void globalWarmup() {
initMap();
}
private void initMap() {
Streamer streamer = StreamerFactory.getInstance(map);
for (int i = 0; i < keyCount; i++) {
Employee employee = new Employee(i);
streamer.pushEntry(employee.getId(), employee);
}
streamer.await();
}
@RunWithWorker
public Worker createWorker() {
return new Worker();
}
private class Worker extends AbstractWorker {
private final PredicateOperationCounter operationCounter = new PredicateOperationCounter();
private long lastUpdateMs = System.currentTimeMillis();
private long iterationsLastMinute = 0;
private long maxLastMinute = Long.MIN_VALUE;
private long minLastMinute = Long.MAX_VALUE;
private long spendTimeMs = 0;
public Worker() {
super(operationSelectorBuilder);
}
@Override
public void timeStep(Operation operation) {
long startMs = System.currentTimeMillis();
switch (operation) {
case PREDICATE_BUILDER:
predicateBuilder();
break;
case SQL_STRING:
sqlString();
break;
case PAGING_PREDICATE:
pagingPredicate();
break;
case UPDATE_EMPLOYEE:
updateEmployee();
break;
case DESTROY_MAP:
destroyMap();
break;
default:
throw new UnsupportedOperationException();
}
long nowMs = System.currentTimeMillis();
long durationMs = nowMs - startMs;
maxLastMinute = Math.max(durationMs, maxLastMinute);
minLastMinute = Math.min(durationMs, minLastMinute);
iterationsLastMinute++;
spendTimeMs += durationMs;
if (lastUpdateMs + SECONDS.toMillis(60) < nowMs) {
double avg = spendTimeMs / (double) iterationsLastMinute;
double perf = (iterationsLastMinute * 1000d) / (double) spendTimeMs;
logger.info(format("last minute: iterations=%d, min=%d ms, max=%d ms, avg=%.2f ms, perf=%.2f predicates/second",
iterationsLastMinute, minLastMinute, maxLastMinute, avg, perf));
maxLastMinute = Long.MIN_VALUE;
minLastMinute = Long.MAX_VALUE;
iterationsLastMinute = 0;
lastUpdateMs = nowMs;
}
}
@Override
public void afterRun() {
operationCounterList.add(operationCounter);
}
private void predicateBuilder() {
int age = randomInt(Employee.MAX_AGE);
String name = Employee.getRandomName();
// TODO: Still broken because it relies on reflection which is dog slow, so we need an explicit AgeNamePredicate
EntryObject entryObject = new PredicateBuilder().getEntryObject();
Predicate agePredicate = entryObject.get("age").lessThan(age);
Predicate ageNamePredicate = entryObject.get("name").equal(name).and(agePredicate);
Collection employees = map.values(ageNamePredicate);
for (Employee emp : employees) {
String assertMessage = format(baseAssertMessage, emp, ageNamePredicate);
assertTrue(assertMessage, emp.getAge() < age);
assertTrue(assertMessage, emp.getName().equals(name));
}
operationCounter.predicateBuilderCount++;
}
private void sqlString() {
boolean active = getRandom().nextBoolean();
int age = randomInt(Employee.MAX_AGE);
SqlPredicate predicate = new SqlPredicate("active=" + active + " AND age >" + age);
Collection employees = map.values(predicate);
for (Employee emp : employees) {
String assertMessage = format(baseAssertMessage, emp, predicate);
assertTrue(assertMessage, emp.isActive() == active);
assertTrue(assertMessage, emp.getAge() > age);
}
operationCounter.sqlStringCount++;
}
private void pagingPredicate() {
double maxSalary = getRandom().nextDouble() * Employee.MAX_SALARY;
Predicate predicate = Predicates.lessThan("salary", maxSalary);
SalaryComparator salaryComparator = new SalaryComparator();
PagingPredicate pagingPredicate = new PagingPredicate(predicate, salaryComparator, pageSize);
Collection employees;
List employeeList;
do {
employees = map.values(pagingPredicate);
employeeList = fillListWithQueryResultSet(employees);
Employee nextEmployee;
Employee currentEmployee;
for (int i = 0; i < employeeList.size() - 1; i++) {
currentEmployee = employeeList.get(i);
nextEmployee = employeeList.get(i + 1);
// check the order & max salary
assertTrue(format(baseAssertMessage, currentEmployee.getSalary(), predicate),
currentEmployee.getSalary() <= nextEmployee.getSalary() && nextEmployee.getSalary() < maxSalary);
}
pagingPredicate.nextPage();
} while (!employees.isEmpty());
operationCounter.pagePredicateCount++;
}
private List fillListWithQueryResultSet(Iterable iterable) {
List list = new ArrayList();
for (Employee employee : iterable) {
list.add(employee);
}
return list;
}
private void updateEmployee() {
Integer key = randomInt(keyCount);
Employee employee = map.get(key);
if (employee != null) {
employee.randomizeProperties();
map.put(key, employee);
operationCounter.updateEmployeeCount++;
}
}
private void destroyMap() {
map.destroy();
initMap();
operationCounter.destroyCount++;
}
}
private static class SalaryComparator implements Comparator, Serializable {
@Override
public int compare(Map.Entry o1, Map.Entry o2) {
double employee1Salary = ((Employee) (o1.getValue())).getSalary();
double employee2Salary = ((Employee) (o2.getValue())).getSalary();
return Double.compare(employee1Salary, employee2Salary);
}
}
@Verify
public void globalVerify() {
PredicateOperationCounter total = new PredicateOperationCounter();
for (PredicateOperationCounter operationCounter : operationCounterList) {
total.add(operationCounter);
}
logger.info(format("Operation counters from %s: %s", name, total));
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy