Repository: ignite Updated Branches: refs/heads/master 44b0622db -> 6b60badfb
IGNITE-7489 Factor total allocated pages in data region's fillFactor, add test. - Fixes #3463. Signed-off-by: Alexey Goncharuk <alexey.goncha...@gmail.com> Project: http://git-wip-us.apache.org/repos/asf/ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/6b60badf Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/6b60badf Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/6b60badf Branch: refs/heads/master Commit: 6b60badfb02b1046a4c1851bf560bac9bcb2c348 Parents: 44b0622 Author: Ilya Kasnacheev <ilya.kasnach...@gmail.com> Authored: Thu Feb 22 13:23:41 2018 +0300 Committer: Alexey Goncharuk <alexey.goncha...@gmail.com> Committed: Thu Feb 22 13:23:41 2018 +0300 ---------------------------------------------------------------------- .../persistence/DataRegionMetricsImpl.java | 14 +- .../GridCacheDatabaseSharedManager.java | 21 +- .../persistence/GridCacheOffheapManager.java | 16 +- .../IgniteCacheDatabaseSharedManager.java | 17 +- .../persistence/freelist/AbstractFreeList.java | 24 +-- .../pagemem/FillFactorMetricTest.java | 214 +++++++++++++++++++ .../ignite/testsuites/IgnitePdsTestSuite.java | 4 + 7 files changed, 257 insertions(+), 53 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ignite/blob/6b60badf/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/DataRegionMetricsImpl.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/DataRegionMetricsImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/DataRegionMetricsImpl.java index a21e306..bc5b32d 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/DataRegionMetricsImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/DataRegionMetricsImpl.java @@ -30,7 +30,7 @@ import org.jetbrains.annotations.Nullable; */ public class DataRegionMetricsImpl implements DataRegionMetrics, AllocatedPageTracker { /** */ - private final IgniteOutClosure<Float> fillFactorProvider; + private final IgniteOutClosure<Long> freeSpaceProvider; /** */ private final LongAdder totalAllocatedPages = new LongAdder(); @@ -83,9 +83,9 @@ public class DataRegionMetricsImpl implements DataRegionMetrics, AllocatedPageTr /** * @param memPlcCfg DataRegionConfiguration. */ - public DataRegionMetricsImpl(DataRegionConfiguration memPlcCfg, @Nullable IgniteOutClosure<Float> fillFactorProvider) { + public DataRegionMetricsImpl(DataRegionConfiguration memPlcCfg, @Nullable IgniteOutClosure<Long> freeSpaceProvider) { this.memPlcCfg = memPlcCfg; - this.fillFactorProvider = fillFactorProvider; + this.freeSpaceProvider = freeSpaceProvider; metricsEnabled = memPlcCfg.isMetricsEnabled(); @@ -142,10 +142,14 @@ public class DataRegionMetricsImpl implements DataRegionMetrics, AllocatedPageTr /** {@inheritDoc} */ @Override public float getPagesFillFactor() { - if (!metricsEnabled || fillFactorProvider == null) + if (!metricsEnabled || freeSpaceProvider == null) return 0; - return fillFactorProvider.apply(); + long freeSpace = freeSpaceProvider.apply(); + + long totalAllocated = getPageSize() * totalAllocatedPages.longValue(); + + return (float) (totalAllocated - freeSpace) / totalAllocated; } /** {@inheritDoc} */ http://git-wip-us.apache.org/repos/asf/ignite/blob/6b60badf/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheDatabaseSharedManager.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheDatabaseSharedManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheDatabaseSharedManager.java index fde5fb4..d4ba4ef 100755 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheDatabaseSharedManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheDatabaseSharedManager.java @@ -679,16 +679,15 @@ public class GridCacheDatabaseSharedManager extends IgniteCacheDatabaseSharedMan } /** {@inheritDoc} */ - @Override protected IgniteOutClosure<Float> fillFactorProvider(final DataRegionConfiguration dataRegCfg) { + @Override protected IgniteOutClosure<Long> freeSpaceProvider(final DataRegionConfiguration dataRegCfg) { if (!dataRegCfg.isPersistenceEnabled()) - return super.fillFactorProvider(dataRegCfg); + return super.freeSpaceProvider(dataRegCfg); final String dataRegName = dataRegCfg.getName(); - return new IgniteOutClosure<Float>() { - @Override public Float apply() { - long loadSize = 0L; - long totalSize = 0L; + return new IgniteOutClosure<Long>() { + @Override public Long apply() { + long freeSpace = 0L; for (CacheGroupContext grpCtx : cctx.cache().cacheGroups()) { if (!grpCtx.dataRegion().config().getName().equals(dataRegName)) @@ -696,16 +695,10 @@ public class GridCacheDatabaseSharedManager extends IgniteCacheDatabaseSharedMan assert grpCtx.offheap() instanceof GridCacheOffheapManager; - T2<Long, Long> fillFactor = ((GridCacheOffheapManager)grpCtx.offheap()).fillFactor(); - - loadSize += fillFactor.get1(); - totalSize += fillFactor.get2(); + freeSpace += ((GridCacheOffheapManager)grpCtx.offheap()).freeSpace(); } - if (totalSize == 0) - return (float)0; - - return (float)loadSize / totalSize; + return freeSpace; } }; } http://git-wip-us.apache.org/repos/asf/ignite/blob/6b60badf/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheOffheapManager.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheOffheapManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheOffheapManager.java index 4837f6e..befe062 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheOffheapManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheOffheapManager.java @@ -720,13 +720,12 @@ public class GridCacheOffheapManager extends IgniteCacheOffheapManagerImpl imple } /** - * Calculates fill factor of all partition data stores. + * Calculates free space of all partition data stores - number of bytes available for use in allocated pages. * * @return Tuple (numenator, denominator). */ - T2<Long, Long> fillFactor() { - long loadSize = 0; - long totalSize = 0; + long freeSpace() { + long freeSpace = 0; for (CacheDataStore store : partDataStores.values()) { assert store instanceof GridCacheDataStore; @@ -736,13 +735,10 @@ public class GridCacheOffheapManager extends IgniteCacheOffheapManagerImpl imple if (freeList == null) continue; - T2<Long, Long> fillFactor = freeList.fillFactor(); - - loadSize += fillFactor.get1(); - totalSize += fillFactor.get2(); + freeSpace += freeList.freeSpace(); } - return new T2<>(loadSize, totalSize); + return freeSpace; } /** @@ -1042,7 +1038,7 @@ public class GridCacheOffheapManager extends IgniteCacheOffheapManagerImpl imple reuseRoot.isAllocated()) { @Override protected long allocatePageNoReuse() throws IgniteCheckedException { assert grp.shared().database().checkpointLockIsHeldByThread(); - + return pageMem.allocatePage(grpId, partId, PageIdAllocator.FLAG_DATA); } }; http://git-wip-us.apache.org/repos/asf/ignite/blob/6b60badf/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/IgniteCacheDatabaseSharedManager.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/IgniteCacheDatabaseSharedManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/IgniteCacheDatabaseSharedManager.java index 4330a0b..b63e985 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/IgniteCacheDatabaseSharedManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/IgniteCacheDatabaseSharedManager.java @@ -268,7 +268,7 @@ public class IgniteCacheDatabaseSharedManager extends GridCacheSharedManagerAdap if (dfltMemPlcName == null) dfltMemPlcName = DFLT_DATA_REG_DEFAULT_NAME; - DataRegionMetricsImpl memMetrics = new DataRegionMetricsImpl(dataRegionCfg, fillFactorProvider(dataRegionCfg)); + DataRegionMetricsImpl memMetrics = new DataRegionMetricsImpl(dataRegionCfg, freeSpaceProvider(dataRegionCfg)); DataRegion memPlc = initMemory(dataStorageCfg, dataRegionCfg, memMetrics, trackable); @@ -289,28 +289,23 @@ public class IgniteCacheDatabaseSharedManager extends GridCacheSharedManagerAdap * @param dataRegCfg Data region configuration. * @return Closure. */ - protected IgniteOutClosure<Float> fillFactorProvider(final DataRegionConfiguration dataRegCfg) { + protected IgniteOutClosure<Long> freeSpaceProvider(final DataRegionConfiguration dataRegCfg) { final String dataRegName = dataRegCfg.getName(); - return new IgniteOutClosure<Float>() { + return new IgniteOutClosure<Long>() { private CacheFreeListImpl freeList; - @Override public Float apply() { + @Override public Long apply() { if (freeList == null) { CacheFreeListImpl freeList0 = freeListMap.get(dataRegName); if (freeList0 == null) - return (float) 0; + return 0L; freeList = freeList0; } - T2<Long, Long> fillFactor = freeList.fillFactor(); - - if (fillFactor.get2() == 0) - return (float) 0; - - return (float) fillFactor.get1() / fillFactor.get2(); + return freeList.freeSpace(); } }; } http://git-wip-us.apache.org/repos/asf/ignite/blob/6b60badf/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java index 0847ca6..5f5948d 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/AbstractFreeList.java @@ -63,7 +63,10 @@ public abstract class AbstractFreeList<T extends Storable> extends PagesList imp /** */ private static final int MIN_PAGE_FREE_SPACE = 8; - /** */ + /** + * Step between buckets in free list, measured in powers of two. + * For example, for page size 4096 and 256 buckets, shift is 4 and step is 16 bytes. + */ private final int shift; /** */ @@ -368,27 +371,22 @@ public abstract class AbstractFreeList<T extends Storable> extends PagesList imp } /** - * Calculates average fill factor over FreeListImpl instance. + * Calculates free space tracked by this FreeListImpl instance. * - * @return Tuple (numenator, denominator). + * @return Free space available for use, in bytes. */ - public T2<Long, Long> fillFactor() { - long pageSize = pageSize(); - - long totalSize = 0; - long loadSize = 0; + public long freeSpace() { + long freeSpace = 0; for (int b = BUCKETS - 2; b > 0; b--) { - long bsize = pageSize - ((REUSE_BUCKET - b) << shift); + long perPageFreeSpace = b << shift; long pages = bucketsSize[b].longValue(); - loadSize += pages * (pageSize - bsize); - - totalSize += pages * pageSize; + freeSpace += pages * perPageFreeSpace; } - return totalSize == 0 ? new T2<>(0L, 0L) : new T2<>(loadSize, totalSize); + return freeSpace; } /** {@inheritDoc} */ http://git-wip-us.apache.org/repos/asf/ignite/blob/6b60badf/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/pagemem/FillFactorMetricTest.java ---------------------------------------------------------------------- diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/pagemem/FillFactorMetricTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/pagemem/FillFactorMetricTest.java new file mode 100644 index 0000000..cdea7bc --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/pagemem/FillFactorMetricTest.java @@ -0,0 +1,214 @@ +/* + * 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.persistence.pagemem; + +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import org.apache.ignite.DataRegionMetrics; +import org.apache.ignite.IgniteCache; +import org.apache.ignite.cache.affinity.rendezvous.RendezvousAffinityFunction; +import org.apache.ignite.configuration.CacheConfiguration; +import org.apache.ignite.configuration.DataRegionConfiguration; +import org.apache.ignite.configuration.DataStorageConfiguration; +import org.apache.ignite.configuration.IgniteConfiguration; +import org.apache.ignite.internal.IgniteInternalFuture; +import org.apache.ignite.internal.IgniteInterruptedCheckedException; +import org.apache.ignite.internal.util.typedef.internal.U; +import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi; +import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder; +import org.apache.ignite.testframework.GridTestUtils; +import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest; + +/** + * Tests for fillFactor metrics. + */ +public class FillFactorMetricTest extends GridCommonAbstractTest { + /** */ + private static final TcpDiscoveryVmIpFinder IP_FINDER = new TcpDiscoveryVmIpFinder(true); + + /** */ + private static final String MY_DATA_REGION = "MyPolicy"; + + /** */ + private static final String MY_CACHE = "mycache"; + + /** */ + public static final int NODES = 2; + + /** */ + public static final long LARGE_PRIME = 4294967291L; + + /** {@inheritDoc} */ + @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception { + return super.getConfiguration(igniteInstanceName) + .setDiscoverySpi(new TcpDiscoverySpi().setIpFinder(IP_FINDER)) + .setDataStorageConfiguration( + new DataStorageConfiguration().setDataRegionConfigurations( + new DataRegionConfiguration() + .setName(MY_DATA_REGION) + .setInitialSize(100 * 1024L * 1024L) + .setMaxSize(200 * 1024L * 1024L) + .setMetricsEnabled(true) + )); + } + + /** */ + protected CacheConfiguration<Object, Object> cacheCfg() { + return new CacheConfiguration<>() + .setName(MY_CACHE) + .setDataRegionName(MY_DATA_REGION) + .setAffinity(new RendezvousAffinityFunction().setPartitions(16)); + } + + /** {@inheritDoc} */ + @Override protected void afterTest() throws Exception { + stopAllGrids(); + } + + /** + * Records counter. + */ + private AtomicInteger recordsInCache = new AtomicInteger(); + + /** + * Last fill factor values. + */ + private final float[] curFillFactor = new float[NODES]; + + /** + * throws if failed. + */ + public void testFillAndEmpty() throws Exception { + final AtomicBoolean stopLoadFlag = new AtomicBoolean(); + final AtomicBoolean doneFlag = new AtomicBoolean(); + + startGrids(NODES); + + grid(0).getOrCreateCache(cacheCfg()); + + final int pageSize = grid(0).configuration().getDataStorageConfiguration().getPageSize(); + + IgniteInternalFuture printStatFut = GridTestUtils.runAsync(new Runnable() { + @Override public void run() { + while (!doneFlag.get()) { + log.info("Stat nodes:"); + printStat(0); + printStat(1); + + try { + U.sleep(1000); + } + catch (IgniteInterruptedCheckedException e) { + return; + } + } + } + + protected void printStat(int node) { + DataRegionMetrics m = grid(node).dataRegionMetrics(MY_DATA_REGION); + + float fillFactor = m.getPagesFillFactor(); + + long usedMem = (long)((m.getPhysicalMemoryPages() * pageSize) + * fillFactor); + + log.info(String.format("Stat node-%d:\t%d\t%f\t%d", + node, + m.getPhysicalMemoryPages(), + fillFactor, + usedMem + )); + + curFillFactor[node] = fillFactor; + } + }); + + for (int iter = 0; iter < 3; iter++) { + log.info("Going upward"); + + stopLoadFlag.set(false); + recordsInCache.set(0); + + IgniteInternalFuture loadFut = GridTestUtils.runAsync(new Runnable() { + @Override public void run() { + IgniteCache<Object, Object> cache = grid(0).cache(MY_CACHE); + + while (!stopLoadFlag.get()) { + int i = recordsInCache.incrementAndGet(); + + final long res = (i * i) % LARGE_PRIME; + + cache.put(res, new byte[1 << (res % 16)]); + + try { + // Steadily add entries to cache but avoid overconsumption of RAM and CPU + Thread.sleep(1); + } + catch (InterruptedException ie) { + return; + } + } + } + }); + + // Wait for cache to be reasonably full + U.sleep(6_000); + + stopLoadFlag.set(true); + + loadFut.get(); + + // Fill factor will typically be 0.98 + for (float fillFactor : curFillFactor) + assertTrue("FillFactor too low: " + fillFactor, fillFactor > 0.9); + + log.info("Going downward"); + + IgniteInternalFuture clearFut = GridTestUtils.runAsync(new Runnable() { + @Override public void run() { + IgniteCache<Object, Object> cache = grid(0).cache(MY_CACHE); + + int i; + while ((i = recordsInCache.getAndDecrement()) > 0) { + final long res = (i * i) % LARGE_PRIME; + + cache.remove(res); + + try { + Thread.sleep(1); + } + catch (InterruptedException ie) { + return; + } + } + } + }); + + // Wait for cache to be cleared + clearFut.get(); + + // Fill factor will typically be 0.8, occupied pages mostly partition metadata + for (float fillFactor : curFillFactor) + assertTrue("FillFactor too high: " + fillFactor, fillFactor < 0.85); + } + + doneFlag.set(true); + + printStatFut.get(); + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/6b60badf/modules/core/src/test/java/org/apache/ignite/testsuites/IgnitePdsTestSuite.java ---------------------------------------------------------------------- diff --git a/modules/core/src/test/java/org/apache/ignite/testsuites/IgnitePdsTestSuite.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgnitePdsTestSuite.java index f957aec..a8397d7 100644 --- a/modules/core/src/test/java/org/apache/ignite/testsuites/IgnitePdsTestSuite.java +++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgnitePdsTestSuite.java @@ -28,6 +28,7 @@ import org.apache.ignite.internal.processors.cache.persistence.db.file.IgnitePds import org.apache.ignite.internal.processors.cache.persistence.db.file.IgnitePdsEvictionTest; import org.apache.ignite.internal.processors.cache.persistence.pagemem.BPlusTreePageMemoryImplTest; import org.apache.ignite.internal.processors.cache.persistence.pagemem.BPlusTreeReuseListPageMemoryImplTest; +import org.apache.ignite.internal.processors.cache.persistence.pagemem.FillFactorMetricTest; import org.apache.ignite.internal.processors.cache.persistence.pagemem.IndexStoragePageMemoryImplTest; import org.apache.ignite.internal.processors.cache.persistence.pagemem.PageMemoryImplNoLoadTest; import org.apache.ignite.internal.processors.cache.persistence.pagemem.PageMemoryImplTest; @@ -68,6 +69,9 @@ public class IgnitePdsTestSuite extends TestSuite { // Write throttling suite.addTestSuite(PagesWriteThrottleSmokeTest.class); + // Metrics + suite.addTestSuite(FillFactorMetricTest.class); + return suite; }