IGNITE-794 WIP on memory estimation.
Project: http://git-wip-us.apache.org/repos/asf/incubator-ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-ignite/commit/5bcac1c7 Tree: http://git-wip-us.apache.org/repos/asf/incubator-ignite/tree/5bcac1c7 Diff: http://git-wip-us.apache.org/repos/asf/incubator-ignite/diff/5bcac1c7 Branch: refs/heads/ignite-794 Commit: 5bcac1c73f5528f10fffbf27353dce464df1568e Parents: 779f341 Author: AKuznetsov <akuznet...@gridgain.com> Authored: Mon Apr 27 17:46:50 2015 +0700 Committer: AKuznetsov <akuznet...@gridgain.com> Committed: Mon Apr 27 17:46:50 2015 +0700 ---------------------------------------------------------------------- modules/core/pom.xml | 6 - .../ignite/internal/visor/cache/VisorCache.java | 81 ++++++--- .../processors/query/h2/IgniteH2Indexing.java | 9 +- modules/memory/pom.xml | 75 +++++++++ .../apache/ignite/memory/MemoryEstimator.java | 168 +++++++++++++++++++ pom.xml | 1 + 6 files changed, 310 insertions(+), 30 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/5bcac1c7/modules/core/pom.xml ---------------------------------------------------------------------- diff --git a/modules/core/pom.xml b/modules/core/pom.xml index b374edf..62612f8 100644 --- a/modules/core/pom.xml +++ b/modules/core/pom.xml @@ -41,12 +41,6 @@ </dependency> <dependency> - <groupId>org.ehcache</groupId> - <artifactId>sizeof</artifactId> - <version>0.3.0-SNAPSHOT</version> - </dependency> - - <dependency> <groupId>mx4j</groupId> <artifactId>mx4j-tools</artifactId> <version>3.0.1</version> http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/5bcac1c7/modules/core/src/main/java/org/apache/ignite/internal/visor/cache/VisorCache.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/visor/cache/VisorCache.java b/modules/core/src/main/java/org/apache/ignite/internal/visor/cache/VisorCache.java index 1ba003f..a2f24a7 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/visor/cache/VisorCache.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/visor/cache/VisorCache.java @@ -27,14 +27,13 @@ import org.apache.ignite.internal.processors.cache.*; import org.apache.ignite.internal.processors.cache.distributed.dht.*; import org.apache.ignite.internal.processors.cache.distributed.dht.preloader.*; import org.apache.ignite.internal.processors.cache.distributed.near.*; -import org.apache.ignite.internal.processors.query.*; import org.apache.ignite.internal.util.lang.*; import org.apache.ignite.internal.util.typedef.internal.*; import org.apache.ignite.lang.*; -import org.ehcache.sizeof.*; import org.jetbrains.annotations.*; import java.io.*; +import java.lang.reflect.*; import java.util.*; import java.util.concurrent.*; @@ -45,8 +44,17 @@ public class VisorCache implements Serializable { /** */ private static final long serialVersionUID = 0L; - /** Default cache size sampling. */ - private static final int DFLT_CACHE_SIZE_SAMPLING = 10; + /** */ + private static final String MEM_ESTIMATOR = "MemoryEstimator"; + + /** */ + private static final String MEM_ESTIMATOR_INSTALLED = "MemoryEstimatorInstalled"; + + /** */ + private static final String MEM_ESTIMATOR_CACHE_SZ_MTHD = "MemoryEstimatorCacheSizeMethod"; + + /** */ + private static final String MEM_ESTIMATOR_INDEXES_SZ_MTHD = "MemoryEstimatorIndexesSizeMethod"; /** Cache name. */ private String name; @@ -60,6 +68,9 @@ public class VisorCache implements Serializable { /** Cache size in bytes. */ private long memorySize; + /** Cache size in bytes. */ + private long indexesSize; + /** Number of all entries in cache. */ private int size; @@ -196,7 +207,6 @@ public class VisorCache implements Serializable { nearSize = ca.nearSize(); dynamicDeploymentId = ca.context().dynamicDeploymentId(); - memorySize = estimateMemorySize(ignite, ca, sample); dhtSize = size - nearSize; primarySize = ca.primarySize(); offHeapAllocatedSize = ca.offHeapAllocatedSize(); @@ -204,6 +214,8 @@ public class VisorCache implements Serializable { partitions = ca.affinity().partitions(); metrics = VisorCacheMetrics.from(ignite, ca); + estimateMemorySize(ignite, ca, sample); + return this; } @@ -216,34 +228,51 @@ public class VisorCache implements Serializable { * @return Estimation of memory size occupied by cache. * @throws IgniteCheckedException If estimation failed. */ - protected long estimateMemorySize(IgniteEx ignite, GridCacheAdapter ca, int sample) throws IgniteCheckedException { - ConcurrentMap<String, SizeOf> storage = ignite.cluster().nodeLocalMap(); + protected void estimateMemorySize(IgniteEx ignite, GridCacheAdapter ca, int sample) throws IgniteCheckedException { + ConcurrentMap<String, Object> storage = ignite.cluster().nodeLocalMap(); - SizeOf sizeOf = storage.get("SizeOf"); + Boolean installed = (Boolean)storage.get(MEM_ESTIMATOR_INSTALLED); - if (sizeOf == null) - sizeOf = SizeOf.newInstance(); + if (installed == null) { + try { + Class<?> cls = Class.forName("org.apache.ignite.memory.MemoryEstimator"); - int cnt = Math.min(sample > 0 ? sample : DFLT_CACHE_SIZE_SAMPLING, ca.size()); + Object estimator = cls.newInstance(); - long memSz = 0; + Method mtdCacheSz = cls.getMethod("estimateCacheSize", GridCacheAdapter.class, int.class); + Method mtdIndexesSz = cls.getMethod("estimateIndexesSize", IgniteEx.class, GridCacheAdapter.class); - if (cnt > 0) { - for (int i = 0; i < cnt; i++) { - GridCacheMapEntry entry = ca.randomInternalEntry(); + memorySize = (Long)mtdCacheSz.invoke(estimator, ca, sample); + indexesSize = (Long)mtdIndexesSz.invoke(estimator, ignite, ca); - long ksz = sizeOf.deepSizeOf(Integer.MAX_VALUE, false, entry.key()).getCalculated(); - long vsz = sizeOf.deepSizeOf(Integer.MAX_VALUE, false, entry.rawGet()).getCalculated(); - - memSz += (ksz + vsz); + storage.putIfAbsent(MEM_ESTIMATOR, estimator); + storage.putIfAbsent(MEM_ESTIMATOR_CACHE_SZ_MTHD, mtdCacheSz); + storage.putIfAbsent(MEM_ESTIMATOR_INDEXES_SZ_MTHD, mtdIndexesSz); + storage.putIfAbsent(MEM_ESTIMATOR_INSTALLED, Boolean.TRUE); } + catch (Exception e) { + storage.putIfAbsent(MEM_ESTIMATOR_INSTALLED, Boolean.FALSE); - memSz = (long)((double)memSz / cnt * size); + throw U.cast(e); + } } + else if (installed) { + Object estimator = storage.get(MEM_ESTIMATOR); + Method mtdCacheSz = (Method)storage.get(MEM_ESTIMATOR_CACHE_SZ_MTHD); + Method mtdIndexesSz = (Method)storage.get(MEM_ESTIMATOR_INDEXES_SZ_MTHD); + + assert estimator != null && mtdCacheSz != null && mtdIndexesSz != null; - GridQueryIndexing indexing = ignite.context().query().indexing(); + try { + memorySize = (Long)mtdCacheSz.invoke(estimator, ca, sample); + indexesSize = (Long)mtdIndexesSz.invoke(estimator, ignite, ca); + } + catch (Exception e) { + throw U.cast(e); + } + } - return memSz; + System.out.println("Cache: " + name + ", entries memory=" + memorySize + ", indexes memory=" + indexesSize); } /** @@ -255,6 +284,7 @@ public class VisorCache implements Serializable { c.name = name; c.mode = mode; c.memorySize = memorySize; + c.indexesSize = indexesSize; c.size = size; c.nearSize = nearSize; c.dhtSize = dhtSize; @@ -300,6 +330,13 @@ public class VisorCache implements Serializable { } /** + * @return Indexes size in bytes. + */ + public long indexesSize() { + return indexesSize; + } + + /** * @return Number of all entries in cache. */ public int size() { http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/5bcac1c7/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java ---------------------------------------------------------------------- diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java index 1bc3409..4fcbe10 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java @@ -1044,7 +1044,7 @@ public class IgniteH2Indexing implements GridQueryIndexing { * @param schema Schema name. * @return Collection of table descriptors. */ - private Collection<TableDescriptor> tables(String schema) { + public Collection<TableDescriptor> tables(String schema) { Schema s = schemas.get(schema); if (s == null) @@ -1480,7 +1480,7 @@ public class IgniteH2Indexing implements GridQueryIndexing { /** * Information about table in database. */ - private class TableDescriptor implements GridH2Table.IndexesFactory { + public class TableDescriptor implements GridH2Table.IndexesFactory { /** */ private final String fullTblName; @@ -1541,6 +1541,11 @@ public class IgniteH2Indexing implements GridQueryIndexing { return S.toString(TableDescriptor.class, this); } + public GridH2Table h2Table() { + return tbl; + } + + /** {@inheritDoc} */ @Override public ArrayList<Index> createIndexes(GridH2Table tbl) { this.tbl = tbl; http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/5bcac1c7/modules/memory/pom.xml ---------------------------------------------------------------------- diff --git a/modules/memory/pom.xml b/modules/memory/pom.xml new file mode 100644 index 0000000..4d373a1 --- /dev/null +++ b/modules/memory/pom.xml @@ -0,0 +1,75 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<!-- + 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. +--> + +<!-- + POM file. +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.apache.ignite</groupId> + <artifactId>ignite-parent</artifactId> + <version>1</version> + <relativePath>../../parent</relativePath> + </parent> + + <artifactId>ignite-memory</artifactId> + <version>1.0.3-SNAPSHOT</version> + + <dependencies> + <dependency> + <groupId>org.apache.ignite</groupId> + <artifactId>ignite-core</artifactId> + <version>${project.version}</version> + </dependency> + + <dependency> + <groupId>org.apache.ignite</groupId> + <artifactId>ignite-indexing</artifactId> + <version>${project.version}</version> + </dependency> + + <dependency> + <groupId>org.ehcache</groupId> + <artifactId>sizeof</artifactId> + <version>0.3.0-SNAPSHOT</version> + </dependency> + </dependencies> + + <build> + <resources> + <resource> + <directory>src/main/java</directory> + <excludes> + <exclude>**/*.java</exclude> + </excludes> + </resource> + </resources> + + <testResources> + <testResource> + <directory>src/test/java</directory> + <excludes> + <exclude>**/*.java</exclude> + </excludes> + </testResource> + </testResources> + </build> +</project> http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/5bcac1c7/modules/memory/src/main/java/org/apache/ignite/memory/MemoryEstimator.java ---------------------------------------------------------------------- diff --git a/modules/memory/src/main/java/org/apache/ignite/memory/MemoryEstimator.java b/modules/memory/src/main/java/org/apache/ignite/memory/MemoryEstimator.java new file mode 100644 index 0000000..80c68c3 --- /dev/null +++ b/modules/memory/src/main/java/org/apache/ignite/memory/MemoryEstimator.java @@ -0,0 +1,168 @@ +/* + * 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.memory; + +import org.apache.ignite.internal.*; +import org.apache.ignite.internal.processors.cache.*; +import org.apache.ignite.internal.processors.query.*; +import org.apache.ignite.internal.processors.query.h2.*; +import org.apache.ignite.internal.processors.query.h2.IgniteH2Indexing.*; +import org.apache.ignite.internal.processors.query.h2.opt.*; +import org.ehcache.sizeof.*; +import org.ehcache.sizeof.filters.*; +import org.h2.index.*; + +import java.lang.reflect.*; +import java.util.*; + +/** + * Utility class that will estimate memory occupied by cache. + */ +public class MemoryEstimator { + /** Default cache size sampling. */ + private static final int DFLT_CACHE_SIZE_SAMPLING = 10; + + /** */ + private final SizeOf sizeOfCache; + /** */ + private final SizeOf sizeOfIndex1; + + private final Set<String> ignored = new HashSet<>(); +// /** */ +// private final SizeOf sizeOfIndex2; + + /** + * Default constructor. + */ + public MemoryEstimator() { + ignored.add("org.h2.engine.Database"); + ignored.add("org.h2.message.TraceSystem"); + + SizeOfFilter filter1 = new SizeOfFilter() { + @Override public Collection<Field> filterFields(Class<?> klazz, Collection<Field> fields) { + return fields; + } + + @Override public boolean filterClass(Class<?> klazz) { + String klazzName = klazz.getName(); + + System.out.println("]]] " + klazzName); + + return true; + } + }; + + SizeOfFilter filter = new SizeOfFilter() { + @Override public Collection<Field> filterFields(Class<?> klazz, Collection<Field> fields) { + return fields; + } + + @Override public boolean filterClass(Class<?> klazz) { + String klazzName = klazz.getName(); + + boolean f = (!klazzName.startsWith("org.apache.ignite") || + klazzName.contains("h2") || klazzName.contains("H2") || + klazzName.contains("snaptree")) && + !ignored.contains(klazzName); + + System.out.println("))) " + klazzName + " " + f); + + return f; + } + }; + + sizeOfCache = SizeOf.newInstance(filter1); + sizeOfIndex1 = SizeOf.newInstance(filter); + } + + /** + * Estimate memory size for entries in cache. + * + * @param ca Cache to estimate. + * @param sample Number of entries to sample. + * @return Memory size in bytes under cache entries. + */ + public long estimateCacheSize(GridCacheAdapter ca, int sample) { + int size = ca.size(); + + int cnt = Math.min(sample > 0 ? sample : DFLT_CACHE_SIZE_SAMPLING, size); + + long memSz = 0; + + if (cnt > 0) { + for (int i = 0; i < cnt; i++) { + GridCacheMapEntry entry = ca.randomInternalEntry(); + + long ksz = sizeOfCache.deepSizeOf(Integer.MAX_VALUE, false, entry.key()).getCalculated(); + long vsz = sizeOfCache.deepSizeOf(Integer.MAX_VALUE, false, entry.rawGet()).getCalculated(); + + memSz += (ksz + vsz); + } + + memSz = (long)((double)memSz / cnt * size); + } + + return memSz; + } + + /** + * Estimate memory size for cache indexes. + * + * @param ignite Ignite. + * @param ca Cache to estimate. + * @return Memory size in bytes under indexes. + */ + public long estimateIndexesSize(IgniteEx ignite, GridCacheAdapter ca) { + long memSz = 0; + + GridQueryIndexing indexing = ignite.context().query().indexing(); + + if (indexing instanceof IgniteH2Indexing) { + IgniteH2Indexing h2Indexing = (IgniteH2Indexing)indexing; + + String cacheName = ca.name(); + + if (cacheName == null) + cacheName = ""; + + Collection<TableDescriptor> tbls = h2Indexing.tables(cacheName); + + for (TableDescriptor tbl : tbls) { + GridH2Table h2Tbl = tbl.h2Table(); + + Iterator<Index> idxs = h2Tbl.getIndexes().iterator(); + + // Skip first index, as it is special wrapper. + if (idxs.hasNext()) + idxs.next(); + + while (idxs.hasNext()) { + Index idx = idxs.next(); + + long idxSz = sizeOfIndex1.deepSizeOf(Integer.MAX_VALUE, false, idx).getCalculated(); + + System.out.println("Index=" + idx + ", size=" + idxSz); + + memSz += idxSz; + } + } + } + + return memSz; + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/5bcac1c7/pom.xml ---------------------------------------------------------------------- diff --git a/pom.xml b/pom.xml index 8810b17..bc83d73 100644 --- a/pom.xml +++ b/pom.xml @@ -74,6 +74,7 @@ <module>modules/slf4j</module> <module>modules/jcl</module> <module>modules/schema-import</module> + <module>modules/memory</module> <module>modules/codegen</module> </modules>