diff --git a/modules/core/src/main/java/org/apache/ignite/internal/cache/query/index/sorted/inline/InlineIndexTree.java b/modules/core/src/main/java/org/apache/ignite/internal/cache/query/index/sorted/inline/InlineIndexTree.java index 4198b6e14a4f3..6e55dbe89565a 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/cache/query/index/sorted/inline/InlineIndexTree.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/cache/query/index/sorted/inline/InlineIndexTree.java @@ -107,6 +107,9 @@ public class InlineIndexTree extends BPlusTree { /** Row cache. */ private final @Nullable IndexRowCache idxRowCache; + /** Full row load count metric. */ + @Nullable private final LongAdderMetric fullRowLoadCnt; + /** * Constructor. */ @@ -193,6 +196,18 @@ public InlineIndexTree( initTree(initNew, inlineSize); this.recommender = recommender; + + fullRowLoadCnt = fullRowLoadMetric(def); + } + + /** */ + @Nullable private static LongAdderMetric fullRowLoadMetric(SortedIndexDefinition def) { + MetricRegistryImpl mreg = indexMetricRegistry(def); + + if (mreg == null) + return null; + + return mreg.longAdderMetric("FullRowLoadCount", "Count of full entry loads during index search"); } /** */ @@ -249,12 +264,33 @@ private boolean inlineObjectSupported(SortedIndexDefinition def, MetaPageInfo me } } + /** */ + @Nullable private static MetricRegistryImpl indexMetricRegistry(SortedIndexDefinition def) { + if (def == null || def.cacheInfo().cacheContext() == null) + return null; + + if (IgniteSystemProperties.getBoolean(IGNITE_BPLUS_TREE_DISABLE_METRICS)) + return null; + + return def.cacheInfo().cacheContext().shared().kernalContext().metric().registry( + metricName(INDEX_METRIC_PREFIX, def.idxName().fullName())); + } + + /** */ + private IndexRow getFullRow(BPlusIO io, long pageAddr, int idx, IndexRow searchRow) + throws IgniteCheckedException { + if (fullRowLoadCnt != null && def.cacheInfo().cacheContext().statisticsEnabled() && searchRow.indexPlainRow()) + fullRowLoadCnt.increment(); + + return getRow(io, pageAddr, idx); + } + /** {@inheritDoc} */ @Override protected int compare(BPlusIO io, long pageAddr, int idx, IndexRow row) throws IgniteCheckedException { if (inlineSize == 0) { - IndexRow currRow = getRow(io, pageAddr, idx); + IndexRow currRow = getFullRow(io, pageAddr, idx, row); return compareFullRows(currRow, row, 0, rowHandler(), def.rowComparator()); } @@ -304,7 +340,7 @@ private boolean inlineObjectSupported(SortedIndexDefinition def, MetaPageInfo me recommender.recommend(row, inlineSize, pageSize()); if (currRow == null) - currRow = getRow(io, pageAddr, idx); + currRow = getFullRow(io, pageAddr, idx, row); return compareFullRows(currRow, row, keyIdx, rowHandler(), def.rowComparator()); } @@ -604,19 +640,15 @@ public InlineIndexRowHandler rowHandler() { /** */ private static PageHandlerWrapper wrapper(SortedIndexDefinition def) { - if (def == null || def.cacheInfo().cacheContext() == null) - return null; + MetricRegistryImpl mreg = indexMetricRegistry(def); - if (IgniteSystemProperties.getBoolean(IGNITE_BPLUS_TREE_DISABLE_METRICS)) + if (mreg == null) return null; return new PageHandlerWrapper() { @Override public PageHandler wrap(BPlusTree tree, PageHandler hnd) { GridCacheContext cctx = def.cacheInfo().cacheContext(); - MetricRegistryImpl mreg = cctx.shared().kernalContext().metric().registry( - metricName(INDEX_METRIC_PREFIX, def.idxName().fullName())); - LongAdderMetric cnt = mreg.longAdderMetric(hnd.getClass().getSimpleName() + "Count", "Count of " + hnd.getClass().getSimpleName() + " operations"); LongAdderMetric time = mreg.longAdderMetric(hnd.getClass().getSimpleName() + "Time", diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/InlineIndexTreeTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/InlineIndexTreeTest.java new file mode 100644 index 0000000000000..50941aa30cbc6 --- /dev/null +++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/InlineIndexTreeTest.java @@ -0,0 +1,261 @@ +/* + * 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.index; + +import org.apache.ignite.IgniteCache; +import org.apache.ignite.IgniteSystemProperties; +import org.apache.ignite.cache.query.SqlFieldsQuery; +import org.apache.ignite.cache.query.annotations.QuerySqlField; +import org.apache.ignite.configuration.CacheConfiguration; +import org.apache.ignite.internal.IgniteEx; +import org.apache.ignite.internal.cache.query.index.sorted.inline.InlineIndexImpl; +import org.apache.ignite.spi.metric.LongMetric; +import org.apache.ignite.spi.metric.ReadOnlyMetricRegistry; +import org.apache.ignite.testframework.junits.WithSystemProperty; +import org.junit.Test; + +/** + * Tests for inline index tree behavior. + */ +public class InlineIndexTreeTest extends AbstractIndexingCommonTest { + /** */ + private static final String FULL_ROW_LOAD_CNT = "FullRowLoadCount"; + + /** */ + private static final String LONG_STR_IDX = "longStrField_idx"; + + /** */ + private static final int ROWS = 5000; + + /** */ + private static final String LONG_STR_PREFIX = "a".repeat(50); + + /** + * Checks that full row load metric is incremented when inline size is small. + * + * @throws Exception If failed. + */ + @Test + public void testFullRowLoadsMetric() throws Exception { + TestContext ctx = prepareCluster(4); + + assertEquals(0, metric(ctx.longStrFieldReg)); + + insertRows(ctx.cache); + + long before = metric(ctx.longStrFieldReg); + + queryByLongStrField(ctx.cache, 3000); + + long after = metric(ctx.longStrFieldReg); + + assertTrue(after > before); + } + + /** + * Checks that full row load metric is not incremented when inline size is big. + * + * @throws Exception If failed. + */ + @Test + public void testFullRowLoadsMetricBigInlineSize() throws Exception { + TestContext ctx = prepareCluster(128); + + assertEquals(0, metric(ctx.longStrFieldReg)); + + insertRows(ctx.cache); + + long before = metric(ctx.longStrFieldReg); + + queryByLongStrField(ctx.cache, 3000); + + long after = metric(ctx.longStrFieldReg); + + assertEquals(before, after); + } + + /** + * Checks that put operations do not increment full row loads metric. + * + * @throws Exception If failed. + */ + @Test + public void testMetricOnPut() throws Exception { + TestContext ctx = prepareCluster(4); + + long before = metric(ctx.longStrFieldReg); + + insertRows(ctx.cache); + + long after = metric(ctx.longStrFieldReg); + + assertEquals(before, after); + } + + /** + * Checks that full row loads metric is not incremented when cache statistics is disabled. + * + * @throws Exception If failed. + */ + @Test + public void testFullRowLoadMetricStatisticsDisabled() throws Exception { + TestContext ctx = prepareCluster(4); + + insertRows(ctx.cache); + + ctx.cache.enableStatistics(false); + + queryByLongStrField(ctx.cache, 3000); + + assertEquals(0, metric(ctx.longStrFieldReg)); + + ctx.cache.enableStatistics(true); + + queryByLongStrField(ctx.cache, 3000); + + assertTrue(metric(ctx.longStrFieldReg) > 0); + } + + /** + * Checks that inline index tree metrics are not registered when metrics are disabled. + * + * @throws Exception If failed. + */ + @Test + @WithSystemProperty(key = IgniteSystemProperties.IGNITE_BPLUS_TREE_DISABLE_METRICS, value = "true") + public void testMetricsDisabled() throws Exception { + IgniteEx ignite = startGrid(0); + + IgniteCache cache = ignite.getOrCreateCache(cacheConfiguration(DEFAULT_CACHE_NAME)); + + createLongStrIdx(cache, 4); + + for (ReadOnlyMetricRegistry reg : ignite.context().metric()) + assertFalse(reg.name().startsWith(InlineIndexImpl.INDEX_METRIC_PREFIX)); + } + + /** */ + private CacheConfiguration cacheConfiguration(String cacheName) { + CacheConfiguration ccfg = new CacheConfiguration<>(cacheName); + + ccfg.setIndexedTypes(Integer.class, TestClass.class); + ccfg.setStatisticsEnabled(true); + + return ccfg; + } + + /** */ + private TestContext prepareCluster(int inlineSize) throws Exception { + IgniteEx ignite = startGrid(0); + + IgniteCache cache = ignite.getOrCreateCache(cacheConfiguration(DEFAULT_CACHE_NAME)); + + createLongStrIdx(cache, inlineSize); + + ReadOnlyMetricRegistry longStrFieldReg = findRegistry(ignite, LONG_STR_IDX); + + return new TestContext(cache, longStrFieldReg); + } + + /** */ + private void createLongStrIdx(IgniteCache cache, int inlineSize) { + cache.query(new SqlFieldsQuery( + "CREATE INDEX " + LONG_STR_IDX + " ON TESTCLASS(longStrField) INLINE_SIZE " + inlineSize + )).getAll(); + } + + /** */ + private void insertRows(IgniteCache cache) { + for (int i = 0; i < ROWS; i++) + cache.put(i, new TestClass(i)); + } + + /** */ + private void queryByLongStrField(IgniteCache cache, int val) { + cache.query(new SqlFieldsQuery("SELECT * FROM TESTCLASS WHERE LONGSTRFIELD = ?") + .setArgs(longStrField(val))).getAll(); + } + + /** */ + private ReadOnlyMetricRegistry findRegistry(IgniteEx ignite, String idxName) { + for (ReadOnlyMetricRegistry reg : ignite.context().metric()) { + if (reg.name().startsWith(InlineIndexImpl.INDEX_METRIC_PREFIX) && + reg.name().toUpperCase().contains(idxName.toUpperCase())) + return reg; + } + + throw new AssertionError("Not found metric registry for index " + idxName); + } + + /** */ + private long metric(ReadOnlyMetricRegistry reg) { + LongMetric m = reg.findMetric(FULL_ROW_LOAD_CNT); + + if (m == null) + throw new AssertionError("Not found metric " + FULL_ROW_LOAD_CNT + " in registry " + reg.name()); + + return m.value(); + } + + /** */ + private static String longStrField(int val) { + return LONG_STR_PREFIX + val; + } + + /** {@inheritDoc} */ + @Override protected void afterTest() throws Exception { + stopAllGrids(); + + super.afterTest(); + } + + /** */ + private static class TestContext { + /** */ + private final IgniteCache cache; + + /** */ + private final ReadOnlyMetricRegistry longStrFieldReg; + + /** */ + private TestContext( + IgniteCache cache, + ReadOnlyMetricRegistry longStrFieldReg + ) { + this.cache = cache; + this.longStrFieldReg = longStrFieldReg; + } + } + + /** */ + private static class TestClass { + /** */ + @QuerySqlField(index = true) + private final int intField; + + /** */ + @QuerySqlField + private final String longStrField; + + /** */ + public TestClass(int val) { + intField = val; + longStrField = longStrField(val); + } + } +} diff --git a/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteCacheWithIndexingTestSuite.java b/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteCacheWithIndexingTestSuite.java index 2e78be26fda11..49b267bb64a99 100644 --- a/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteCacheWithIndexingTestSuite.java +++ b/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteCacheWithIndexingTestSuite.java @@ -48,6 +48,7 @@ import org.apache.ignite.internal.processors.cache.WrongIndexedTypesTest; import org.apache.ignite.internal.processors.cache.index.H2TreeCorruptedTreeExceptionTest; import org.apache.ignite.internal.processors.cache.index.IndexCorruptionRebuildTest; +import org.apache.ignite.internal.processors.cache.index.InlineIndexTreeTest; import org.apache.ignite.internal.processors.cache.persistence.RebuildIndexLogMessageTest; import org.apache.ignite.internal.processors.cache.persistence.filename.SQLCacheConfigStoragePathTest; import org.apache.ignite.internal.processors.cache.ttl.CacheSizeTtlTest; @@ -67,6 +68,7 @@ @Suite.SuiteClasses({ InlineIndexColumnTest.class, ComputeInlineSizeTest.class, + InlineIndexTreeTest.class, GridIndexingWithNoopSwapSelfTest.class, GridCacheOffHeapSelfTest.class,