/*
* 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.internal.cache.execute;
import org.junit.experimental.categories.Category;
import org.junit.Test;
import static org.junit.Assert.*;
import org.apache.geode.test.dunit.cache.internal.JUnit4CacheTestCase;
import org.apache.geode.test.dunit.internal.JUnit4DistributedTestCase;
import org.apache.geode.test.junit.categories.DistributedTest;
/**
* This is a dunit test for PartitionedRegion creation and Region API's for put and get
* functionality in case of Custom Partitioning.
*/
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import org.apache.geode.DataSerializable;
import org.apache.geode.cache.AttributesFactory;
import org.apache.geode.cache.Cache;
import org.apache.geode.cache.CacheException;
import org.apache.geode.cache.CacheFactory;
import org.apache.geode.cache.PartitionAttributes;
import org.apache.geode.cache.PartitionAttributesFactory;
import org.apache.geode.cache.PartitionResolver;
import org.apache.geode.cache.Region;
import org.apache.geode.cache.RegionAttributes;
import org.apache.geode.cache.execute.Execution;
import org.apache.geode.cache.execute.FunctionService;
import org.apache.geode.cache.execute.ResultCollector;
import org.apache.geode.cache30.CacheSerializableRunnable;
import org.apache.geode.distributed.DistributedMember;
import org.apache.geode.distributed.DistributedSystem;
import org.apache.geode.internal.cache.PartitionedRegion;
import org.apache.geode.internal.cache.PartitionedRegionDUnitTestCase;
import org.apache.geode.test.dunit.Assert;
import org.apache.geode.test.dunit.Host;
import org.apache.geode.test.dunit.LogWriterUtils;
import org.apache.geode.test.dunit.SerializableRunnable;
import org.apache.geode.test.dunit.VM;
@Category(DistributedTest.class)
public class PRPerformanceTestDUnitTest extends PartitionedRegionDUnitTestCase {
public PRPerformanceTestDUnitTest() {
super();
}
protected static Cache cache = null;
Properties props = new Properties();
VM vm0 = null;
VM vm1 = null;
VM vm2 = null;
VM vm3 = null;
static final int totalNumBuckets = 13;
static ArrayList listOfKeys = new ArrayList();
protected static final byte[] valueArray = new byte[1024];
public static void createCacheInVm() throws Exception {
Properties props = new Properties();
new PRPerformanceTestDUnitTest().createCache(props);
}
private void createCache(Properties props) throws Exception {
DistributedSystem ds = getSystem(props);
assertNotNull(ds);
ds.disconnect();
ds = getSystem(props);
cache = CacheFactory.create(ds);
assertNotNull(cache);
}
/* SerializableRunnable object to create PR with a partition resolver */
SerializableRunnable createPrRegionWithPartitionResolver =
new CacheSerializableRunnable("createPrRegionWithDS") {
public void run2() throws CacheException {
AttributesFactory attr = new AttributesFactory();
PartitionResolver resolver = MonthBasedPartitionResolver.getInstance();
PartitionAttributesFactory paf = new PartitionAttributesFactory();
paf.setTotalNumBuckets(totalNumBuckets);
paf.setPartitionResolver(resolver);
paf.setLocalMaxMemory(900);
paf.setRedundantCopies(0);
PartitionAttributes prAttr = paf.create();
attr.setPartitionAttributes(prAttr);
RegionAttributes regionAttribs = attr.create();
cache.createRegion("PR1", regionAttribs);
PerformanceTestFunction function = new PerformanceTestFunction();
FunctionService.registerFunction(function);
}
};
/* SerializableRunnable object to create PR with a partition resolver */
SerializableRunnable createPrRegionOnlyAccessorWithPartitionResolver =
new CacheSerializableRunnable("createPrRegionOnlyAccessor") {
public void run2() throws CacheException {
AttributesFactory attr = new AttributesFactory();
PartitionAttributesFactory paf = new PartitionAttributesFactory();
PartitionResolver resolver = MonthBasedPartitionResolver.getInstance();
PartitionAttributes prAttr = paf.setLocalMaxMemory(0).setTotalNumBuckets(totalNumBuckets)
.setPartitionResolver(resolver).setRedundantCopies(0).create();
attr.setPartitionAttributes(prAttr);
RegionAttributes regionAttribs = attr.create();
cache.createRegion("PR1", regionAttribs);
}
};
/**
* Search the entires PartitionedRegion for the key, to validate that indeed it doesn't exist
*
* @returns true if it does exist
* @param par
* @param key
*/
public static boolean searchForKey(PartitionedRegion par, Date key) {
// Check to make super sure that the key exists
boolean foundIt = false;
final int numBucks = par.getTotalNumberOfBuckets();
for (int b = 0; b < numBucks; b++) {
if (par.getBucketKeys(b).contains(key)) {
foundIt = true;
// getLogWriter().info("Key " + key + " found in bucket " + b);
break;
}
}
if (!foundIt) {
LogWriterUtils.getLogWriter().severe("Key " + key + " not found in any bucket");
}
return foundIt;
}
public void partitionedRegionTest(final String prName, final int noOfEntries) {
/*
* Do put() operations through VM with PR having both Accessor and Datastore
*/
vm0.invoke(new CacheSerializableRunnable("doPutCreateInvalidateOperations1") {
public void run2() throws CacheException {
Calendar cal = Calendar.getInstance();
final Region pr = cache.getRegion(prName);
if (pr == null) {
fail(prName + " not created");
}
int size = 0;
size = pr.size();
assertEquals("Size doesnt return expected value", 0, size);
assertEquals("isEmpty doesnt return proper state of the PartitionedRegion", true,
pr.isEmpty());
assertEquals(0, pr.keySet().size());
int entries = noOfEntries;
while (entries > 0) {
for (int i = 0; i <= 11; i++) {
int yr = (new Integer((int) (Math.random() * 2100))).intValue();
int month = i;
int date = (new Integer((int) (Math.random() * 30))).intValue();
cal.set(yr, month, date);
Object key = cal.getTime();
listOfKeys.add(key);
assertNotNull(pr);
// pr.put(key, Integer.toString(i));
pr.put(key, valueArray);
// assertIndexDetailsEquals(valueArray, pr.get(key));
}
entries--;
}
}
});
vm0.invoke(new CacheSerializableRunnable("verifyKeysonVM0") {
public void run2() throws CacheException {
// Calendar cal = Calendar.getInstance();
final PartitionedRegion pr = (PartitionedRegion) cache.getRegion(prName);
if (pr == null) {
fail(prName + " not created");
}
Iterator itr = listOfKeys.iterator();
while (itr.hasNext()) {
assertTrue(searchForKey(pr, (Date) itr.next()));
}
// Intitial warm up phase ..Do a get of all the keys
// Iterate over the key and try to get all the values repetitively
itr = listOfKeys.iterator();
ArrayList vals = new ArrayList();
while (itr.hasNext()) {
Object val = pr.get(itr.next());
assertNotNull(val);
vals.add(val);
// assertTrue(searchForKey(pr, (Date)itr.next()));
}
// Call the execute method for each key
PerformanceTestFunction function = new PerformanceTestFunction();
FunctionService.registerFunction(function);
DefaultResultCollector drc = new DefaultResultCollector();
// final Set allKeysSet = new HashSet();
final Set singleKeySet = new HashSet();
Execution dataSet = FunctionService.onRegion(pr);
vals.clear();
ArrayList list = new ArrayList();
itr = listOfKeys.iterator();
while (itr.hasNext()) {
singleKeySet.add(itr.next());
dataSet = dataSet.withFilter(singleKeySet);
try {
ResultCollector rc = dataSet.execute(function.getId());
list = (ArrayList) rc.getResult();
} catch (Exception ex) {
LogWriterUtils.getLogWriter().info("Exception Occured :" + ex.getMessage());
Assert.fail("Test failed", ex);
}
Object val = list.get(0);
assertNotNull(val);
vals.add(val);
singleKeySet.clear();
// assertTrue(searchForKey(pr, (Date)itr.next()));
}
assertEquals(vals.size(), listOfKeys.size());
// END: warmup
// Now start the performance count
itr = listOfKeys.iterator();
TimeKeeper t = new TimeKeeper();
vals.clear();
t.start();
// ArrayList vals = new ArrayList();
while (itr.hasNext()) {
Object val = pr.get(itr.next());
assertNotNull(val);
vals.add(val);
// assertTrue(searchForKey(pr, (Date)itr.next()));
}
t.stop();
LogWriterUtils.getLogWriter().info("Time taken to iterate over " + vals.size()
+ " no. of keys: " + t.getTimeInMs() + " ms");
// Call the execute method for each key and see if this takes more time
vals.clear();
t = new TimeKeeper();
t.start();
// ArrayList list = new ArrayList();
itr = listOfKeys.iterator();
while (itr.hasNext()) {
singleKeySet.add(itr.next());
dataSet = dataSet.withFilter(singleKeySet);
try {
ResultCollector rc = dataSet.execute(function.getId());
list = (ArrayList) rc.getResult();
} catch (Exception expected) {
// No data should cause exec to throw
}
Object val = list.get(0);
assertNotNull(val);
vals.add(val);
singleKeySet.clear();
}
t.stop();
assertEquals(vals.size(), listOfKeys.size());
LogWriterUtils.getLogWriter().info("Time taken to iterate over " + vals.size()
+ " no. of keys using FunctionExecution: " + t.getTimeInMs() + " ms");
}
});
}
/**
* This is a PartitionedRegion test for Custom Prtitioning . 4 VMs are used to create the PR with
* and without(Only Accessor) the DataStore.
*/
@Test
public void testPartitionedRegionOperationsCustomPartitioning() throws Exception {
Host host = Host.getHost(0);
// create the VM(0 - 4)
vm0 = host.getVM(0);
vm1 = host.getVM(1);
vm2 = host.getVM(2);
vm3 = host.getVM(3);
final VM accessor = vm0;
// final VM accessor = vm3;
// create cache in all vms
accessor.invoke(() -> PRPerformanceTestDUnitTest.createCacheInVm());
vm1.invoke(() -> PRPerformanceTestDUnitTest.createCacheInVm());
vm2.invoke(() -> PRPerformanceTestDUnitTest.createCacheInVm());
vm3.invoke(() -> PRPerformanceTestDUnitTest.createCacheInVm());
// Create PR;s in different VM's
accessor.invoke(createPrRegionOnlyAccessorWithPartitionResolver);
vm1.invoke(createPrRegionWithPartitionResolver);
vm2.invoke(createPrRegionWithPartitionResolver);
vm3.invoke(createPrRegionWithPartitionResolver);
partitionedRegionTest("/PR1", 50);
/*
* destroy the Region.
*/
destroyTheRegion("/PR1");
// Create PR;s in different VM's
}
public void destroyTheRegion(final String name) {
/*
* destroy the Region.
*/
vm0.invoke(new CacheSerializableRunnable("destroyRegionOp") {
public void run2() throws CacheException {
Region pr = cache.getRegion(name);
if (pr == null) {
fail(name + " not created");
}
pr.destroyRegion();
}
});
}
}
class SerializablePerfMonth implements DataSerializable {
private int month;
public SerializablePerfMonth(int month) {
this.month = month;
}
public void fromData(DataInput in) throws IOException, ClassNotFoundException {
this.month = in.readInt();
}
public void toData(DataOutput out) throws IOException {
out.writeInt(this.month);
}
public int hashCode() {
/*
* if(this.month<4) return 1; else if(this.month >= 4 && this.month < 8) return 2; else return
* 3;
*
*/
return this.month;
}
}
class TimeKeeper {
private long startTime = -1;
private long endTime = -1;
public void start() {
startTime = System.currentTimeMillis();
}
public void stop() {
endTime = System.currentTimeMillis();
}
public long getTimeInMs() {
if ((startTime == -1) || (endTime == -1)) {
System.err.println("call start() and stop() before this method");
return -1;
} else if ((endTime == startTime)) {
System.err.println("the start time and end time are the same...returning 1ms");
return 1;
} else
return (endTime - startTime);
}
}