| /* |
| * 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.ignite.internal.processors.cache; |
| |
| import java.util.UUID; |
| import javax.cache.CacheException; |
| import org.apache.ignite.IgniteCache; |
| import org.apache.ignite.IgniteCheckedException; |
| import org.apache.ignite.IgniteLogger; |
| import org.apache.ignite.cache.CacheMode; |
| import org.apache.ignite.cache.affinity.rendezvous.RendezvousAffinityFunction; |
| import org.apache.ignite.cluster.ClusterNode; |
| import org.apache.ignite.configuration.CacheConfiguration; |
| import org.apache.ignite.configuration.DataPageEvictionMode; |
| import org.apache.ignite.configuration.DataRegionConfiguration; |
| import org.apache.ignite.configuration.DataStorageConfiguration; |
| import org.apache.ignite.configuration.IgniteConfiguration; |
| import org.apache.ignite.failure.FailureHandler; |
| import org.apache.ignite.failure.StopNodeOrHaltFailureHandler; |
| import org.apache.ignite.internal.IgniteEx; |
| import org.apache.ignite.internal.mem.IgniteOutOfMemoryException; |
| import org.apache.ignite.internal.util.typedef.internal.U; |
| import org.apache.ignite.lang.IgnitePredicate; |
| import org.apache.ignite.testframework.ListeningTestLogger; |
| import org.apache.ignite.testframework.LogListener; |
| import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest; |
| import org.jetbrains.annotations.Nullable; |
| import org.junit.Test; |
| |
| import static java.util.Objects.nonNull; |
| import static org.apache.ignite.configuration.DataStorageConfiguration.DFLT_PAGE_SIZE; |
| import static org.apache.ignite.testframework.GridTestUtils.assertThrows; |
| import static org.apache.ignite.testframework.LogListener.matches; |
| |
| /** |
| * |
| */ |
| public class CacheDataRegionConfigurationTest extends GridCommonAbstractTest { |
| /** */ |
| private volatile CacheConfiguration ccfg; |
| |
| /** */ |
| private volatile DataStorageConfiguration memCfg; |
| |
| /** Failure handler. */ |
| @Nullable private FailureHandler failureHnd; |
| |
| /** */ |
| private IgniteLogger logger; |
| |
| /** */ |
| private static final long DFLT_MEM_PLC_SIZE = 10L * 1024 * 1024; |
| |
| /** */ |
| private static final long BIG_MEM_PLC_SIZE = 1024L * 1024 * 1024; |
| |
| /** {@inheritDoc} */ |
| @Override protected IgniteConfiguration getConfiguration(String gridName) throws Exception { |
| IgniteConfiguration cfg = super.getConfiguration(gridName); |
| |
| if (nonNull(logger)) |
| cfg.setGridLogger(logger); |
| |
| if (nonNull(failureHnd)) |
| cfg.setFailureHandler(failureHnd); |
| |
| if (gridName.contains("client")) { |
| cfg.setClientMode(true); |
| |
| return cfg; |
| } |
| |
| if (nonNull(memCfg)) |
| cfg.setDataStorageConfiguration(memCfg); |
| |
| if (nonNull(ccfg)) |
| cfg.setCacheConfiguration(ccfg); |
| |
| return cfg; |
| } |
| |
| /** {@inheritDoc} */ |
| @Override protected void afterTest() throws Exception { |
| super.afterTest(); |
| |
| stopAllGrids(); |
| |
| cleanPersistenceDir(); |
| } |
| |
| /** {@inheritDoc} */ |
| @Override protected void beforeTest() throws Exception { |
| super.beforeTest(); |
| |
| stopAllGrids(); |
| |
| cleanPersistenceDir(); |
| } |
| |
| /** */ |
| private void checkStartGridException(Class<? extends Throwable> ex, String message) { |
| assertThrows(log(), () -> { |
| startGrid(0); |
| |
| return null; |
| }, ex, message); |
| } |
| |
| /** |
| * Verifies that proper exception is thrown when DataRegion is misconfigured for cache. |
| */ |
| @Test |
| public void testMissingDataRegion() { |
| ccfg = new CacheConfiguration(DEFAULT_CACHE_NAME); |
| |
| ccfg.setDataRegionName("nonExistingMemPlc"); |
| |
| checkStartGridException(IgniteCheckedException.class, "Requested DataRegion is not configured"); |
| } |
| |
| /** |
| * Verifies that {@link IgniteOutOfMemoryException} is thrown when cache is configured with too small DataRegion. |
| */ |
| @Test |
| public void testTooSmallDataRegion() throws Exception { |
| memCfg = new DataStorageConfiguration(); |
| |
| DataRegionConfiguration dfltPlcCfg = new DataRegionConfiguration(); |
| dfltPlcCfg.setName("dfltPlc"); |
| dfltPlcCfg.setInitialSize(DFLT_MEM_PLC_SIZE); |
| dfltPlcCfg.setMaxSize(DFLT_MEM_PLC_SIZE); |
| |
| DataRegionConfiguration bigPlcCfg = new DataRegionConfiguration(); |
| bigPlcCfg.setName("bigPlc"); |
| bigPlcCfg.setMaxSize(BIG_MEM_PLC_SIZE); |
| |
| memCfg.setDataRegionConfigurations(bigPlcCfg); |
| memCfg.setDefaultDataRegionConfiguration(dfltPlcCfg); |
| |
| ccfg = new CacheConfiguration(DEFAULT_CACHE_NAME); |
| |
| IgniteEx ignite0 = startGrid(0); |
| |
| IgniteCache<Object, Object> cache = ignite0.cache(DEFAULT_CACHE_NAME); |
| |
| boolean oomeThrown = false; |
| |
| try { |
| for (int i = 0; i < 500_000; i++) |
| cache.put(i, "abc"); |
| } |
| catch (Exception e) { |
| Throwable cause = e; |
| |
| do { |
| if (cause instanceof IgniteOutOfMemoryException) { |
| oomeThrown = true; |
| break; |
| } |
| |
| if (cause == null) |
| break; |
| |
| if (cause.getSuppressed() == null || cause.getSuppressed().length == 0) |
| cause = cause.getCause(); |
| else |
| cause = cause.getSuppressed()[0]; |
| } |
| while (true); |
| } |
| |
| if (!oomeThrown) |
| fail("OutOfMemoryException hasn't been thrown"); |
| } |
| |
| /** |
| * Verifies that with enough memory allocated adding values to cache doesn't cause any exceptions. |
| */ |
| @Test |
| public void testProperlySizedMemoryPolicy() throws Exception { |
| memCfg = new DataStorageConfiguration(); |
| |
| DataRegionConfiguration dfltPlcCfg = new DataRegionConfiguration(); |
| dfltPlcCfg.setName("dfltPlc"); |
| dfltPlcCfg.setInitialSize(DFLT_MEM_PLC_SIZE); |
| dfltPlcCfg.setMaxSize(DFLT_MEM_PLC_SIZE); |
| |
| DataRegionConfiguration bigPlcCfg = new DataRegionConfiguration(); |
| bigPlcCfg.setName("bigPlc"); |
| bigPlcCfg.setMaxSize(BIG_MEM_PLC_SIZE); |
| |
| memCfg.setDataRegionConfigurations(bigPlcCfg); |
| memCfg.setDefaultDataRegionConfiguration(dfltPlcCfg); |
| |
| ccfg = new CacheConfiguration(DEFAULT_CACHE_NAME); |
| ccfg.setDataRegionName("bigPlc"); |
| |
| IgniteEx ignite0 = startGrid(0); |
| |
| IgniteCache<Object, Object> cache = ignite0.cache(DEFAULT_CACHE_NAME); |
| |
| try { |
| for (int i = 0; i < 500_000; i++) |
| cache.put(i, "abc"); |
| } |
| catch (Exception e) { |
| fail("With properly sized DataRegion no exceptions are expected to be thrown."); |
| } |
| } |
| |
| /** |
| * Verifies that {@link IgniteCheckedException} is thrown when swap and persistence are enabled at the same time |
| * for a data region. |
| */ |
| @Test |
| public void testSetPersistenceAndSwap() { |
| DataRegionConfiguration invCfg = new DataRegionConfiguration(); |
| |
| invCfg.setName("invCfg"); |
| invCfg.setInitialSize(DFLT_MEM_PLC_SIZE); |
| invCfg.setMaxSize(DFLT_MEM_PLC_SIZE); |
| // Enabling the persistence. |
| invCfg.setPersistenceEnabled(true); |
| // Enabling the swap space. |
| invCfg.setSwapPath("/path/to/some/directory"); |
| |
| memCfg = new DataStorageConfiguration(); |
| memCfg.setDataRegionConfigurations(invCfg); |
| |
| ccfg = new CacheConfiguration(DEFAULT_CACHE_NAME); |
| ccfg.setDataRegionName("ccfg"); |
| |
| checkStartGridException(IgniteCheckedException.class, "Failed to start processor: GridProcessorAdapter []"); |
| } |
| |
| /** |
| * Filter to exclude the node from affinity nodes by its name. |
| */ |
| private static class NodeNameNodeFilter implements IgnitePredicate<ClusterNode> { |
| /** */ |
| private final String filteredNode; |
| |
| /** |
| * @param node Node. |
| */ |
| private NodeNameNodeFilter(String node) { |
| filteredNode = node; |
| } |
| |
| /** {@inheritDoc} */ |
| @Override public boolean apply(ClusterNode node) { |
| return !node.attribute("org.apache.ignite.ignite.name").toString().contains(filteredNode); |
| } |
| } |
| |
| /** |
| * Verifies that warning message is printed to the logs if user tries to start a static cache in data region which |
| * overhead (e.g. metapages for partitions) occupies more space of the region than a defined threshold (15%) |
| * |
| * @throws Exception If failed. |
| */ |
| @Test |
| public void testWarningIfStaticCacheOverheadExceedsThreshold() throws Exception { |
| DataRegionConfiguration smallRegionCfg = new DataRegionConfiguration(); |
| int numOfPartitions = 512; |
| int partitionsMetaMemoryChunk = U.sizeInMegabytes(512 * DFLT_PAGE_SIZE); |
| |
| smallRegionCfg.setInitialSize(DFLT_MEM_PLC_SIZE); |
| smallRegionCfg.setMaxSize(DFLT_MEM_PLC_SIZE); |
| smallRegionCfg.setPersistenceEnabled(true); |
| smallRegionCfg.setName("smallRegion"); |
| |
| memCfg = new DataStorageConfiguration(); |
| memCfg.setDefaultDataRegionConfiguration(smallRegionCfg); |
| //one hour to guarantee that checkpoint will be triggered by 'dirty pages amount' trigger |
| memCfg.setCheckpointFrequency(60 * 60 * 1000); |
| |
| CacheConfiguration<Object, Object> manyPartitionsCache = new CacheConfiguration<>(DEFAULT_CACHE_NAME); |
| |
| //512 partitions are enough only if primary and backups count |
| manyPartitionsCache.setAffinity(new RendezvousAffinityFunction(false, numOfPartitions)); |
| manyPartitionsCache.setBackups(1); |
| |
| ccfg = manyPartitionsCache; |
| |
| ListeningTestLogger srv0Logger = new ListeningTestLogger(null); |
| LogListener cacheGrpLsnr0 = matches("Cache group 'default' brings high overhead").build(); |
| LogListener dataRegLsnr0 = matches("metainformation in data region 'smallRegion'").build(); |
| LogListener partsInfoLsnr0 = matches(numOfPartitions + " partitions, " + |
| DFLT_PAGE_SIZE + |
| " bytes per partition, " + partitionsMetaMemoryChunk + " MBs total").build(); |
| srv0Logger.registerAllListeners(cacheGrpLsnr0, dataRegLsnr0, partsInfoLsnr0); |
| logger = srv0Logger; |
| |
| IgniteEx ignite0 = startGrid("srv0"); |
| |
| ListeningTestLogger srv1Logger = new ListeningTestLogger(null); |
| LogListener cacheGrpLsnr1 = matches("Cache group 'default' brings high overhead").build(); |
| LogListener dataRegLsnr1 = matches("metainformation in data region 'smallRegion'").build(); |
| LogListener partsInfoLsnr1 = matches(numOfPartitions + " partitions, " + |
| DFLT_PAGE_SIZE + |
| " bytes per partition, " + partitionsMetaMemoryChunk + " MBs total").build(); |
| srv1Logger.registerAllListeners(cacheGrpLsnr1, dataRegLsnr1, partsInfoLsnr1); |
| logger = srv1Logger; |
| |
| startGrid("srv1"); |
| |
| ignite0.cluster().active(true); |
| |
| //srv0 and srv1 print warning into the log as the threshold for cache in default cache group is broken |
| assertTrue(cacheGrpLsnr0.check()); |
| assertTrue(dataRegLsnr0.check()); |
| assertTrue(partsInfoLsnr0.check()); |
| |
| assertTrue(cacheGrpLsnr1.check()); |
| assertTrue(dataRegLsnr1.check()); |
| assertTrue(partsInfoLsnr1.check()); |
| } |
| |
| /** |
| * Verifies that warning message is printed to the logs if user tries to start a dynamic cache in data region which |
| * overhead (e.g. metapages for partitions) occupies more space of the region than a defined threshold. |
| * |
| * @throws Exception If failed. |
| */ |
| @Test |
| public void testWarningIfDynamicCacheOverheadExceedsThreshold() throws Exception { |
| String filteredSrvName = "srv2"; |
| int numOfPartitions = 512; |
| int partitionsMetaMemoryChunk = U.sizeInMegabytes(512 * DFLT_PAGE_SIZE); |
| |
| DataRegionConfiguration smallRegionCfg = new DataRegionConfiguration(); |
| |
| smallRegionCfg.setName("smallRegion"); |
| smallRegionCfg.setInitialSize(DFLT_MEM_PLC_SIZE); |
| smallRegionCfg.setMaxSize(DFLT_MEM_PLC_SIZE); |
| smallRegionCfg.setPersistenceEnabled(true); |
| |
| //explicit default data region configuration to test possible NPE case |
| DataRegionConfiguration defaultRegionCfg = new DataRegionConfiguration(); |
| defaultRegionCfg.setName("defaultRegion"); |
| defaultRegionCfg.setInitialSize(DFLT_MEM_PLC_SIZE); |
| defaultRegionCfg.setMaxSize(DFLT_MEM_PLC_SIZE); |
| defaultRegionCfg.setPersistenceEnabled(true); |
| |
| memCfg = new DataStorageConfiguration(); |
| memCfg.setDefaultDataRegionConfiguration(defaultRegionCfg); |
| memCfg.setDataRegionConfigurations(smallRegionCfg); |
| //one hour to guarantee that checkpoint will be triggered by 'dirty pages amount' trigger |
| memCfg.setCheckpointFrequency(60 * 60 * 1000); |
| |
| ListeningTestLogger srv0Logger = new ListeningTestLogger(null); |
| LogListener cacheGrpLsnr0 = matches("Cache group 'default' brings high overhead").build(); |
| LogListener dataRegLsnr0 = matches("metainformation in data region 'defaultRegion'").build(); |
| LogListener partsInfoLsnr0 = matches(numOfPartitions + " partitions, " + |
| DFLT_PAGE_SIZE + |
| " bytes per partition, " + partitionsMetaMemoryChunk + " MBs total").build(); |
| srv0Logger.registerAllListeners(cacheGrpLsnr0, dataRegLsnr0, partsInfoLsnr0); |
| logger = srv0Logger; |
| |
| IgniteEx ignite0 = startGrid("srv0"); |
| |
| ListeningTestLogger srv1Logger = new ListeningTestLogger(null); |
| LogListener cacheGrpLsnr1 = matches("Cache group 'default' brings high overhead").build(); |
| LogListener dataRegLsnr1 = matches("metainformation in data region 'defaultRegion'").build(); |
| LogListener partsInfoLsnr1 = matches(numOfPartitions + " partitions, " + |
| DFLT_PAGE_SIZE + |
| " bytes per partition, " + partitionsMetaMemoryChunk + " MBs total").build(); |
| srv1Logger.registerAllListeners(cacheGrpLsnr1, dataRegLsnr1, partsInfoLsnr1); |
| logger = srv1Logger; |
| |
| startGrid("srv1"); |
| |
| ListeningTestLogger srv2Logger = new ListeningTestLogger(null); |
| LogListener cacheGrpLsnr2 = matches("Cache group 'default' brings high overhead").build(); |
| srv2Logger.registerListener(cacheGrpLsnr2); |
| logger = srv2Logger; |
| |
| startGrid("srv2"); |
| |
| ignite0.cluster().active(true); |
| |
| IgniteEx cl = startGrid("client01"); |
| |
| CacheConfiguration<Object, Object> manyPartitionsCache = new CacheConfiguration<>(DEFAULT_CACHE_NAME); |
| |
| manyPartitionsCache.setAffinity(new RendezvousAffinityFunction(false, numOfPartitions)); |
| manyPartitionsCache.setNodeFilter(new NodeNameNodeFilter(filteredSrvName)); |
| manyPartitionsCache.setBackups(1); |
| |
| cl.createCache(manyPartitionsCache); |
| |
| //srv0 and srv1 print warning into the log as the threshold for cache in default cache group is broken |
| assertTrue(cacheGrpLsnr0.check()); |
| assertTrue(dataRegLsnr0.check()); |
| assertTrue(partsInfoLsnr0.check()); |
| |
| assertTrue(cacheGrpLsnr1.check()); |
| assertTrue(dataRegLsnr1.check()); |
| assertTrue(partsInfoLsnr1.check()); |
| |
| //srv2 doesn't print the warning as it is filtered by node filter from affinity nodes |
| assertFalse(cacheGrpLsnr2.check()); |
| } |
| |
| /** |
| * Verifies that warning is printed out to logs if after removing nodes from baseline |
| * some caches reach or cross dangerous limit of metainformation overhead per data region. |
| * |
| * @throws Exception If failed. |
| */ |
| @Test |
| public void testWarningOnBaselineTopologyChange() throws Exception { |
| DataRegionConfiguration defaultRegionCfg = new DataRegionConfiguration(); |
| defaultRegionCfg.setInitialSize(DFLT_MEM_PLC_SIZE); |
| defaultRegionCfg.setMaxSize(DFLT_MEM_PLC_SIZE); |
| defaultRegionCfg.setPersistenceEnabled(true); |
| |
| memCfg = new DataStorageConfiguration(); |
| memCfg.setDefaultDataRegionConfiguration(defaultRegionCfg); |
| //one hour to guarantee that checkpoint will be triggered by 'dirty pages amount' trigger |
| memCfg.setCheckpointFrequency(60 * 60 * 1000); |
| |
| ListeningTestLogger srv0Logger = new ListeningTestLogger(null); |
| LogListener cacheGrpLsnr0 = matches("Cache group 'default' brings high overhead").build(); |
| srv0Logger.registerListener(cacheGrpLsnr0); |
| logger = srv0Logger; |
| |
| IgniteEx ignite0 = startGrid("srv0"); |
| |
| ListeningTestLogger srv1Logger = new ListeningTestLogger(null); |
| LogListener cacheGrpLsnr1 = matches("Cache group 'default' brings high overhead").build(); |
| srv1Logger.registerListener(cacheGrpLsnr1); |
| logger = srv1Logger; |
| |
| startGrid("srv1"); |
| |
| ignite0.cluster().active(true); |
| |
| ignite0.createCache( |
| new CacheConfiguration<>(DEFAULT_CACHE_NAME) |
| .setDataRegionName(defaultRegionCfg.getName()) |
| .setCacheMode(CacheMode.PARTITIONED) |
| .setAffinity(new RendezvousAffinityFunction(false, 512)) |
| ); |
| |
| assertFalse(cacheGrpLsnr0.check()); |
| assertFalse(cacheGrpLsnr1.check()); |
| |
| stopGrid("srv1"); |
| |
| ignite0.cluster().baselineAutoAdjustEnabled(false); |
| |
| long topVer = ignite0.cluster().topologyVersion(); |
| |
| ignite0.cluster().setBaselineTopology(topVer); |
| |
| awaitPartitionMapExchange(); |
| |
| assertTrue(cacheGrpLsnr0.check()); |
| } |
| |
| /** |
| * Negative test: verifies that no warning is printed to logs if user starts static and dynamic caches |
| * in data region with enough capacity to host these caches; |
| * in other words, no thresholds for metapages ration are broken. |
| * |
| * @throws Exception If failed. |
| */ |
| @Test |
| public void testNoWarningIfCacheConfigurationDoesntBreakThreshold() throws Exception { |
| DataRegionConfiguration defaultRegionCfg = new DataRegionConfiguration(); |
| defaultRegionCfg.setInitialSize(DFLT_MEM_PLC_SIZE); |
| defaultRegionCfg.setMaxSize(DFLT_MEM_PLC_SIZE); |
| defaultRegionCfg.setPersistenceEnabled(true); |
| |
| memCfg = new DataStorageConfiguration(); |
| memCfg.setDefaultDataRegionConfiguration(defaultRegionCfg); |
| //one hour to guarantee that checkpoint will be triggered by 'dirty pages amount' trigger |
| memCfg.setCheckpointFrequency(60 * 60 * 1000); |
| |
| CacheConfiguration<Object, Object> fewPartitionsCache = new CacheConfiguration<>(DEFAULT_CACHE_NAME); |
| |
| //512 partitions are enough only if primary and backups count |
| fewPartitionsCache.setAffinity(new RendezvousAffinityFunction(false, 16)); |
| fewPartitionsCache.setBackups(1); |
| |
| ccfg = fewPartitionsCache; |
| |
| ListeningTestLogger srv0Logger = new ListeningTestLogger(null); |
| LogListener cacheGrpLsnr0 = matches("Cache group 'default' brings high overhead").build(); |
| LogListener dynamicGrpLsnr = matches("Cache group 'dynamicCache' brings high overhead").build(); |
| srv0Logger.registerListener(cacheGrpLsnr0); |
| srv0Logger.registerListener(dynamicGrpLsnr); |
| logger = srv0Logger; |
| |
| IgniteEx ignite0 = startGrid("srv0"); |
| |
| ignite0.cluster().active(true); |
| |
| assertFalse(cacheGrpLsnr0.check()); |
| |
| ignite0.createCache(new CacheConfiguration<>("dynamicCache") |
| .setAffinity(new RendezvousAffinityFunction(false, 16)) |
| ); |
| |
| assertFalse(dynamicGrpLsnr.check()); |
| } |
| |
| /** |
| * Verifies that {@link IgniteCheckedException} is thrown when page eviction threshold is less than 0.5. |
| */ |
| @Test |
| public void testSetSmallInvalidEviction() { |
| final double SMALL_EVICTION_THRESHOLD = 0.1D; |
| DataRegionConfiguration invCfg = new DataRegionConfiguration(); |
| |
| invCfg.setName("invCfg"); |
| invCfg.setInitialSize(DFLT_MEM_PLC_SIZE); |
| invCfg.setMaxSize(DFLT_MEM_PLC_SIZE); |
| invCfg.setPageEvictionMode(DataPageEvictionMode.RANDOM_LRU); |
| // Setting the page eviction threshold less than 0.5 |
| invCfg.setEvictionThreshold(SMALL_EVICTION_THRESHOLD); |
| |
| memCfg = new DataStorageConfiguration(); |
| memCfg.setDataRegionConfigurations(invCfg); |
| |
| ccfg = new CacheConfiguration(DEFAULT_CACHE_NAME); |
| |
| checkStartGridException(IgniteCheckedException.class, "Failed to start processor: GridProcessorAdapter []"); |
| } |
| |
| /** |
| * Verifies that {@link IgniteCheckedException} is thrown when page eviction threshold is greater than 0.999. |
| */ |
| @Test |
| public void testSetBigInvalidEviction() { |
| final double BIG_EVICTION_THRESHOLD = 1.0D; |
| DataRegionConfiguration invCfg = new DataRegionConfiguration(); |
| |
| invCfg.setName("invCfg"); |
| invCfg.setInitialSize(DFLT_MEM_PLC_SIZE); |
| invCfg.setMaxSize(DFLT_MEM_PLC_SIZE); |
| invCfg.setPageEvictionMode(DataPageEvictionMode.RANDOM_LRU); |
| // Setting the page eviction threshold greater than 0.999 |
| invCfg.setEvictionThreshold(BIG_EVICTION_THRESHOLD); |
| |
| memCfg = new DataStorageConfiguration(); |
| memCfg.setDataRegionConfigurations(invCfg); |
| |
| ccfg = new CacheConfiguration(DEFAULT_CACHE_NAME); |
| |
| checkStartGridException(IgniteCheckedException.class, "Failed to start processor: GridProcessorAdapter []"); |
| } |
| |
| /** |
| * Verifies that {@link IgniteCheckedException} is thrown when empty pages pool size is less than 10 |
| */ |
| @Test |
| public void testInvalidSmallEmptyPagesPoolSize() { |
| final int SMALL_PAGES_POOL_SIZE = 5; |
| DataRegionConfiguration invCfg = new DataRegionConfiguration(); |
| |
| invCfg.setName("invCfg"); |
| invCfg.setInitialSize(DFLT_MEM_PLC_SIZE); |
| invCfg.setMaxSize(DFLT_MEM_PLC_SIZE); |
| invCfg.setPageEvictionMode(DataPageEvictionMode.RANDOM_LRU); |
| // Setting the pages pool size less than 10 |
| invCfg.setEmptyPagesPoolSize(SMALL_PAGES_POOL_SIZE); |
| |
| memCfg = new DataStorageConfiguration(); |
| memCfg.setDataRegionConfigurations(invCfg); |
| |
| ccfg = new CacheConfiguration(DEFAULT_CACHE_NAME); |
| |
| checkStartGridException(IgniteCheckedException.class, "Failed to start processor: GridProcessorAdapter []"); |
| } |
| |
| /** |
| * Verifies that {@link IgniteCheckedException} is thrown when empty pages pool size is greater than |
| * DataRegionConfiguration.getMaxSize() / DataStorageConfiguration.getPageSize() / 10. |
| */ |
| @Test |
| public void testInvalidBigEmptyPagesPoolSize() { |
| final int DFLT_PAGE_SIZE = 1024; |
| long expectedMaxPoolSize; |
| DataRegionConfiguration invCfg = new DataRegionConfiguration(); |
| |
| invCfg.setName("invCfg"); |
| invCfg.setInitialSize(DFLT_MEM_PLC_SIZE); |
| invCfg.setMaxSize(DFLT_MEM_PLC_SIZE); |
| invCfg.setPageEvictionMode(DataPageEvictionMode.RANDOM_LRU); |
| |
| memCfg = new DataStorageConfiguration(); |
| memCfg.setDataRegionConfigurations(invCfg); |
| memCfg.setPageSize(DFLT_PAGE_SIZE); |
| |
| ccfg = new CacheConfiguration(DEFAULT_CACHE_NAME); |
| |
| expectedMaxPoolSize = invCfg.getMaxSize() / memCfg.getPageSize() / 10; |
| |
| if (expectedMaxPoolSize < Integer.MAX_VALUE) { |
| // Setting the empty pages pool size greater than |
| // DataRegionConfiguration.getMaxSize() / DataStorageConfiguration.getPageSize() / 10 |
| invCfg.setEmptyPagesPoolSize((int)expectedMaxPoolSize + 1); |
| memCfg.setDataRegionConfigurations(invCfg); |
| checkStartGridException(IgniteCheckedException.class, "Failed to start processor: GridProcessorAdapter []"); |
| } |
| } |
| |
| /** |
| * Verifies that {@link IgniteCheckedException} is thrown when IgniteCheckedException if validation of |
| * memory metrics properties fails. Metrics rate time interval must not be less than 1000ms. |
| */ |
| @Test |
| public void testInvalidMetricsProperties() { |
| final long SMALL_RATE_TIME_INTERVAL_MS = 999; |
| DataRegionConfiguration invCfg = new DataRegionConfiguration(); |
| |
| invCfg.setName("invCfg"); |
| invCfg.setInitialSize(DFLT_MEM_PLC_SIZE); |
| invCfg.setMaxSize(DFLT_MEM_PLC_SIZE); |
| invCfg.setPageEvictionMode(DataPageEvictionMode.RANDOM_LRU); |
| // Setting the metrics rate time less then 1000ms |
| invCfg.setMetricsRateTimeInterval(SMALL_RATE_TIME_INTERVAL_MS); |
| |
| memCfg = new DataStorageConfiguration(); |
| memCfg.setDataRegionConfigurations(invCfg); |
| |
| ccfg = new CacheConfiguration(DEFAULT_CACHE_NAME); |
| |
| checkStartGridException(IgniteCheckedException.class, "Failed to start processor: GridProcessorAdapter []"); |
| } |
| |
| /** |
| * Verifies that {@link IgniteCheckedException} is thrown when IgniteCheckedException if validation of |
| * memory metrics properties fails. Metrics sub interval count must be positive. |
| */ |
| @Test |
| public void testInvalidSubIntervalCount() { |
| final int NEG_SUB_INTERVAL_COUNT = -1000; |
| DataRegionConfiguration invCfg = new DataRegionConfiguration(); |
| |
| invCfg.setName("invCfg"); |
| invCfg.setInitialSize(DFLT_MEM_PLC_SIZE); |
| invCfg.setMaxSize(DFLT_MEM_PLC_SIZE); |
| invCfg.setPageEvictionMode(DataPageEvictionMode.RANDOM_LRU); |
| // Setting the metrics sub interval count as negative |
| invCfg.setMetricsSubIntervalCount(NEG_SUB_INTERVAL_COUNT); |
| |
| memCfg = new DataStorageConfiguration(); |
| memCfg.setDataRegionConfigurations(invCfg); |
| |
| ccfg = new CacheConfiguration(DEFAULT_CACHE_NAME); |
| |
| checkStartGridException(IgniteCheckedException.class, "Failed to start processor: GridProcessorAdapter []"); |
| } |
| |
| /** |
| * Test checks that nodes will not fall if you receive a request |
| * to create a cache with an unknown data region. |
| * |
| * @throws Exception If failed. |
| */ |
| @Test |
| public void testNoFailNodeIfUnknownDataRegion() throws Exception { |
| failureHnd = new StopNodeOrHaltFailureHandler(); |
| ccfg = new CacheConfiguration<>(DEFAULT_CACHE_NAME); |
| memCfg = new DataStorageConfiguration() |
| .setDefaultDataRegionConfiguration(new DataRegionConfiguration().setPersistenceEnabled(true)); |
| |
| LogListener logLsnr = matches("Possible failure suppressed accordingly to a configured handler").build(); |
| logger = new ListeningTestLogger(log, logLsnr); |
| |
| IgniteEx srvNode = startGrid(0); |
| |
| String dataRegionName = "region"; |
| |
| IgniteConfiguration clientCfg = getConfiguration(getTestIgniteInstanceName(1)) |
| .setDataStorageConfiguration( |
| new DataStorageConfiguration() |
| .setDataRegionConfigurations(new DataRegionConfiguration().setName(dataRegionName)) |
| .setDefaultDataRegionConfiguration(new DataRegionConfiguration().setPersistenceEnabled(true)) |
| ); |
| |
| IgniteEx clientNode = startClientGrid(optimize(clientCfg)); |
| |
| srvNode.cluster().active(true); |
| |
| assertThrows(log, () -> { |
| clientNode.getOrCreateCache( |
| new CacheConfiguration<>(DEFAULT_CACHE_NAME + 1).setDataRegionName(dataRegionName) |
| ); |
| |
| return null; |
| }, CacheException.class, null); |
| |
| assertThrows(log, () -> { |
| clientNode.getOrCreateCache( |
| new CacheConfiguration<>(DEFAULT_CACHE_NAME + 1).setDataRegionName(UUID.randomUUID().toString()) |
| ); |
| |
| return null; |
| }, CacheException.class, null); |
| |
| IgniteCache<Object, Object> cacheSrv = srvNode.cache(DEFAULT_CACHE_NAME); |
| IgniteCache<Object, Object> cacheClient = clientNode.cache(DEFAULT_CACHE_NAME); |
| |
| cacheSrv.put(1, 1); |
| assertEquals(1, cacheSrv.get(1)); |
| |
| cacheClient.put(2, 2); |
| assertEquals(2, cacheClient.get(2)); |
| |
| assertFalse(logLsnr.check()); |
| } |
| |
| /** |
| * Verify that the eviction strategy can support large dataregion. |
| */ |
| @Test |
| public void testLargeRegionsWithRandomLRU() throws Exception { |
| doTestLargeRegionsWithEviction(DataPageEvictionMode.RANDOM_LRU); |
| } |
| |
| /** |
| * Verify that the eviction strategy can support large dataregion. |
| */ |
| @Test |
| public void testLargeRegionsWithRandom2LRU() throws Exception { |
| doTestLargeRegionsWithEviction(DataPageEvictionMode.RANDOM_2_LRU); |
| } |
| |
| /** |
| * @param evictMode Page eviction mode. |
| * @throws Exception If failed. |
| */ |
| private void doTestLargeRegionsWithEviction(DataPageEvictionMode evictMode) throws Exception { |
| DataRegionConfiguration cfg = new DataRegionConfiguration() |
| .setName("region-1") |
| .setMaxSize(4 * 1024 * U.GB) |
| .setPageEvictionMode(evictMode); |
| |
| memCfg = new DataStorageConfiguration().setDataRegionConfigurations(cfg); |
| |
| startGrid(); |
| } |
| } |