IGNITE-13364 Improve calculation of default index inline size - Fixes #9167.
Signed-off-by: Ivan Daschinsky <ivandasch@apache.org>
diff --git a/modules/control-utility/src/test/java/org/apache/ignite/internal/commandline/indexreader/IgniteIndexReaderTest.java b/modules/control-utility/src/test/java/org/apache/ignite/internal/commandline/indexreader/IgniteIndexReaderTest.java
index 5d82835..8bc8fdd 100644
--- a/modules/control-utility/src/test/java/org/apache/ignite/internal/commandline/indexreader/IgniteIndexReaderTest.java
+++ b/modules/control-utility/src/test/java/org/apache/ignite/internal/commandline/indexreader/IgniteIndexReaderTest.java
@@ -891,7 +891,7 @@
boolean idxReadingErr = isReportIdxAndPartFilesReadingErr();
boolean partReadingErr = isReportIdxAndPartFilesReadingErr();
- checkOutput(output, 19, 24, 0, 1, idxReadingErr, partReadingErr, false);
+ checkOutput(output, 19, 25, 0, 1, idxReadingErr, partReadingErr, false);
for (int i = 0; i < CREATED_TABLES_CNT; i++)
checkIdxs(output, TableInfo.generate(i), true);
@@ -926,7 +926,7 @@
boolean partReadingErr = isReportIdxAndPartFilesReadingErr();
- checkOutput(output, 19, 22, 0, 0, false, partReadingErr, true);
+ checkOutput(output, 19, 23, 0, 0, false, partReadingErr, true);
for (int i = 0; i < CREATED_TABLES_CNT; i++)
checkIdxs(output, TableInfo.generate(i), true);
diff --git a/modules/core/src/main/java/org/apache/ignite/IgniteSystemProperties.java b/modules/core/src/main/java/org/apache/ignite/IgniteSystemProperties.java
index 3a3a4f8..178ce8e 100644
--- a/modules/core/src/main/java/org/apache/ignite/IgniteSystemProperties.java
+++ b/modules/core/src/main/java/org/apache/ignite/IgniteSystemProperties.java
@@ -1057,7 +1057,7 @@
* Defaults to {@code 0}, meaning that inline index store is disabled.
*/
@SystemProperty(value = "Maximum payload size in bytes for H2TreeIndex. " +
- "0 means that inline index store is disabled", type = Integer.class, defaults = "10")
+ "0 means that inline index store is disabled", type = Integer.class, defaults = "64")
public static final String IGNITE_MAX_INDEX_PAYLOAD_SIZE = "IGNITE_MAX_INDEX_PAYLOAD_SIZE";
/**
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/cache/query/index/sorted/IndexKeyDefinition.java b/modules/core/src/main/java/org/apache/ignite/internal/cache/query/index/sorted/IndexKeyDefinition.java
index a7e6c5a..140f0ac 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/cache/query/index/sorted/IndexKeyDefinition.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/cache/query/index/sorted/IndexKeyDefinition.java
@@ -34,11 +34,20 @@
/** Order. */
private final Order order;
+ /** Precision for variable length key types. */
+ private final int precision;
+
/** */
- public IndexKeyDefinition(String name, int idxType, Order order) {
+ public IndexKeyDefinition(String name, int idxType, Order order, long precision) {
this.idxType = idxType;
this.order = order;
this.name = name;
+
+ // Workaround due to wrong type conversion (int -> long).
+ if (precision >= Integer.MAX_VALUE)
+ this.precision = -1;
+ else
+ this.precision = (int)precision;
}
/** */
@@ -56,6 +65,11 @@
return name;
}
+ /** */
+ public int precision() {
+ return precision;
+ }
+
/**
* @return {@code true} if specified key's type matches to the current type, otherwise {@code false}.
*/
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 6b3736d..b6c2764 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
@@ -68,6 +68,12 @@
* BPlusTree where nodes stores inlined index keys.
*/
public class InlineIndexTree extends BPlusTree<IndexRow, IndexRow> {
+ /**
+ * Default sql index size for types with variable length (such as String or byte[]).
+ * Note that effective length will be lower, because 3 bytes will be taken for the inner representation of variable type.
+ */
+ public static final int IGNITE_VARIABLE_TYPE_DEFAULT_INLINE_SIZE = 10;
+
/** Amount of bytes to store inlined index keys. */
private final int inlineSize;
@@ -178,7 +184,9 @@
rowHnd = rowHndFactory.create(def, keyTypeSettings);
- inlineSize = computeInlineSize(rowHnd.inlineIndexKeyTypes(), configuredInlineSize, maxInlineSize);
+ inlineSize = computeInlineSize(
+ rowHnd.inlineIndexKeyTypes(), rowHnd.indexKeyDefinitions(),
+ configuredInlineSize, maxInlineSize);
setIos(inlineSize, mvccEnabled);
}
@@ -428,12 +436,14 @@
/**
* @param keyTypes Index key types.
+ * @param keyDefs Index key definitions.
* @param cfgInlineSize Inline size from index config.
* @param maxInlineSize Max inline size from cache config.
* @return Inline size.
*/
public static int computeInlineSize(
List<InlineIndexKeyType> keyTypes,
+ List<IndexKeyDefinition> keyDefs,
int cfgInlineSize,
int maxInlineSize
) {
@@ -452,13 +462,27 @@
int size = 0;
- for (InlineIndexKeyType keyType: keyTypes) {
- if (keyType.inlineSize() <= 0) {
+ for (int i = 0; i < keyTypes.size(); i++) {
+ InlineIndexKeyType keyType = keyTypes.get(i);
+
+ int sizeInc = keyType.inlineSize();
+
+ if (sizeInc < 0) {
+ int precision = keyDefs.get(i).precision();
+
+ if (precision > 0)
+ // 3 is required to store (type, length) of value.
+ sizeInc = 3 + precision;
+ else
+ sizeInc = IGNITE_VARIABLE_TYPE_DEFAULT_INLINE_SIZE;
+ }
+
+ size += sizeInc;
+
+ if (size > propSize) {
size = propSize;
break;
}
-
- size += keyType.inlineSize();
}
return Math.min(PageIO.MAX_PAYLOAD_SIZE, size);
@@ -474,7 +498,7 @@
}
/** Default value for {@code IGNITE_MAX_INDEX_PAYLOAD_SIZE} */
- public static final int IGNITE_MAX_INDEX_PAYLOAD_SIZE_DEFAULT = 10;
+ public static final int IGNITE_MAX_INDEX_PAYLOAD_SIZE_DEFAULT = 64;
/**
* @return Inline size.
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2TreeIndexBase.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2TreeIndexBase.java
index 8072cd1..2ca9f68 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2TreeIndexBase.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2TreeIndexBase.java
@@ -32,9 +32,6 @@
* H2 tree index base.
*/
public abstract class H2TreeIndexBase extends GridH2IndexBase {
- /** Default value for {@code IGNITE_MAX_INDEX_PAYLOAD_SIZE} */
- public static final int IGNITE_MAX_INDEX_PAYLOAD_SIZE_DEFAULT = 10;
-
/**
* Constructor.
*
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/index/QueryIndexKeyDefinitionProvider.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/index/QueryIndexKeyDefinitionProvider.java
index 307ea55..6e07e00 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/index/QueryIndexKeyDefinitionProvider.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/index/QueryIndexKeyDefinitionProvider.java
@@ -66,7 +66,7 @@
/** */
private IndexKeyDefinition keyDefinition(IndexColumn c) {
return new IndexKeyDefinition(
- c.columnName, c.column.getType(), sortOrder(c.sortType));
+ c.columnName, c.column.getType(), sortOrder(c.sortType), c.column.getPrecision());
}
/** Maps H2 column order to Ignite index order. */
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/index/client/ClientIndexFactory.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/index/client/ClientIndexFactory.java
index 0bd1cd5..632a3ab 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/index/client/ClientIndexFactory.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/index/client/ClientIndexFactory.java
@@ -50,7 +50,7 @@
List<InlineIndexKeyType> keyTypes = InlineIndexKeyTypeRegistry.types(keyDefs, DUMMY_SETTINGS);
- int inlineSize = InlineIndexTree.computeInlineSize(keyTypes, def.getCfgInlineSize(), def.getMaxInlineSize());
+ int inlineSize = InlineIndexTree.computeInlineSize(keyTypes, keyDefs, def.getCfgInlineSize(), def.getMaxInlineSize());
return new ClientInlineIndex(def.idxName().idxName(), inlineSize);
}
diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/SqlSystemViewsSelfTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/SqlSystemViewsSelfTest.java
index cc5739b..dde19f5 100644
--- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/SqlSystemViewsSelfTest.java
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/SqlSystemViewsSelfTest.java
@@ -21,6 +21,7 @@
import java.nio.file.Path;
import java.sql.Timestamp;
import java.time.Instant;
+import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
@@ -299,7 +300,7 @@
{1374144180, "SQL_PUBLIC_DFLT_AFF_CACHE", "PUBLIC", "DFLT_AFF_CACHE", "AFFINITY_KEY", "BTREE",
"\"ID1\" ASC, \"ID2\" ASC", false, false, 10},
{1374144180, "SQL_PUBLIC_DFLT_AFF_CACHE", "PUBLIC", "DFLT_AFF_CACHE", "IDX_AFF_1", "BTREE",
- "\"ID2\" DESC, \"ID1\" ASC, \"MY_VAL\" DESC", false, false, 10},
+ "\"ID2\" DESC, \"ID1\" ASC, \"MY_VAL\" DESC", false, false, 20},
{1374144180, "SQL_PUBLIC_DFLT_AFF_CACHE", "PUBLIC", "DFLT_AFF_CACHE", "__SCAN_", "SCAN", null, false, false, null},
{1374144180, "SQL_PUBLIC_DFLT_AFF_CACHE", "PUBLIC", "DFLT_AFF_CACHE", "_key_PK", "BTREE",
"\"ID1\" ASC, \"ID2\" ASC", true, true, 10},
@@ -307,9 +308,9 @@
"\"ID1\" ASC, \"ID2\" ASC, \"ID1\" ASC", false, true, null},
{1102275506, "SQL_PUBLIC_DFLT_CACHE", "PUBLIC", "DFLT_CACHE", "IDX_1", "BTREE",
- "\"ID2\" DESC, \"ID1\" ASC, \"MY_VAL\" DESC, \"ID1\" ASC, \"ID2\" ASC", false, false, 10},
+ "\"ID2\" DESC, \"ID1\" ASC, \"MY_VAL\" DESC, \"ID1\" ASC, \"ID2\" ASC", false, false, 25},
{1102275506, "SQL_PUBLIC_DFLT_CACHE", "PUBLIC", "DFLT_CACHE", "IDX_3", "BTREE",
- "\"MY_VAL\" ASC, \"ID1\" ASC, \"ID2\" ASC, \"ID1\" ASC, \"ID2\" ASC", false, false, 10},
+ "\"MY_VAL\" ASC, \"ID1\" ASC, \"ID2\" ASC, \"ID1\" ASC, \"ID2\" ASC", false, false, 25},
{1102275506, "SQL_PUBLIC_DFLT_CACHE", "PUBLIC", "DFLT_CACHE", "__SCAN_", "SCAN", null, false, false, null},
{1102275506, "SQL_PUBLIC_DFLT_CACHE", "PUBLIC", "DFLT_CACHE", "_key_PK", "BTREE",
"\"ID1\" ASC, \"ID2\" ASC", true, true, 10},
@@ -332,7 +333,7 @@
assertEquals(expRow.length, resRow.size());
for (int j = 0; j < expRow.length; j++)
- assertEquals(expRow[j], resRow.get(j));
+ assertEquals("expRow: [" + Arrays.toString(expRow) + "]", expRow[j], resRow.get(j));
}
}
diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/database/inlinecolumn/ComputeInlineSizeTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/database/inlinecolumn/ComputeInlineSizeTest.java
new file mode 100644
index 0000000..2cbe187
--- /dev/null
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/database/inlinecolumn/ComputeInlineSizeTest.java
@@ -0,0 +1,157 @@
+/*
+ * 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.query.h2.database.inlinecolumn;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+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.Index;
+import org.apache.ignite.internal.cache.query.index.sorted.inline.InlineIndexImpl;
+import org.apache.ignite.internal.cache.query.index.sorted.inline.InlineIndexTree;
+import org.apache.ignite.internal.processors.cache.GridCacheContext;
+import org.apache.ignite.internal.processors.cache.IgniteInternalCache;
+import org.apache.ignite.internal.processors.cache.index.AbstractIndexingCommonTest;
+import org.apache.ignite.internal.processors.cache.persistence.tree.io.PageIO;
+import org.junit.Test;
+
+/** Tests for the computation inline size. */
+public class ComputeInlineSizeTest extends AbstractIndexingCommonTest {
+ /** */
+ private static final String CACHE = "CACHE";
+
+ /** */
+ private static IgniteEx ignite;
+
+ /** {@inheritDoc} */
+ @Override protected void beforeTestsStarted() throws Exception {
+ ignite = startGrid();
+ }
+
+ /** {@inheritDoc} */
+ @Override protected void afterTest() throws Exception {
+ ignite.destroyCache(CACHE);
+ }
+
+ /** */
+ @Test
+ public void testAnnotationPrecision() {
+ CacheConfiguration<Long, Person> ccfg = new CacheConfiguration<Long, Person>()
+ .setName(CACHE)
+ .setIndexedTypes(Long.class, Person.class);
+
+ ignite.createCache(ccfg);
+
+ checkIdxsInlineSizes();
+ }
+
+ /** */
+ @Test
+ public void testSQLIndexes() {
+ StringBuilder bld = new StringBuilder();
+
+ String createQry = "create table TABLE (" +
+ "id long primary key" +
+ ", str varchar" +
+ ", bytes binary" +
+ ", strprec varchar(" + (InlineIndexTree.IGNITE_VARIABLE_TYPE_DEFAULT_INLINE_SIZE + 10) + ")" +
+ ", strprecbig varchar(" + (PageIO.MAX_PAYLOAD_SIZE * 2) + " )" +
+ ", bytesprec binary(" + (InlineIndexTree.IGNITE_VARIABLE_TYPE_DEFAULT_INLINE_SIZE + 20) + " )" +
+ ")with \"cache_name=" + CACHE + "\";";
+
+ bld.append(createQry);
+
+ for (String s: Arrays.asList("str", "strprec", "bytes", "bytesprec", "strprecbig"))
+ bld.append(String.format("create index PERSON_%s_IDX on TABLE (%s); ", s.toUpperCase(), s));
+
+ query(new SqlFieldsQuery(bld.toString()));
+
+ checkIdxsInlineSizes();
+ }
+
+ /** */
+ private void checkIdxsInlineSizes() {
+ Collection<Index> idx = ignite.context().indexProcessor().indexes(context());
+
+ Map<String, Integer> expInlineSize = new HashMap<String, Integer>() {{
+ // 9 is inline for _KEY (LongIndexKeyType).
+ put("PERSON_STR_IDX",
+ 9 + InlineIndexTree.IGNITE_VARIABLE_TYPE_DEFAULT_INLINE_SIZE);
+ put("PERSON_STRPRECBIG_IDX",
+ InlineIndexTree.IGNITE_MAX_INDEX_PAYLOAD_SIZE_DEFAULT);
+ // 3 is for storing info (type, length) of inlined key.
+ put("PERSON_STRPREC_IDX",
+ 9 + InlineIndexTree.IGNITE_VARIABLE_TYPE_DEFAULT_INLINE_SIZE + 10 + 3);
+ put("PERSON_BYTES_IDX",
+ 9 + InlineIndexTree.IGNITE_VARIABLE_TYPE_DEFAULT_INLINE_SIZE);
+ put("PERSON_BYTESPREC_IDX",
+ 9 + InlineIndexTree.IGNITE_VARIABLE_TYPE_DEFAULT_INLINE_SIZE + 20 + 3);
+ }};
+
+ for (Index i: idx) {
+ InlineIndexImpl impl = (InlineIndexImpl)i;
+
+ if (expInlineSize.containsKey(impl.name())) {
+ int inlineSize = expInlineSize.remove(impl.name());
+
+ assertEquals(inlineSize, impl.inlineSize());
+ }
+ }
+
+ assertTrue(expInlineSize.isEmpty());
+ }
+
+ /** */
+ private void query(SqlFieldsQuery qry) {
+ ignite.context().query().querySqlFields(qry, false, false);
+ }
+
+ /** */
+ private GridCacheContext<Long, Person> context() {
+ IgniteInternalCache<Long, Person> c = ignite.cachex(CACHE);
+
+ return c.context();
+ }
+
+ /** */
+ public static class Person {
+ /** */
+ @QuerySqlField(index = true)
+ private String str;
+
+ /** */
+ @QuerySqlField(index = true, precision = InlineIndexTree.IGNITE_VARIABLE_TYPE_DEFAULT_INLINE_SIZE + 10)
+ private String strPrec;
+
+ /** */
+ @QuerySqlField(index = true, precision = PageIO.MAX_PAYLOAD_SIZE * 2)
+ private String strPrecBig;
+
+ /** */
+ @QuerySqlField(index = true)
+ private byte[] bytes;
+
+ /** */
+ @QuerySqlField(index = true, precision = InlineIndexTree.IGNITE_VARIABLE_TYPE_DEFAULT_INLINE_SIZE + 20)
+ private byte[] bytesPrec;
+ }
+}
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 57ab453..c7afcfc 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
@@ -53,6 +53,7 @@
import org.apache.ignite.internal.processors.cache.ttl.CacheTtlTransactionalLocalSelfTest;
import org.apache.ignite.internal.processors.cache.ttl.CacheTtlTransactionalPartitionedSelfTest;
import org.apache.ignite.internal.processors.client.IgniteDataStreamerTest;
+import org.apache.ignite.internal.processors.query.h2.database.inlinecolumn.ComputeInlineSizeTest;
import org.apache.ignite.internal.processors.query.h2.database.inlinecolumn.InlineIndexColumnTest;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
@@ -63,6 +64,7 @@
@RunWith(Suite.class)
@Suite.SuiteClasses({
InlineIndexColumnTest.class,
+ ComputeInlineSizeTest.class,
GridIndexingWithNoopSwapSelfTest.class,
GridCacheOffHeapSelfTest.class,