blob: d97e6b2309b740843c7c996c7346c996f8c36076 [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.internal.cache.eviction;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import java.io.File;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import org.junit.After;
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.EvictionAlgorithm;
import org.apache.geode.cache.EvictionAttributes;
import org.apache.geode.cache.PartitionAttributesFactory;
import org.apache.geode.cache.Region;
import org.apache.geode.cache.util.ObjectSizer;
import org.apache.geode.distributed.DistributedSystem;
import org.apache.geode.internal.JvmSizeUtils;
import org.apache.geode.internal.OSProcess;
import org.apache.geode.internal.cache.BucketRegion;
import org.apache.geode.internal.cache.CachedDeserializableFactory;
import org.apache.geode.internal.cache.PartitionedRegion;
import org.apache.geode.internal.cache.RegionMap;
import org.apache.geode.internal.cache.TestNonSizerObject;
import org.apache.geode.internal.cache.TestObjectSizerImpl;
import org.apache.geode.internal.cache.entries.AbstractLRURegionEntry;
import org.apache.geode.internal.size.ReflectionSingleObjectSizer;
import org.apache.geode.internal.size.Sizeable;
import org.apache.geode.test.dunit.LogWriterUtils;
import org.apache.geode.test.dunit.cache.CacheTestCase;
import org.apache.geode.test.junit.categories.EvictionTest;
@Category({EvictionTest.class})
@SuppressWarnings("serial")
public class EvictionObjectSizerDUnitTest extends CacheTestCase {
private static final int maxEnteries = 20;
private static final int maxSizeInMb = 20;
private static Cache cache;
private static Region region;
@After
public void tearDown() throws Exception {
if (cache != null) {
cache.close();
}
cache = null;
region = null;
}
/**
* Without object sizer
*/
@Test
public void testWithoutObjectSizerForHeapLRU() throws Exception {
prepareScenario(EvictionAlgorithm.LRU_HEAP, null);
// Size of overhead=
// 49(HeapLRUCapacityController)((PartitionedRegion)region).getEvictionController()).getPerEntryOverhead()
// Size of Integer key= 0 (it is inlined)
// Size of Byte Array(1 MB)= 1024 * 1024 + 8 (byte object) + 4 ( size of object) + 4 (rounded up
// to nearest word)
// = 1048592
// Total Size of each entry should be= 1048592
putData("PR1", 2, 1);
int keySize = 0;
int valueSize =
JvmSizeUtils.getObjectHeaderSize() + 4 /* array length */ + (1024 * 1024) /* bytes */;
valueSize = (int) ReflectionSingleObjectSizer.roundUpSize(valueSize);
int entrySize = keySize + valueSize
+ ((HeapLRUController) ((PartitionedRegion) region).getEvictionController())
.getPerEntryOverhead();
verifySize("PR1", 2, entrySize);
assertEquals(2 * entrySize,
((PartitionedRegion) region).getEvictionController().getCounters().getCounter());
}
/**
* With object sizer for standard objects.Key -Integer Value ByteArray
*
*/
@Test
public void testObjectSizerForHeapLRU_StandardObjects() throws Exception {
prepareScenario(EvictionAlgorithm.LRU_HEAP, new TestObjectSizerImpl());
// Size of overhead= 49
// Size of Integer key= 0(inlined)
// Size of Byte Array(1 MB) + overhead (16 bytes)= 1048592 + 16
// Total Size of each entry should be= 1048592
putData("PR1", 2, 1);
{
int keySize = 0;
int valueSize =
JvmSizeUtils.getObjectHeaderSize() + 4 /* array length */ + (1024 * 1024) /* bytes */;
valueSize = (int) ReflectionSingleObjectSizer.roundUpSize(valueSize);
int entrySize = keySize + valueSize
+ ((HeapLRUController) ((PartitionedRegion) region).getEvictionController())
.getPerEntryOverhead();
verifySize("PR1", 2, entrySize);
}
// Size of overhead= 49
// Size of Integer key= 0(inlined)
// Size of Byte Array(2 MB) + overhead= 2097152 + 16
// Total Size of each entry should be= 2097201
{
putData("PR1", 2, 2);
int keySize = 0;
int valueSize = JvmSizeUtils.getObjectHeaderSize() + 4 /* array length */
+ (1024 * 1024 * 2) /* bytes */;
valueSize = (int) ReflectionSingleObjectSizer.roundUpSize(valueSize);
int entrySize = keySize + valueSize
+ ((HeapLRUController) ((PartitionedRegion) region).getEvictionController())
.getPerEntryOverhead();
verifySize("PR1", 2, entrySize);
}
}
/**
* With object sizer for customized value object implementing ObjectSizer .Key -Integer Value
* TestNonSizerObject
*/
@Test
public void testObjectSizerForHeapLRU_CustomizedNonSizerObject() throws Exception {
prepareScenario(EvictionAlgorithm.LRU_HEAP, new TestObjectSizerImpl());
// Size of overhead= 49
// Size of Integer key= 0(inlined)
// Size of byte array 0 + size of overhead(16)
// Total Size of each entry should be= 54
putCustomizedData(1, new byte[0]);
{
int keySize = 0;
int valueSize = JvmSizeUtils.getObjectHeaderSize() + 4 /* array length */ + 0 /* bytes */;
valueSize = (int) ReflectionSingleObjectSizer.roundUpSize(valueSize);
int entrySize = keySize + valueSize
+ ((HeapLRUController) ((PartitionedRegion) region).getEvictionController())
.getPerEntryOverhead();
assertEquals(entrySize, getSizeOfCustomizedData(1));
}
// Size of overhead= 49
// Size of Integer key= 0(inlined)
// Size of byte array 4 + size of overhead(12)
// Total Size of each entry should be= 59
putCustomizedData(2, new byte[4]);
{
int keySize = 0;
int valueSize = JvmSizeUtils.getObjectHeaderSize() + 4 /* array length */ + 4 /* bytes */;
valueSize = (int) ReflectionSingleObjectSizer.roundUpSize(valueSize);
int entrySize = keySize + valueSize
+ ((HeapLRUController) ((PartitionedRegion) region).getEvictionController())
.getPerEntryOverhead();
assertEquals(entrySize, getSizeOfCustomizedData(2));
}
}
/**
* With object sizer for customized value object implementing ObjectSizer .Key -Integer Value
* TestObjectSizerImpl
*/
@Test
public void testObjectSizerForHeapLRU_CustomizedSizerObject() throws Exception {
prepareScenario(EvictionAlgorithm.LRU_HEAP, new TestObjectSizerImpl());
// Size of overhead= 49
// Size of Integer key= 0(inlined)
// Size of TestObjectSizerImpl= 160 (serialized size), changed to 156 because package changed to
// org.apache.geode
// Total Size of entry should be= 71
putCustomizedData(1, new TestObjectSizerImpl());
int expected = (0 + 156 + (Sizeable.PER_OBJECT_OVERHEAD * 2)
+ ((HeapLRUController) ((PartitionedRegion) region).getEvictionController())
.getPerEntryOverhead());
assertEquals(expected, getSizeOfCustomizedData(1));
assertEquals(expected,
((PartitionedRegion) region).getEvictionController().getCounters().getCounter());
}
/**
* With object sizer for customized key and value objects.
*/
@Test
public void testObjectSizerForHeapLRU_CustomizedSizerObjects() throws Exception {
prepareScenario(EvictionAlgorithm.LRU_HEAP, new TestObjectSizerImpl());
// Size of overhead= 49
// Size of TestNonSizerObject key= 1(customized)
// Size of TestObjectSizerImpl= 160 (serialized size), changed to 156 because package changed to
// org.apache.geode
// Total Size of entry should be= 72
putCustomizedObjects(new TestNonSizerObject("1"), new TestObjectSizerImpl());
int expected = (1 + 156 + (Sizeable.PER_OBJECT_OVERHEAD * 2)
+ ((HeapLRUController) ((PartitionedRegion) region).getEvictionController())
.getPerEntryOverhead());
assertEquals(expected, getSizeOfCustomizedObject(new TestNonSizerObject("1")));
assertEquals(expected,
((PartitionedRegion) region).getEvictionController().getCounters().getCounter());
}
private void prepareScenario(EvictionAlgorithm evictionAlgorithm, ObjectSizer sizer) {
createMyCache();
createPartitionedRegion(true, evictionAlgorithm, "PR1", 1, 1, 10000, sizer);
}
private void createMyCache() {
Properties props = new Properties();
DistributedSystem ds = getSystem(props);
assertNotNull(ds);
ds.disconnect();
ds = getSystem(props);
cache = CacheFactory.create(ds);
cache.getResourceManager().setEvictionHeapPercentage(50);
}
private static void createPartitionedRegion(boolean setEvictionOn,
EvictionAlgorithm evictionAlgorithm, String regionName, int totalNoOfBuckets,
int evictionAction, int evictorInterval, ObjectSizer sizer) {
final AttributesFactory factory = new AttributesFactory();
PartitionAttributesFactory partitionAttributesFactory = new PartitionAttributesFactory()
.setRedundantCopies(totalNoOfBuckets == 4 ? 0 : 1).setTotalNumBuckets(totalNoOfBuckets);
factory.setConcurrencyChecksEnabled(false);
factory.setPartitionAttributes(partitionAttributesFactory.create());
if (setEvictionOn) {
if (evictionAlgorithm.isLRUHeap()) {
factory.setEvictionAttributes(EvictionAttributes.createLRUHeapAttributes(sizer,
evictionAction == 1 ? EvictionAction.LOCAL_DESTROY : EvictionAction.OVERFLOW_TO_DISK));
} else if (evictionAlgorithm.isLRUMemory()) {
factory.setEvictionAttributes(EvictionAttributes.createLRUMemoryAttributes(maxSizeInMb,
sizer,
evictionAction == 1 ? EvictionAction.LOCAL_DESTROY : EvictionAction.OVERFLOW_TO_DISK));
} else {
factory.setEvictionAttributes(EvictionAttributes.createLRUEntryAttributes(maxEnteries,
evictionAction == 1 ? EvictionAction.LOCAL_DESTROY : EvictionAction.OVERFLOW_TO_DISK));
}
if (evictionAction == 2) {
factory.setDiskSynchronous(true);
final File[] diskDirs = new File[1];
diskDirs[0] =
new File("Partitioned_Region_Eviction/" + "LogFile" + "_" + OSProcess.getId());
diskDirs[0].mkdirs();
factory.setDiskStoreName(cache.createDiskStoreFactory().setDiskDirs(diskDirs)
.create("EvictionObjectSizerDUnitTest").getName());
}
}
region = cache.createRegion(regionName, factory.create());
assertNotNull(region);
LogWriterUtils.getLogWriter().info("Partitioned Region created Successfully :" + region);
}
/**
* returns data size in bytes
*/
private static int putData(final String regionName, final int noOfElememts,
final int sizeOfElement) {
int result = 0;
final Region pr = cache.getRegion(regionName);
for (int counter = 1; counter <= noOfElememts; counter++) {
byte[] baValue = new byte[sizeOfElement * 1024 * 1024];
int baSize = CachedDeserializableFactory.getByteSize(baValue);
result += baSize;
pr.put(new Integer(counter), baValue);
}
return result;
}
private static void verifySize(String regionName, int noOfElememts, int entrySize) {
final Region pr = cache.getRegion(regionName);
for (final Iterator i =
((PartitionedRegion) pr).getDataStore().getAllLocalBuckets().iterator(); i.hasNext();) {
final Map.Entry entry = (Map.Entry) i.next();
final BucketRegion bucketRegion = (BucketRegion) entry.getValue();
if (bucketRegion == null) {
continue;
} else {
RegionMap map = bucketRegion.getRegionMap();
if (map == null || map.size() == 0) {
continue;
}
LogWriterUtils.getLogWriter().info("Checking for entry in bucket region: " + bucketRegion);
for (int counter = 1; counter <= noOfElememts; counter++) {
assertEquals(entrySize,
((AbstractLRURegionEntry) map.getEntry(new Integer(counter))).getEntrySize());
}
}
}
}
private void putCustomizedData(int counter, Object object) {
final Region pr = cache.getRegion("PR1");
pr.put(new Integer(counter), object);
}
private void putCustomizedObjects(Object key, Object value) {
final Region pr = cache.getRegion("PR1");
pr.put(key, value);
}
private int getSizeOfCustomizedData(int counter) {
final Region pr = cache.getRegion("PR1");
for (final Iterator i =
((PartitionedRegion) pr).getDataStore().getAllLocalBuckets().iterator(); i.hasNext();) {
final Map.Entry entry = (Map.Entry) i.next();
final BucketRegion bucketRegion = (BucketRegion) entry.getValue();
if (bucketRegion == null) {
continue;
} else {
RegionMap map = bucketRegion.getRegionMap();
return ((AbstractLRURegionEntry) map.getEntry(new Integer(counter))).getEntrySize();
}
}
return 0;
}
private int getSizeOfCustomizedObject(Object object) {
final Region pr = cache.getRegion("PR1");
for (final Iterator i =
((PartitionedRegion) pr).getDataStore().getAllLocalBuckets().iterator(); i.hasNext();) {
final Map.Entry entry = (Map.Entry) i.next();
final BucketRegion bucketRegion = (BucketRegion) entry.getValue();
if (bucketRegion == null) {
continue;
} else {
RegionMap map = bucketRegion.getRegionMap();
AbstractLRURegionEntry re = (AbstractLRURegionEntry) map.getEntry(object);
if (re != null) {
return re.getEntrySize();
}
}
}
return 0;
}
}