You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by vo...@apache.org on 2018/10/08 11:03:05 UTC

ignite git commit: IGNITE-8507: SQL: print a warning if a row cannot be fully inlined into an index. This closes #4834.

Repository: ignite
Updated Branches:
  refs/heads/master 917a43323 -> ac04ad4b1


IGNITE-8507: SQL: print a warning if a row cannot be fully inlined into an index. This closes #4834.


Project: http://git-wip-us.apache.org/repos/asf/ignite/repo
Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/ac04ad4b
Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/ac04ad4b
Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/ac04ad4b

Branch: refs/heads/master
Commit: ac04ad4b1ebab7a546c6534c6f2842bc76c14e18
Parents: 917a433
Author: Yuriy Gerzhedovich <yg...@gridgain.com>
Authored: Mon Oct 8 14:02:57 2018 +0300
Committer: devozerov <pp...@gmail.com>
Committed: Mon Oct 8 14:02:57 2018 +0300

----------------------------------------------------------------------
 .../processors/query/h2/H2TableDescriptor.java  |   5 +-
 .../processors/query/h2/IgniteH2Indexing.java   |   6 +-
 .../processors/query/h2/database/H2Tree.java    | 145 ++++++++++++++++++-
 .../query/h2/database/H2TreeIndex.java          |  71 +++++++--
 .../query/h2/database/InlineIndexHelper.java    | 143 ++++++++++++++++--
 .../h2/database/InlineIndexHelperTest.java      |  30 ++--
 6 files changed, 358 insertions(+), 42 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/ac04ad4b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2TableDescriptor.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2TableDescriptor.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2TableDescriptor.java
index 899bdda..988ec2f 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2TableDescriptor.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2TableDescriptor.java
@@ -203,6 +203,7 @@ public class H2TableDescriptor implements GridH2SystemIndexFactory {
             "_key_PK",
             tbl,
             true,
+            false,
             H2Utils.treeIndexColumns(desc, new ArrayList<IndexColumn>(2), keyCol, affCol),
             -1
         );
@@ -250,7 +251,7 @@ public class H2TableDescriptor implements GridH2SystemIndexFactory {
 
         // Add explicit affinity key index if nothing alike was found.
         if (affCol != null && !affIdxFound) {
-            idxs.add(idx.createSortedIndex("AFFINITY_KEY", tbl, false,
+            idxs.add(idx.createSortedIndex("AFFINITY_KEY", tbl, false, true,
                 H2Utils.treeIndexColumns(desc, new ArrayList<IndexColumn>(2), affCol, keyCol), -1));
         }
 
@@ -300,7 +301,7 @@ public class H2TableDescriptor implements GridH2SystemIndexFactory {
         if (idxDesc.type() == QueryIndexType.SORTED) {
             cols = H2Utils.treeIndexColumns(desc, cols, keyCol, affCol);
 
-            return idx.createSortedIndex(idxDesc.name(), tbl, false, cols, idxDesc.inlineSize());
+            return idx.createSortedIndex(idxDesc.name(), tbl, false, false, cols, idxDesc.inlineSize());
         }
         else if (idxDesc.type() == QueryIndexType.GEOSPATIAL)
             return H2Utils.createSpatialIndex(tbl, idxDesc.name(), cols.toArray(new IndexColumn[cols.size()]));

http://git-wip-us.apache.org/repos/asf/ignite/blob/ac04ad4b/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 4b855a7..fe563b7 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
@@ -987,11 +987,13 @@ public class IgniteH2Indexing implements GridQueryIndexing {
      * @param name Index name,
      * @param tbl Table.
      * @param pk Primary key flag.
+     * @param affinityKey Affinity key flag.
      * @param cols Columns.
      * @param inlineSize Index inline size.
      * @return Index.
      */
-    GridH2IndexBase createSortedIndex(String name, GridH2Table tbl, boolean pk, List<IndexColumn> cols,
+    GridH2IndexBase createSortedIndex(String name, GridH2Table tbl, boolean pk, boolean affinityKey,
+        List<IndexColumn> cols,
         int inlineSize) {
         try {
             GridCacheContext cctx = tbl.cache();
@@ -1003,7 +1005,7 @@ public class IgniteH2Indexing implements GridQueryIndexing {
 
             H2RowCache cache = rowCache.forGroup(cctx.groupId());
 
-            return new H2TreeIndex(cctx, cache, tbl, name, pk, cols, inlineSize, segments);
+            return new H2TreeIndex(cctx, cache, tbl, name, pk, affinityKey, cols, inlineSize, segments);
         }
         catch (IgniteCheckedException e) {
             throw new IgniteException(e);

http://git-wip-us.apache.org/repos/asf/ignite/blob/ac04ad4b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2Tree.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2Tree.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2Tree.java
index ce40df0..4c6c0c0 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2Tree.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2Tree.java
@@ -17,10 +17,15 @@
 
 package org.apache.ignite.internal.processors.query.h2.database;
 
+import java.util.ArrayList;
 import java.util.Comparator;
 import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicLong;
+import java.util.stream.Collectors;
 import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.IgniteLogger;
+import org.apache.ignite.IgniteSystemProperties;
 import org.apache.ignite.internal.pagemem.PageMemory;
 import org.apache.ignite.internal.pagemem.wal.IgniteWriteAheadLogManager;
 import org.apache.ignite.internal.processors.cache.mvcc.MvccUtils;
@@ -43,6 +48,8 @@ import org.h2.table.IndexColumn;
 import org.h2.value.Value;
 import org.jetbrains.annotations.Nullable;
 
+import static org.apache.ignite.internal.processors.query.h2.database.InlineIndexHelper.CANT_BE_COMPARE;
+
 /**
  */
 public abstract class H2Tree extends BPlusTree<GridH2SearchRow, GridH2Row> {
@@ -65,6 +72,21 @@ public abstract class H2Tree extends BPlusTree<GridH2SearchRow, GridH2Row> {
     private final boolean mvccEnabled;
 
     /** */
+    private final boolean pk;
+
+    /** */
+    private final boolean affinityKey;
+
+    /** */
+    private final String cacheName;
+
+    /** */
+    private final String tblName;
+
+    /** */
+    private final String idxName;
+
+    /** */
     private final Comparator<Value> comp = new Comparator<Value>() {
         @Override public int compare(Value o1, Value o2) {
             return compareValues(o1, o2);
@@ -74,10 +96,25 @@ public abstract class H2Tree extends BPlusTree<GridH2SearchRow, GridH2Row> {
     /** Row cache. */
     private final H2RowCache rowCache;
 
+    /** How often real invocation of inline size calculation will be skipped. */
+    private static final int THROTTLE_INLINE_SIZE_CALCULATION = 1_000;
+
+    /** Counter of inline size calculation for throttling real invocations. */
+    private final ThreadLocal<Long> inlineSizeCalculationCntr = ThreadLocal.withInitial(() -> 0L);
+
+    /** Keep max calculated inline size for current index. */
+    private final AtomicInteger maxCalculatedInlineSize;
+
+    /** */
+    private final IgniteLogger log;
+
     /**
      * Constructor.
      *
      * @param name Tree name.
+     * @param idxName Name of index.
+     * @param cacheName Cache name.
+     * @param tblName Table name.
      * @param reuseList Reuse list.
      * @param grpId Cache group ID.
      * @param pageMem Page memory.
@@ -86,12 +123,18 @@ public abstract class H2Tree extends BPlusTree<GridH2SearchRow, GridH2Row> {
      * @param metaPageId Meta page ID.
      * @param initNew Initialize new index.
      * @param rowCache Row cache.
+     * @param pk {@code true} for primary key.
+     * @param affinityKey {@code true} for affinity key.
      * @param mvccEnabled Mvcc flag.
      * @param failureProcessor if the tree is corrupted.
+     * @param log Logger.
      * @throws IgniteCheckedException If failed.
      */
     protected H2Tree(
         String name,
+        String idxName,
+        String cacheName,
+        String tblName,
         ReuseList reuseList,
         int grpId,
         PageMemory pageMem,
@@ -103,9 +146,13 @@ public abstract class H2Tree extends BPlusTree<GridH2SearchRow, GridH2Row> {
         IndexColumn[] cols,
         List<InlineIndexHelper> inlineIdxs,
         int inlineSize,
+        AtomicInteger maxCalculatedInlineSize,
+        boolean pk,
+        boolean affinityKey,
         boolean mvccEnabled,
         @Nullable H2RowCache rowCache,
-        @Nullable FailureProcessor failureProcessor
+        @Nullable FailureProcessor failureProcessor,
+        IgniteLogger log
     ) throws IgniteCheckedException {
         super(name, grpId, pageMem, wal, globalRmvId, metaPageId, reuseList, failureProcessor);
 
@@ -114,7 +161,16 @@ public abstract class H2Tree extends BPlusTree<GridH2SearchRow, GridH2Row> {
             inlineSize = getMetaInlineSize();
         }
 
+        this.idxName = idxName;
+        this.cacheName = cacheName;
+        this.tblName = tblName;
+
         this.inlineSize = inlineSize;
+        this.maxCalculatedInlineSize = maxCalculatedInlineSize;
+
+        this.pk = pk;
+        this.affinityKey = affinityKey;
+
         this.mvccEnabled = mvccEnabled;
 
         assert rowStore != null;
@@ -132,6 +188,8 @@ public abstract class H2Tree extends BPlusTree<GridH2SearchRow, GridH2Row> {
 
         this.rowCache = rowCache;
 
+        this.log = log;
+
         initTree(initNew, inlineSize);
     }
 
@@ -163,7 +221,7 @@ public abstract class H2Tree extends BPlusTree<GridH2SearchRow, GridH2Row> {
      * Create row from link.
      *
      * @param link Link.
-     * @param mvccOpCntr
+     * @param mvccOpCntr MVCC operation counter.
      * @return Row.
      * @throws IgniteCheckedException if failed.
      */
@@ -247,7 +305,7 @@ public abstract class H2Tree extends BPlusTree<GridH2SearchRow, GridH2Row> {
 
                 int c = inlineIdx.compare(pageAddr, off + fieldOff, inlineSize() - fieldOff, v2, comp);
 
-                if (c == -2)
+                if (c == CANT_BE_COMPARE)
                     break;
 
                 lastIdxUsed++;
@@ -264,6 +322,8 @@ public abstract class H2Tree extends BPlusTree<GridH2SearchRow, GridH2Row> {
             if (lastIdxUsed == cols.length)
                 return mvccCompare((H2RowLinkIO)io, pageAddr, idx, row);
 
+            inlineSizeRecomendation(row);
+
             SearchRow rowData = getRow(io, pageAddr, idx);
 
             for (int i = lastIdxUsed, len = cols.length; i < len; i++) {
@@ -362,6 +422,85 @@ public abstract class H2Tree extends BPlusTree<GridH2SearchRow, GridH2Row> {
     }
 
     /**
+     * Calculate aggregate inline size for given indexes and log recommendation in case calculated size more than
+     * current inline size.
+     *
+     * @param row Grid H2 row related to given inline indexes.
+     */
+    private void inlineSizeRecomendation(SearchRow row) {
+        //Do the check only for put operations.
+        if(!(row instanceof GridH2KeyValueRowOnheap))
+            return;
+
+        Long invokeCnt = inlineSizeCalculationCntr.get();
+
+        inlineSizeCalculationCntr.set(++invokeCnt);
+
+        boolean throttle = invokeCnt % THROTTLE_INLINE_SIZE_CALCULATION != 0;
+
+        if (throttle)
+            return;
+
+        int newSize = 0;
+
+        InlineIndexHelper idx;
+
+        List<String> colNames = new ArrayList<>();
+
+        for (InlineIndexHelper index : inlineIdxs) {
+            idx = index;
+
+            newSize += idx.inlineSizeOf(row.getValue(idx.columnIndex()));
+
+            colNames.add(index.colName());
+        }
+
+        if (newSize > inlineSize()) {
+            int oldSize;
+
+            while (true) {
+                oldSize = maxCalculatedInlineSize.get();
+
+                if (oldSize >= newSize)
+                    return;
+
+                if (maxCalculatedInlineSize.compareAndSet(oldSize, newSize))
+                    break;
+            }
+
+            String cols = colNames.stream().collect(Collectors.joining(", ", "(", ")"));
+
+            String idxType = pk ? "PRIMARY KEY" : affinityKey ? "AFFINITY KEY (implicit)" : "SECONDARY";
+
+            String recommendation;
+
+            if (pk || affinityKey) {
+                recommendation = "set system property "
+                    + IgniteSystemProperties.IGNITE_MAX_INDEX_PAYLOAD_SIZE + " with recommended size " +
+                    "(be aware it will be used by default for all indexes without explicit inline size)";
+            }
+            else {
+                recommendation = "use INLINE_SIZE option for CREATE INDEX command, " +
+                    "QuerySqlField.inlineSize for annotated classes, or QueryIndex.inlineSize for explicit " +
+                    "QueryEntity configuration";
+            }
+
+            String warn = "Indexed columns of a row cannot be fully inlined into index " +
+                "what may lead to slowdown due to additional data page reads, increase index inline size if needed " +
+                "(" + recommendation + ") " +
+                "[cacheName=" + cacheName +
+                ", tableName=" + tblName +
+                ", idxName=" + idxName +
+                ", idxCols=" + cols +
+                ", idxType=" + idxType +
+                ", curSize=" + inlineSize() +
+                ", recommendedInlineSize=" + newSize + "]";
+
+            U.warn(log, warn);
+        }
+    }
+
+    /**
      * @param v1 First value.
      * @param v2 Second value.
      * @return Comparison result.

http://git-wip-us.apache.org/repos/asf/ignite/blob/ac04ad4b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2TreeIndex.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2TreeIndex.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2TreeIndex.java
index ab6f42a..a15742f 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2TreeIndex.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2TreeIndex.java
@@ -20,8 +20,10 @@ package org.apache.ignite.internal.processors.query.h2.database;
 import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
 import org.apache.ignite.IgniteCheckedException;
 import org.apache.ignite.IgniteException;
+import org.apache.ignite.IgniteLogger;
 import org.apache.ignite.IgniteSystemProperties;
 import org.apache.ignite.internal.processors.cache.GridCacheContext;
 import org.apache.ignite.internal.processors.cache.mvcc.MvccSnapshot;
@@ -41,6 +43,7 @@ import org.apache.ignite.internal.processors.query.h2.opt.GridH2Table;
 import org.apache.ignite.internal.util.IgniteTree;
 import org.apache.ignite.internal.util.lang.GridCursor;
 import org.apache.ignite.internal.util.typedef.F;
+import org.apache.ignite.internal.util.typedef.internal.U;
 import org.apache.ignite.spi.indexing.IndexingQueryCacheFilter;
 import org.apache.ignite.spi.indexing.IndexingQueryFilter;
 import org.h2.engine.Session;
@@ -73,11 +76,27 @@ public class H2TreeIndex extends GridH2IndexBase {
     /** Cache context. */
     private final GridCacheContext<?, ?> cctx;
 
+    /** Table name/ */
+    private final String tblName;
+
+    /** */
+    private final boolean pk;
+
+    /** */
+    private final boolean affinityKey;
+
+    /** */
+    private final String idxName;
+
+    /** */
+    private final IgniteLogger log;
+
     /**
      * @param cctx Cache context.
      * @param tbl Table.
-     * @param name Index name.
+     * @param idxName Index name.
      * @param pk Primary key.
+     * @param affinityKey {@code true} for affinity key.
      * @param colsList Index columns.
      * @param inlineSize Inline size.
      * @throws IgniteCheckedException If failed.
@@ -86,8 +105,9 @@ public class H2TreeIndex extends GridH2IndexBase {
         GridCacheContext<?, ?> cctx,
         @Nullable H2RowCache rowCache,
         GridH2Table tbl,
-        String name,
+        String idxName,
         boolean pk,
+        boolean affinityKey,
         List<IndexColumn> colsList,
         int inlineSize,
         int segmentsCnt
@@ -96,20 +116,28 @@ public class H2TreeIndex extends GridH2IndexBase {
 
         this.cctx = cctx;
 
+        this.log = cctx.logger(getClass().getName());
+
+        this.pk = pk;
+        this.affinityKey = affinityKey;
+
+        this.tblName = tbl.getName();
+        this.idxName = idxName;
+
         IndexColumn[] cols = colsList.toArray(new IndexColumn[colsList.size()]);
 
         IndexColumn.mapColumns(cols, tbl);
 
-        initBaseIndex(tbl, 0, name, cols,
+        initBaseIndex(tbl, 0, idxName, cols,
             pk ? IndexType.createPrimaryKey(false, false) : IndexType.createNonUnique(false, false, false));
 
         GridQueryTypeDescriptor typeDesc = tbl.rowDescriptor().type();
 
         int typeId = cctx.binaryMarshaller() ? typeDesc.typeId() : typeDesc.valueClass().hashCode();
 
-        name = (tbl.rowDescriptor() == null ? "" : typeId + "_") + name;
+        String treeName = (tbl.rowDescriptor() == null ? "" : typeId + "_") + idxName;
 
-        name = BPlusTree.treeName(name, "H2Tree");
+        treeName = BPlusTree.treeName(treeName, "H2Tree");
 
         if (cctx.affinityNode()) {
             inlineIdxs = getAvailableInlineColumns(cols);
@@ -118,15 +146,20 @@ public class H2TreeIndex extends GridH2IndexBase {
 
             IgniteCacheDatabaseSharedManager db = cctx.shared().database();
 
+            AtomicInteger maxCalculatedInlineSize = new AtomicInteger();
+
             for (int i = 0; i < segments.length; i++) {
                 db.checkpointReadLock();
 
                 try {
-                    RootPage page = getMetaPage(name, i);
+                    RootPage page = getMetaPage(treeName, i);
 
                     segments[i] = new H2Tree(
-                        name,
-                        cctx.offheap().reuseListForIndex(name),
+                        treeName,
+                        idxName,
+                        tblName,
+                        tbl.cacheName(),
+                        cctx.offheap().reuseListForIndex(treeName),
                         cctx.groupId(),
                         cctx.dataRegion().pageMemory(),
                         cctx.shared().wal(),
@@ -137,9 +170,13 @@ public class H2TreeIndex extends GridH2IndexBase {
                         cols,
                         inlineIdxs,
                         computeInlineSize(inlineIdxs, inlineSize),
+                        maxCalculatedInlineSize,
+                        pk,
+                        affinityKey,
                         cctx.mvccEnabled(),
                         rowCache,
-                        cctx.kernalContext().failure()) {
+                        cctx.kernalContext().failure(),
+                        log) {
                         @Override public int compareValues(Value v1, Value v2) {
                             return v1 == v2 ? 0 : table.compareTypeSafe(v1, v2);
                         }
@@ -167,10 +204,24 @@ public class H2TreeIndex extends GridH2IndexBase {
         List<InlineIndexHelper> res = new ArrayList<>();
 
         for (IndexColumn col : cols) {
-            if (!InlineIndexHelper.AVAILABLE_TYPES.contains(col.column.getType()))
+            if (!InlineIndexHelper.AVAILABLE_TYPES.contains(col.column.getType())) {
+                String idxType = pk ? "PRIMARY KEY" : affinityKey ? "AFFINITY KEY (implicit)" : "SECONDARY";
+
+                U.warn(log, "Column cannot be inlined into the index because it's type doesn't support inlining, " +
+                    "index access may be slow due to additional page reads (change column type if possible) " +
+                    "[cacheName=" + cctx.name() +
+                    ", tableName=" + tblName +
+                    ", idxName=" + idxName +
+                    ", idxType=" + idxType +
+                    ", colName=" + col.columnName +
+                    ", columnType=" + InlineIndexHelper.nameTypeBycode(col.column.getType()) + ']'
+                );
+
                 break;
+            }
 
             InlineIndexHelper idx = new InlineIndexHelper(
+                col.columnName,
                 col.column.getType(),
                 col.column.getColumnId(),
                 col.sortType,

http://git-wip-us.apache.org/repos/asf/ignite/blob/ac04ad4b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/InlineIndexHelper.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/InlineIndexHelper.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/InlineIndexHelper.java
index 0299033..2f88558 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/InlineIndexHelper.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/InlineIndexHelper.java
@@ -50,6 +50,9 @@ import org.h2.value.ValueUuid;
  * Helper class for in-page indexes.
  */
 public class InlineIndexHelper {
+    /** Value for comparison meaning 'Not enough information to compare'. */
+    public static final int CANT_BE_COMPARE = -2;
+
     private static final Charset CHARSET = StandardCharsets.UTF_8;
 
     /** PageContext for use in IO's */
@@ -76,6 +79,9 @@ public class InlineIndexHelper {
     );
 
     /** */
+    private final String colName;
+
+    /** */
     private final int type;
 
     /** */
@@ -94,11 +100,16 @@ public class InlineIndexHelper {
     private final boolean compareStringsOptimized;
 
     /**
+     * @param colName Column name.
      * @param type Index type (see {@link Value}).
      * @param colIdx Index column index.
      * @param sortType Column sort type (see {@link IndexColumn#sortType}).
+     * @param compareMode Compare mode.
      */
-    public InlineIndexHelper(int type, int colIdx, int sortType, CompareMode compareMode) {
+    public InlineIndexHelper(String colName, int type, int colIdx, int sortType,
+        CompareMode compareMode) {
+
+        this.colName = colName;
         this.type = type;
         this.colIdx = colIdx;
         this.sortType = sortType;
@@ -165,6 +176,13 @@ public class InlineIndexHelper {
     }
 
     /**
+     * @return Column name
+     */
+    public String colName() {
+        return colName;
+    }
+
+    /**
      * @return Index type.
      */
     public int type() {
@@ -347,7 +365,7 @@ public class InlineIndexHelper {
      * @param maxSize Maximum size to read.
      * @param v Value to compare.
      * @param comp Comparator.
-     * @return Compare result (-2 means we can't compare).
+     * @return Compare result ( {@code CANT_BE_COMPARE} means we can't compare).
      */
     public int compare(long pageAddr, int off, int maxSize, Value v, Comparator<Value> comp) {
         int c = tryCompareOptimized(pageAddr, off, maxSize, v);
@@ -358,7 +376,7 @@ public class InlineIndexHelper {
         Value v1 = get(pageAddr, off, maxSize);
 
         if (v1 == null)
-            return -2;
+            return CANT_BE_COMPARE;
 
         c = Integer.signum(comp.compare(v1, v));
 
@@ -368,7 +386,7 @@ public class InlineIndexHelper {
         if (isValueFull(pageAddr, off) || canRelyOnCompare(c, v1, v))
             return fixSort(c, sortType());
 
-        return -2;
+        return CANT_BE_COMPARE;
     }
 
     /**
@@ -376,7 +394,7 @@ public class InlineIndexHelper {
      * @param off Offset.
      * @param maxSize Maximum size to read.
      * @param v Value to compare.
-     * @return Compare result ({@code Integer.MIN_VALUE} means unsupported operation; {@code -2} - can't compare).
+     * @return Compare result ({@code Integer.MIN_VALUE} means unsupported operation; {@code CANT_BE_COMPARE} - can't compare).
      */
     private int tryCompareOptimized(long pageAddr, int off, int maxSize, Value v) {
         int type;
@@ -384,7 +402,7 @@ public class InlineIndexHelper {
         if ((size > 0 && size + 1 > maxSize)
                 || maxSize < 1
                 || (type = PageUtils.getByte(pageAddr, off)) == Value.UNKNOWN)
-            return -2;
+            return CANT_BE_COMPARE;
 
         if (type == Value.NULL)
             return Integer.MIN_VALUE;
@@ -568,7 +586,7 @@ public class InlineIndexHelper {
      * @param pageAddr Page address.
      * @param off Offset.
      * @param v Value to compare.
-     * @return Compare result ({@code -2} means we can't compare).
+     * @return Compare result ({@code CANT_BE_COMPARE} means we can't compare).
      */
     private int compareAsBytes(long pageAddr, int off, Value v) {
         byte[] bytes = v.getBytesNoCopy();
@@ -620,7 +638,7 @@ public class InlineIndexHelper {
             // b) Even truncated current value is longer, so that it's bigger.
             return fixSort(1, sortType());
 
-        return -2;
+        return CANT_BE_COMPARE;
     }
 
     /**
@@ -628,7 +646,7 @@ public class InlineIndexHelper {
      * @param off Offset.
      * @param v Value to compare.
      * @param ignoreCase {@code True} if a case-insensitive comparison should be used.
-     * @return Compare result ({@code -2} means we can't compare).
+     * @return Compare result ({@code CANT_BE_COMPARE} means we can't compare).
      */
     private int compareAsString(long pageAddr, int off, Value v, boolean ignoreCase) {
         String s = v.getString();
@@ -795,7 +813,48 @@ public class InlineIndexHelper {
             // b) Even truncated current value is longer, so that it's bigger.
             return fixSort(1, sortType());
 
-        return -2;
+        return CANT_BE_COMPARE;
+    }
+
+    /**
+     * Calculate size to inline given value.
+     *
+     * @param val Value to calculate inline size.
+     * @return Calculated inline size for given value.
+     */
+    public int inlineSizeOf(Value val){
+        if (val.getType() == Value.NULL)
+            return 1;
+
+        if (val.getType() != type)
+            throw new UnsupportedOperationException("value type doesn't match");
+
+        switch (type) {
+            case Value.BOOLEAN:
+            case Value.BYTE:
+            case Value.SHORT:
+            case Value.INT:
+            case Value.LONG:
+            case Value.FLOAT:
+            case Value.DOUBLE:
+            case Value.TIME:
+            case Value.DATE:
+            case Value.TIMESTAMP:
+            case Value.UUID:
+                return size + 1;
+
+            case Value.STRING:
+            case Value.STRING_FIXED:
+            case Value.STRING_IGNORECASE:
+                return val.getString().getBytes(CHARSET).length + 3;
+
+            case Value.BYTES:
+            case Value.JAVA_OBJECT:
+                return val.getBytes().length + 3;
+
+            default:
+                throw new UnsupportedOperationException("no get operation for fast index type " + type);
+        }
     }
 
     /**
@@ -931,7 +990,6 @@ public class InlineIndexHelper {
 
                     return maxSize;
                 }
-
             }
 
             default:
@@ -1015,4 +1073,67 @@ public class InlineIndexHelper {
     public static int fixSort(int c, int sortType) {
         return sortType == SortOrder.ASCENDING ? c : -c;
     }
+
+    /**
+     * @param typeCode Type code.
+     * @return Name.
+     */
+    public static String nameTypeBycode(int typeCode) {
+        switch (typeCode) {
+            case Value.UNKNOWN:
+                return "UNKNOWN";
+            case Value.NULL:
+                return "NULL";
+            case Value.BOOLEAN:
+                return "BOOLEAN";
+            case Value.BYTE:
+                return "BYTE";
+            case Value.SHORT:
+                return "SHORT";
+            case Value.INT:
+                return "INT";
+            case Value.LONG:
+                return "LONG";
+            case Value.DECIMAL:
+                return "DECIMAL";
+            case Value.DOUBLE:
+                return "DOUBLE";
+            case Value.FLOAT:
+                return "FLOAT";
+            case Value.TIME:
+                return "TIME";
+            case Value.DATE:
+                return "DATE";
+            case Value.TIMESTAMP:
+                return "TIMESTAMP";
+            case Value.BYTES:
+                return "BYTES";
+            case Value.STRING:
+                return "STRING";
+            case Value.STRING_IGNORECASE:
+                return "STRING_IGNORECASE";
+            case Value.BLOB:
+                return "BLOB";
+            case Value.CLOB:
+                return "CLOB";
+            case Value.ARRAY:
+                return "ARRAY";
+            case Value.RESULT_SET:
+                return "RESULT_SET";
+            case Value.JAVA_OBJECT:
+                return "JAVA_OBJECT";
+            case Value.UUID:
+                return "UUID";
+            case Value.STRING_FIXED:
+                return "STRING_FIXED";
+            case Value.GEOMETRY:
+                return "GEOMETRY";
+            case Value.TIMESTAMP_TZ:
+                return "TIMESTAMP_TZ";
+            case Value.ENUM:
+                return "ENUM";
+            default:
+                return "UNKNOWN type " + typeCode;
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/ac04ad4b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/database/InlineIndexHelperTest.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/database/InlineIndexHelperTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/database/InlineIndexHelperTest.java
index fe77da3..0600137 100644
--- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/database/InlineIndexHelperTest.java
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/database/InlineIndexHelperTest.java
@@ -53,6 +53,8 @@ import org.h2.value.ValueTimestamp;
 import org.h2.value.ValueUuid;
 import org.springframework.util.SerializationUtils;
 
+import static org.apache.ignite.internal.processors.query.h2.database.InlineIndexHelper.CANT_BE_COMPARE;
+
 /**
  * Simple tests for {@link InlineIndexHelper}.
  */
@@ -93,9 +95,9 @@ public class InlineIndexHelperTest extends GridCommonAbstractTest {
         assertEquals(1, putAndCompare("bbb", "aaa", maxSize));
         assertEquals(1, putAndCompare("aaa", "aa", maxSize));
         assertEquals(1, putAndCompare("aaa", "a", maxSize));
-        assertEquals(-2, putAndCompare("aaa", "aaa", maxSize));
-        assertEquals(-2, putAndCompare("aaa", "aab", maxSize));
-        assertEquals(-2, putAndCompare("aab", "aaa", maxSize));
+        assertEquals(CANT_BE_COMPARE, putAndCompare("aaa", "aaa", maxSize));
+        assertEquals(CANT_BE_COMPARE, putAndCompare("aaa", "aab", maxSize));
+        assertEquals(CANT_BE_COMPARE, putAndCompare("aab", "aaa", maxSize));
     }
 
     /** */
@@ -108,9 +110,9 @@ public class InlineIndexHelperTest extends GridCommonAbstractTest {
         assertEquals(1, putAndCompare("¢¢¢", "¡¡¡", maxSize));
         assertEquals(1, putAndCompare("¡¡¡", "¡¡", maxSize));
         assertEquals(1, putAndCompare("¡¡¡", "¡", maxSize));
-        assertEquals(-2, putAndCompare("¡¡¡", "¡¡¡", maxSize));
-        assertEquals(-2, putAndCompare("¡¡¡", "¡¡¢", maxSize));
-        assertEquals(-2, putAndCompare("¡¡¢", "¡¡¡", maxSize));
+        assertEquals(CANT_BE_COMPARE, putAndCompare("¡¡¡", "¡¡¡", maxSize));
+        assertEquals(CANT_BE_COMPARE, putAndCompare("¡¡¡", "¡¡¢", maxSize));
+        assertEquals(CANT_BE_COMPARE, putAndCompare("¡¡¢", "¡¡¡", maxSize));
     }
 
     /** */
@@ -207,7 +209,7 @@ public class InlineIndexHelperTest extends GridCommonAbstractTest {
 
             int off = 0;
 
-            InlineIndexHelper ih = new InlineIndexHelper(Value.STRING, 1, 0,
+            InlineIndexHelper ih = new InlineIndexHelper("", Value.STRING, 1, 0,
                 CompareMode.getInstance(null, 0));
 
             ih.put(pageAddr, off, v1 == null ? ValueNull.INSTANCE : ValueString.get(v1), maxSize);
@@ -232,7 +234,7 @@ public class InlineIndexHelperTest extends GridCommonAbstractTest {
 
     /** Test on String values compare */
     public void testRelyOnCompare() {
-        InlineIndexHelper ha = new InlineIndexHelper(Value.STRING, 0, SortOrder.ASCENDING,
+        InlineIndexHelper ha = new InlineIndexHelper("", Value.STRING, 0, SortOrder.ASCENDING,
             CompareMode.getInstance(null, 0));
 
         // same size
@@ -254,7 +256,7 @@ public class InlineIndexHelperTest extends GridCommonAbstractTest {
 
     /** Test on Bytes values compare */
     public void testRelyOnCompareBytes() {
-        InlineIndexHelper ha = new InlineIndexHelper(Value.BYTES, 0, SortOrder.ASCENDING,
+        InlineIndexHelper ha = new InlineIndexHelper("", Value.BYTES, 0, SortOrder.ASCENDING,
             CompareMode.getInstance(null, 0));
 
         // same size
@@ -276,7 +278,7 @@ public class InlineIndexHelperTest extends GridCommonAbstractTest {
 
     /** Test on Bytes values compare */
     public void testRelyOnCompareJavaObject() {
-        InlineIndexHelper ha = new InlineIndexHelper(Value.JAVA_OBJECT, 0, SortOrder.ASCENDING,
+        InlineIndexHelper ha = new InlineIndexHelper("",Value.JAVA_OBJECT, 0, SortOrder.ASCENDING,
             CompareMode.getInstance(null, 0));
 
         // different types
@@ -323,7 +325,7 @@ public class InlineIndexHelperTest extends GridCommonAbstractTest {
 
             int off = 0;
 
-            InlineIndexHelper ih = new InlineIndexHelper(Value.STRING, 1, 0,
+            InlineIndexHelper ih = new InlineIndexHelper("", Value.STRING, 1, 0,
                 CompareMode.getInstance(null, 0));
 
             ih.put(pageAddr, off, ValueString.get("aaaaaaa"), 3 + 5);
@@ -374,7 +376,7 @@ public class InlineIndexHelperTest extends GridCommonAbstractTest {
 
             int off = 0;
 
-            InlineIndexHelper ih = new InlineIndexHelper(Value.BYTES, 1, 0,
+            InlineIndexHelper ih = new InlineIndexHelper("", Value.BYTES, 1, 0,
                 CompareMode.getInstance(null, 0));
 
             int maxSize = 3 + 3;
@@ -432,7 +434,7 @@ public class InlineIndexHelperTest extends GridCommonAbstractTest {
 
             int off = 0;
 
-            InlineIndexHelper ih = new InlineIndexHelper(Value.JAVA_OBJECT, 1, 0,
+            InlineIndexHelper ih = new InlineIndexHelper("", Value.JAVA_OBJECT, 1, 0,
                 CompareMode.getInstance(null, 0));
 
             int maxSize = 3 + 3;
@@ -563,7 +565,7 @@ public class InlineIndexHelperTest extends GridCommonAbstractTest {
             int off = 0;
             int max = 255;
 
-            InlineIndexHelper ih = new InlineIndexHelper(v1.getType(), 1, 0,
+            InlineIndexHelper ih = new InlineIndexHelper("", v1.getType(), 1, 0,
                 CompareMode.getInstance(null, 0));
 
             off += ih.put(pageAddr, off, v1, max - off);