| /* |
| * 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 static org.junit.Assert.assertTrue; |
| |
| import java.io.File; |
| import java.util.Iterator; |
| import java.util.Map; |
| import java.util.Properties; |
| |
| 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.CacheException; |
| 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.cache30.CacheSerializableRunnable; |
| import org.apache.geode.distributed.DistributedSystem; |
| import org.apache.geode.internal.cache.BucketRegion; |
| import org.apache.geode.internal.cache.PartitionedRegion; |
| import org.apache.geode.internal.cache.control.HeapMemoryMonitor; |
| import org.apache.geode.internal.cache.control.InternalResourceManager; |
| import org.apache.geode.logging.internal.OSProcess; |
| import org.apache.geode.test.dunit.Assert; |
| import org.apache.geode.test.dunit.Host; |
| import org.apache.geode.test.dunit.IgnoredException; |
| import org.apache.geode.test.dunit.LogWriterUtils; |
| import org.apache.geode.test.dunit.SerializableRunnable; |
| import org.apache.geode.test.dunit.VM; |
| import org.apache.geode.test.dunit.cache.CacheTestCase; |
| import org.apache.geode.test.junit.categories.EvictionTest; |
| |
| @Category({EvictionTest.class}) |
| public class EvictionStatsDUnitTest extends CacheTestCase { |
| |
| protected static Cache cache = null; |
| |
| protected static VM dataStore1 = null; |
| |
| protected static VM dataStore2 = null; |
| |
| protected static Region region = null; |
| |
| static int maxEntries = 20; |
| |
| static int maxSizeInMb = 20; |
| |
| static int totalNoOfBuckets = 2; |
| |
| @Override |
| public final void postSetUp() throws Exception { |
| Host host = Host.getHost(0); |
| dataStore1 = host.getVM(0); |
| dataStore2 = host.getVM(1); |
| } |
| |
| @Test |
| public void testEntryLruLimit() { |
| // Ignore this exception as this can happen if pool is shutting down |
| IgnoredException |
| .addIgnoredException(java.util.concurrent.RejectedExecutionException.class.getName()); |
| prepareScenario(EvictionAlgorithm.LRU_ENTRY); |
| putData("PR1", 100); |
| putData("PR2", 60); |
| dataStore1.invoke(new CacheSerializableRunnable("testlimit") { |
| @Override |
| public void run2() throws CacheException { |
| final PartitionedRegion pr1 = (PartitionedRegion) cache.getRegion("PR1"); |
| final PartitionedRegion pr2 = (PartitionedRegion) cache.getRegion("PR2"); |
| assertEquals(maxEntries, pr1.getEvictionLimit()); |
| assertEquals(maxEntries, pr2.getEvictionLimit()); |
| } |
| }); |
| |
| dataStore2.invoke(new CacheSerializableRunnable("testlimit") { |
| @Override |
| public void run2() throws CacheException { |
| final PartitionedRegion pr1 = (PartitionedRegion) cache.getRegion("PR1"); |
| final PartitionedRegion pr2 = (PartitionedRegion) cache.getRegion("PR2"); |
| assertEquals(maxEntries, pr1.getEvictionLimit()); |
| assertEquals(maxEntries, pr2.getEvictionLimit()); |
| } |
| }); |
| } |
| |
| @Test |
| public void testMemLruLimit() { |
| // Ignore this exception as this can happen if pool is shutting down |
| IgnoredException |
| .addIgnoredException(java.util.concurrent.RejectedExecutionException.class.getName()); |
| prepareScenario(EvictionAlgorithm.LRU_MEMORY); |
| putData("PR1", 100); |
| putData("PR2", 60); |
| dataStore1.invoke(new CacheSerializableRunnable("testlimit") { |
| @Override |
| public void run2() throws CacheException { |
| final long ONE_MEG = 1024L * 1024L; |
| final PartitionedRegion pr1 = (PartitionedRegion) cache.getRegion("PR1"); |
| final PartitionedRegion pr2 = (PartitionedRegion) cache.getRegion("PR2"); |
| assertEquals(pr1.getLocalMaxMemory(), pr1.getEvictionLimit() / ONE_MEG); |
| assertEquals(pr2.getLocalMaxMemory(), pr2.getEvictionLimit() / ONE_MEG); |
| } |
| }); |
| |
| dataStore2.invoke(new CacheSerializableRunnable("testlimit") { |
| @Override |
| public void run2() throws CacheException { |
| final long ONE_MEG = 1024L * 1024L; |
| final PartitionedRegion pr1 = (PartitionedRegion) cache.getRegion("PR1"); |
| final PartitionedRegion pr2 = (PartitionedRegion) cache.getRegion("PR2"); |
| assertEquals(pr1.getLocalMaxMemory(), pr1.getEvictionLimit() / ONE_MEG); |
| assertEquals(pr2.getLocalMaxMemory(), pr2.getEvictionLimit() / ONE_MEG); |
| } |
| }); |
| |
| } |
| |
| @Test |
| public void testEntryLruCounter() { |
| // Ignore this excetion as this can happen if pool is shutting down |
| IgnoredException |
| .addIgnoredException(java.util.concurrent.RejectedExecutionException.class.getName()); |
| prepareScenario(EvictionAlgorithm.LRU_ENTRY); |
| putData("PR1", 10); |
| putData("PR2", 16); |
| long sizeOfPr1 = getPRCounter("PR1"); |
| long sizeOfPr2 = getPRCounter("PR2"); |
| |
| long totalBucketSizeForPR1 = getCounterForBucketsOfPR("PR1"); |
| long totalBucketSizeForPR2 = getCounterForBucketsOfPR("PR2"); |
| |
| assertEquals(sizeOfPr1, totalBucketSizeForPR1); |
| assertEquals(sizeOfPr2, totalBucketSizeForPR2); |
| } |
| |
| @Test |
| public void testMemLruCounter() { |
| // Ignore this excetion as this can happen if pool is shutting down |
| IgnoredException |
| .addIgnoredException(java.util.concurrent.RejectedExecutionException.class.getName()); |
| prepareScenario(EvictionAlgorithm.LRU_MEMORY); |
| putData("PR1", 10); |
| putData("PR2", 16); |
| long sizeOfPr1 = getPRCounter("PR1"); |
| long sizeOfPr2 = getPRCounter("PR2"); |
| |
| long totalBucketSizeForPR1 = getCounterForBucketsOfPR("PR1"); |
| long totalBucketSizeForPR2 = getCounterForBucketsOfPR("PR2"); |
| |
| assertEquals(sizeOfPr1, totalBucketSizeForPR1); |
| assertEquals(sizeOfPr2, totalBucketSizeForPR2); |
| } |
| |
| @Test |
| public void testHeapLruCounter() { |
| // Ignore this excetion as this can happen if pool is shutting down |
| IgnoredException |
| .addIgnoredException(java.util.concurrent.RejectedExecutionException.class.getName()); |
| prepareScenario(EvictionAlgorithm.LRU_HEAP); |
| System.setProperty(HeapLRUController.TOP_UP_HEAP_EVICTION_PERCENTAGE_PROPERTY, |
| Float.toString(0)); |
| putData("PR1", 20); |
| putData("PR2", 20); |
| long sizeOfPr1 = getPRCounter("PR1"); |
| long sizeOfPr2 = getPRCounter("PR2"); |
| |
| long totalBucketSizeForPR1 = getCounterForBucketsOfPR("PR1"); |
| long totalBucketSizeForPR2 = getCounterForBucketsOfPR("PR2"); |
| } |
| |
| @Test |
| public void testEntryLruAllCounterMethods() { |
| // Ignore this excetion as this can happen if pool is shutting down |
| IgnoredException |
| .addIgnoredException(java.util.concurrent.RejectedExecutionException.class.getName()); |
| final long ONE_MEG = 1024L * 1024L; |
| createCache(); |
| createPartitionedRegion(true, EvictionAlgorithm.LRU_ENTRY, "PR1", 2, 1, 10000); |
| for (int counter = 1; counter <= maxEntries; counter++) { |
| region.put(new Integer(counter), new byte[(1 * 1024 * 1024) - 2]); |
| } |
| PartitionedRegion pr = (PartitionedRegion) region; |
| long sizeOfPRegion = pr.getEvictionCounter(); |
| |
| assertEquals(sizeOfPRegion, 20); |
| long bucketSize = 0; |
| for (final Iterator i = |
| ((PartitionedRegion) region).getDataStore().getAllLocalBuckets().iterator(); i.hasNext();) { |
| final Map.Entry entry = (Map.Entry) i.next(); |
| final BucketRegion bucketRegion = (BucketRegion) entry.getValue(); |
| if (bucketRegion == null) { |
| continue; |
| } |
| assertEquals(bucketRegion.getCounter(), 10); |
| bucketSize = bucketSize + (bucketRegion.getCounter()); |
| } |
| assertEquals(sizeOfPRegion, bucketSize); |
| |
| // Cause Eviction. |
| bucketSize = 0; |
| final int extraEnteries = 4; |
| for (int counter = 1; counter <= extraEnteries; counter++) { |
| region.put(new Integer(counter), new byte[(1 * 1024 * 1024) - 2]); |
| } |
| sizeOfPRegion = pr.getEvictionCounter(); |
| assertEquals(sizeOfPRegion, 20); |
| for (final Iterator i = pr.getDataStore().getAllLocalBuckets().iterator(); i.hasNext();) { |
| final Map.Entry entry = (Map.Entry) i.next(); |
| final BucketRegion bucketRegion = (BucketRegion) entry.getValue(); |
| if (bucketRegion == null) { |
| continue; |
| } |
| assertEquals(bucketRegion.getCounter(), 10); |
| bucketSize = bucketSize + (bucketRegion.getCounter()); |
| } |
| assertEquals(sizeOfPRegion, bucketSize); |
| |
| // Clear one bucket |
| for (final Iterator i = pr.getDataStore().getAllLocalBuckets().iterator(); i.hasNext();) { |
| final Map.Entry entry = (Map.Entry) i.next(); |
| final BucketRegion bucketRegion = (BucketRegion) entry.getValue(); |
| if (bucketRegion == null) { |
| continue; |
| } |
| // Don't just clear the bucket here, use the real region |
| // api to remove the entries. |
| for (Object key : bucketRegion.keySet()) { |
| region.destroy(key); |
| } |
| assertEquals(bucketRegion.getCounter(), 0); |
| break; |
| } |
| sizeOfPRegion = pr.getEvictionCounter(); |
| assertEquals(sizeOfPRegion, 10); |
| } |
| |
| |
| |
| @Test |
| public void testEntryLRUEvictionNDestroyNNumOverflowOnDiskCount() { |
| // Ignore this excetion as this can happen if pool is shutting down |
| IgnoredException |
| .addIgnoredException(java.util.concurrent.RejectedExecutionException.class.getName()); |
| final int extraEntries = 24; |
| prepareScenario(EvictionAlgorithm.LRU_ENTRY); |
| putData("PR1", maxEntries + extraEntries); |
| putData("PR2", maxEntries + extraEntries); |
| dataStore1.invoke( |
| new CacheSerializableRunnable("testEntryLRUEvictionNDestroyNNumOverflowOnDiskCount") { |
| @Override |
| public void run2() throws CacheException { |
| PartitionedRegion pr1 = (PartitionedRegion) cache.getRegion("PR1"); |
| assertEquals(pr1.getTotalEvictions(), (extraEntries - maxEntries) / 2); |
| assertEquals(pr1.getEvictionDestroys(), pr1.getTotalEvictions()); |
| |
| PartitionedRegion pr2 = (PartitionedRegion) cache.getRegion("PR2"); |
| assertEquals(pr2.getTotalEvictions(), (extraEntries - maxEntries) / 2); |
| assertEquals(pr2.getEvictionDestroys(), 0); |
| assertEquals(pr2.getDiskRegionStats().getNumOverflowOnDisk(), |
| (extraEntries - maxEntries) / 2); |
| } |
| }); |
| |
| dataStore2.invoke( |
| new CacheSerializableRunnable("testEntryLRUEvictionNDestroyNNumOverflowOnDiskCount") { |
| @Override |
| public void run2() throws CacheException { |
| PartitionedRegion pr1 = (PartitionedRegion) cache.getRegion("PR1"); |
| assertEquals(pr1.getTotalEvictions(), (extraEntries - maxEntries) / 2); |
| assertEquals(pr1.getEvictionDestroys(), pr1.getTotalEvictions()); |
| |
| PartitionedRegion pr2 = (PartitionedRegion) cache.getRegion("PR2"); |
| assertEquals(pr2.getTotalEvictions(), (extraEntries - maxEntries) / 2); |
| assertEquals(pr2.getEvictionDestroys(), 0); |
| assertEquals(pr2.getDiskRegionStats().getNumOverflowOnDisk(), |
| (extraEntries - maxEntries) / 2); |
| } |
| }); |
| } |
| |
| @Test |
| public void testMemLRUEvictionNDestroyNNumOverflowOnDiskCount() { |
| // Ignore this excetion as this can happen if pool is shutting down |
| IgnoredException |
| .addIgnoredException(java.util.concurrent.RejectedExecutionException.class.getName()); |
| int localMaxMem = 50; |
| final int extraEntries = 6; |
| prepareScenario(EvictionAlgorithm.LRU_MEMORY); |
| putData("PR1", (2 * localMaxMem) + extraEntries); |
| putData("PR2", (2 * localMaxMem/* localmaxmem */) + extraEntries); |
| dataStore1.invoke(new CacheSerializableRunnable("testEvictionCount") { |
| @Override |
| public void run2() throws CacheException { |
| PartitionedRegion pr1 = (PartitionedRegion) cache.getRegion("PR1"); |
| LogWriterUtils.getLogWriter().info("dddd local" + pr1.getLocalMaxMemory()); |
| LogWriterUtils.getLogWriter().info("dddd local evi" + pr1.getTotalEvictions()); |
| LogWriterUtils.getLogWriter() |
| .info("dddd local entries" + (pr1.getEvictionCounter() / (1024 * 1024))); |
| HeapMemoryMonitor hmm = |
| ((InternalResourceManager) cache.getResourceManager()).getHeapMonitor(); |
| long memused = hmm.getBytesUsed() / (1024 * 1024); |
| LogWriterUtils.getLogWriter().info("dddd local memused= " + memused); |
| assertTrue(pr1.getTotalEvictions() >= extraEntries / 2); |
| assertEquals(pr1.getEvictionDestroys(), pr1.getTotalEvictions()); |
| PartitionedRegion pr2 = (PartitionedRegion) cache.getRegion("PR2"); |
| assertTrue(pr2.getTotalEvictions() >= extraEntries / 2); |
| assertEquals(pr2.getEvictionDestroys(), 0); |
| assertTrue(pr2.getDiskRegionStats().getNumOverflowOnDisk() >= extraEntries / 2); |
| } |
| }); |
| |
| dataStore2.invoke(new CacheSerializableRunnable("testEvictionCount") { |
| @Override |
| public void run2() throws CacheException { |
| PartitionedRegion pr1 = (PartitionedRegion) cache.getRegion("PR1"); |
| assertTrue(pr1.getTotalEvictions() >= extraEntries / 2); |
| assertEquals(pr1.getEvictionDestroys(), pr1.getTotalEvictions()); |
| |
| PartitionedRegion pr2 = (PartitionedRegion) cache.getRegion("PR2"); |
| assertTrue(pr2.getTotalEvictions() >= extraEntries / 2); |
| assertEquals(pr2.getEvictionDestroys(), 0); |
| assertTrue(pr2.getDiskRegionStats().getNumOverflowOnDisk() >= extraEntries / 2); |
| } |
| }); |
| } |
| |
| |
| public void prepareScenario(EvictionAlgorithm evictionAlgorithm) { |
| createCacheInAllVms(); |
| createPartitionedRegionInAllVMS(true, evictionAlgorithm, "PR1", totalNoOfBuckets, 1, 10000); |
| createPartitionedRegionInAllVMS(true, evictionAlgorithm, "PR2", totalNoOfBuckets, 2, 10000); |
| } |
| |
| public void createCacheInAllVms() { |
| createCache(); |
| |
| dataStore1.invoke(new SerializableRunnable() { |
| @Override |
| public void run() { |
| createCache(); |
| } |
| }); |
| |
| dataStore2.invoke(new SerializableRunnable() { |
| @Override |
| public void run() { |
| createCache(); |
| } |
| }); |
| } |
| |
| public static void createCacheInVm() { |
| new EvictionStatsDUnitTest().createCache(); |
| } |
| |
| public void createCache() { |
| try { |
| Properties props = new Properties(); |
| DistributedSystem ds = getSystem(props); |
| assertNotNull(ds); |
| ds.disconnect(); |
| ds = getSystem(props); |
| cache = CacheFactory.create(ds); |
| assertNotNull(cache); |
| LogWriterUtils.getLogWriter().info("cache= " + cache); |
| LogWriterUtils.getLogWriter().info("cache closed= " + cache.isClosed()); |
| cache.getResourceManager().setEvictionHeapPercentage(20); |
| } catch (Exception e) { |
| Assert.fail("Failed while creating the cache", e); |
| } |
| } |
| |
| private void createPartitionedRegionInAllVMS(final boolean setEvictionOn, |
| final EvictionAlgorithm evictionAlgorithm, final String regionName, |
| final int totalNoOfBuckets, final int evictionAction, final int evictorInterval) { |
| |
| dataStore1.invoke(new SerializableRunnable() { |
| @Override |
| public void run() { |
| createPartitionedRegion(setEvictionOn, evictionAlgorithm, regionName, totalNoOfBuckets, |
| evictionAction, evictorInterval); |
| } |
| }); |
| |
| dataStore2.invoke(new SerializableRunnable() { |
| @Override |
| public void run() { |
| createPartitionedRegion(setEvictionOn, evictionAlgorithm, regionName, totalNoOfBuckets, |
| evictionAction, evictorInterval); |
| } |
| }); |
| } |
| |
| public void createPartitionedRegion(boolean setEvictionOn, EvictionAlgorithm evictionAlgorithm, |
| String regionName, int totalNoOfBuckets, int evictionAction, int evictorInterval) { |
| |
| final AttributesFactory factory = new AttributesFactory(); |
| factory.setOffHeap(isOffHeapEnabled()); |
| PartitionAttributesFactory partitionAttributesFactory = new PartitionAttributesFactory() |
| .setRedundantCopies(0).setTotalNumBuckets(totalNoOfBuckets).setLocalMaxMemory(50); |
| |
| factory.setPartitionAttributes(partitionAttributesFactory.create()); |
| if (setEvictionOn) { |
| if (evictionAlgorithm.isLRUHeap()) { |
| factory.setEvictionAttributes(EvictionAttributes.createLRUHeapAttributes(null, |
| evictionAction == 1 ? EvictionAction.LOCAL_DESTROY : EvictionAction.OVERFLOW_TO_DISK)); |
| } else if (evictionAlgorithm.isLRUMemory()) { |
| factory.setEvictionAttributes(EvictionAttributes.createLRUMemoryAttributes(maxSizeInMb, |
| ObjectSizer.DEFAULT, |
| evictionAction == 1 ? EvictionAction.LOCAL_DESTROY : EvictionAction.OVERFLOW_TO_DISK)); |
| } else { |
| factory.setEvictionAttributes(EvictionAttributes.createLRUEntryAttributes(maxEntries, |
| evictionAction == 1 ? EvictionAction.LOCAL_DESTROY : EvictionAction.OVERFLOW_TO_DISK)); |
| } |
| if (evictionAction == 2) { |
| final File[] diskDirs = new File[1]; |
| diskDirs[0] = |
| new File("Partitioned_Region_EvictionStats/" + "LogFile" + "_" + OSProcess.getId()); |
| diskDirs[0].mkdirs(); |
| factory.setDiskSynchronous(true); |
| factory.setDiskStoreName(cache.createDiskStoreFactory().setDiskDirs(diskDirs) |
| .create("EvictionStatsDUnitTest").getName()); |
| } |
| } |
| |
| region = cache.createRegion(regionName, factory.create()); |
| assertNotNull(region); |
| LogWriterUtils.getLogWriter().info("Partitioned Region created Successfully :" + region); |
| } |
| |
| public static void putData(final String regionName, final int noOfElememts) { |
| dataStore1.invoke(new CacheSerializableRunnable("putData") { |
| @Override |
| public void run2() throws CacheException { |
| final Region pr = cache.getRegion(regionName); |
| for (int counter = 1; counter <= noOfElememts; counter++) { |
| pr.put(new Integer(counter), new byte[1 * 1024 * 1024]); |
| // getLogWriter().info("Deep put data element no->" + counter); |
| } |
| } |
| }); |
| } |
| |
| private long getPRCounter(String prRegionName) { |
| final long ONE_MEG = 1024L * 1024L; |
| long sizeOfPR = 0; |
| sizeOfPR = sizeOfPR + (Long) dataStore1 |
| .invoke(() -> EvictionStatsDUnitTest.getPartionRegionCounter(prRegionName)); |
| sizeOfPR = sizeOfPR + (Long) dataStore2 |
| .invoke(() -> EvictionStatsDUnitTest.getPartionRegionCounter(prRegionName)); |
| return sizeOfPR / ONE_MEG; |
| } |
| |
| public static long getPartionRegionCounter(String prRegionName) { |
| final PartitionedRegion pr = (PartitionedRegion) cache.getRegion(prRegionName); |
| return pr.getEvictionCounter(); |
| } |
| |
| private long getCounterForBucketsOfPR(String prRegionName) { |
| final long ONE_MEG = 1024L * 1024L; |
| long totalBucketSize = 0; |
| totalBucketSize = totalBucketSize |
| + (Long) dataStore1.invoke(() -> EvictionStatsDUnitTest.getCounterForBuckets(prRegionName)); |
| totalBucketSize = totalBucketSize |
| + (Long) dataStore2.invoke(() -> EvictionStatsDUnitTest.getCounterForBuckets(prRegionName)); |
| return totalBucketSize / ONE_MEG; |
| |
| } |
| |
| public static long getCounterForBuckets(String prRegionName) { |
| long bucketSize = 0; |
| final PartitionedRegion pr = (PartitionedRegion) cache.getRegion(prRegionName); |
| for (final Iterator i = pr.getDataStore().getAllLocalBuckets().iterator(); i.hasNext();) { |
| final Map.Entry entry = (Map.Entry) i.next(); |
| final BucketRegion bucketRegion = (BucketRegion) entry.getValue(); |
| if (bucketRegion == null) { |
| continue; |
| } |
| LogWriterUtils.getLogWriter().info("Size of bucket " + bucketRegion.getName() + "of Pr " |
| + prRegionName + " = " + bucketRegion.getCounter() / (1000000)); |
| bucketSize = bucketSize + bucketRegion.getCounter(); |
| } |
| return bucketSize; |
| } |
| |
| public boolean isOffHeapEnabled() { |
| return false; |
| } |
| } |