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 2019/01/30 08:08:54 UTC

[ignite] branch master updated: IGNITE-10985: SQL: Avoid GridCacheVersion deserialization. This closes #5968.

This is an automated email from the ASF dual-hosted git repository.

vozerov pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ignite.git


The following commit(s) were added to refs/heads/master by this push:
     new d0d6c98  IGNITE-10985: SQL: Avoid GridCacheVersion deserialization. This closes #5968.
d0d6c98 is described below

commit d0d6c98ebdd278fc5f2b41dcab35ad2028e8666e
Author: devozerov <vo...@gridgain.com>
AuthorDate: Wed Jan 30 11:08:41 2019 +0300

    IGNITE-10985: SQL: Avoid GridCacheVersion deserialization. This closes #5968.
---
 .../dht/GridDhtTxAbstractEnlistFuture.java         |   4 +-
 .../cache/persistence/CacheDataRowAdapter.java     | 130 ++++++++++++++++-----
 .../evict/PageAbstractEvictionTracker.java         |   2 +-
 .../cache/persistence/tree/io/CacheVersionIO.java  |  25 ++++
 .../processors/cache/tree/CacheDataRowStore.java   |  46 +++++++-
 .../processors/cache/tree/CacheDataTree.java       |  15 ++-
 .../internal/processors/cache/tree/DataRow.java    |   8 +-
 .../cache/tree/mvcc/data/MvccDataRow.java          |   9 +-
 .../query/h2/database/H2PkHashIndex.java           |  11 ++
 .../processors/query/h2/database/H2RowFactory.java |  37 +++---
 10 files changed, 230 insertions(+), 57 deletions(-)

diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxAbstractEnlistFuture.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxAbstractEnlistFuture.java
index 3f53b48..138e24d 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxAbstractEnlistFuture.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxAbstractEnlistFuture.java
@@ -732,7 +732,9 @@ public abstract class GridDhtTxAbstractEnlistFuture<T> extends GridCacheFutureAd
                 CacheDataRowAdapter.RowData.NO_KEY,
                 row0.mvccCoordinatorVersion(),
                 row0.mvccCounter(),
-                row0.mvccOperationCounter());
+                row0.mvccOperationCounter(),
+                false
+            );
 
             GridCacheMvccEntryInfo entry = new GridCacheMvccEntryInfo();
 
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/CacheDataRowAdapter.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/CacheDataRowAdapter.java
index 1889a99..c9d006f 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/CacheDataRowAdapter.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/CacheDataRowAdapter.java
@@ -75,6 +75,9 @@ public class CacheDataRowAdapter implements CacheDataRow {
     @GridToStringInclude
     protected GridCacheVersion ver;
 
+    /** Whether version is ready. */
+    protected boolean verReady;
+
     /** */
     @GridToStringInclude
     protected int cacheId;
@@ -98,6 +101,8 @@ public class CacheDataRowAdapter implements CacheDataRow {
         this.val = val;
         this.ver = ver;
         this.expireTime = expireTime;
+
+        verReady = true;
     }
 
     /**
@@ -108,7 +113,21 @@ public class CacheDataRowAdapter implements CacheDataRow {
      * @throws IgniteCheckedException If failed.
      */
     public final void initFromLink(CacheGroupContext grp, RowData rowData) throws IgniteCheckedException {
-        initFromLink(grp, grp.shared(), grp.dataRegion().pageMemory(), rowData);
+        initFromLink(grp, rowData, false);
+    }
+
+
+    /**
+     * Read row from data pages.
+     *
+     * @param grp Cache group.
+     * @param rowData Required row data.
+     * @param skipVer Whether version read should be skipped.
+     * @throws IgniteCheckedException If failed.
+     */
+    public final void initFromLink(CacheGroupContext grp, RowData rowData, boolean skipVer)
+        throws IgniteCheckedException {
+        initFromLink(grp, grp.shared(), grp.dataRegion().pageMemory(), rowData, skipVer);
     }
 
     /**
@@ -119,13 +138,15 @@ public class CacheDataRowAdapter implements CacheDataRow {
      * @param sharedCtx Shared context.
      * @param pageMem Page memory.
      * @param rowData Row data.
+     * @param skipVer Whether version read should be skipped.
      * @throws IgniteCheckedException If failed.
      */
     public final void initFromLink(
         @Nullable CacheGroupContext grp,
         GridCacheSharedContext<?, ?> sharedCtx,
         PageMemory pageMem,
-        RowData rowData
+        RowData rowData,
+        boolean skipVer
     ) throws IgniteCheckedException {
         // Group is null if try evict page, with persistence evictions should be disabled.
         assert grp != null || pageMem instanceof PageMemoryNoStoreImpl;
@@ -135,7 +156,7 @@ public class CacheDataRowAdapter implements CacheDataRow {
         int grpId = grp != null ? grp.groupId() : 0;
         IoStatisticsHolder statHolder = grp != null ? grp.statisticsHolderData() : IoStatisticsHolderNoOp.INSTANCE;
 
-        doInitFromLink(link, sharedCtx, coctx, pageMem, grpId, statHolder, readCacheId, rowData, null);
+        doInitFromLink(link, sharedCtx, coctx, pageMem, grpId, statHolder, readCacheId, rowData, null, skipVer);
     }
 
     /**
@@ -146,6 +167,7 @@ public class CacheDataRowAdapter implements CacheDataRow {
      * @param sharedCtx Cache shared context.
      * @param pageMem Page memory.
      * @param rowData Required row data.
+     * @param skipVer Whether version read should be skipped.
      * @throws IgniteCheckedException If failed.
      */
     public final void initFromDataPage(
@@ -155,7 +177,8 @@ public class CacheDataRowAdapter implements CacheDataRow {
         @Nullable CacheGroupContext grp,
         GridCacheSharedContext<?, ?> sharedCtx,
         PageMemory pageMem,
-        RowData rowData
+        RowData rowData,
+        boolean skipVer
     ) throws IgniteCheckedException {
         // Group is null if try evict page, with persistence evictions should be disabled.
         assert grp != null || pageMem instanceof PageMemoryNoStoreImpl;
@@ -166,14 +189,26 @@ public class CacheDataRowAdapter implements CacheDataRow {
         IoStatisticsHolder statHolder = grp != null ? grp.statisticsHolderData() : IoStatisticsHolderNoOp.INSTANCE;
 
         IncompleteObject<?> incomplete = readIncomplete(null, sharedCtx, coctx, pageMem,
-            grpId, pageAddr, itemId, io, rowData, readCacheId);
+            grpId, pageAddr, itemId, io, rowData, readCacheId, skipVer);
 
         if (incomplete != null) {
             // Initialize the remaining part of the large row from other pages.
             long nextLink = incomplete.getNextLink();
 
-            if (nextLink != 0L)
-                doInitFromLink(nextLink, sharedCtx, coctx, pageMem, grpId, statHolder, readCacheId, rowData, incomplete);
+            if (nextLink != 0L) {
+                doInitFromLink(
+                    nextLink,
+                    sharedCtx,
+                    coctx,
+                    pageMem,
+                    grpId,
+                    statHolder,
+                    readCacheId,
+                    rowData,
+                    incomplete,
+                    skipVer
+                );
+            }
         }
     }
 
@@ -186,6 +221,7 @@ public class CacheDataRowAdapter implements CacheDataRow {
      * @param readCacheId {@code true} If need to read cache ID.
      * @param rowData Required row data.
      * @param incomplete Incomplete object.
+     * @param skipVer Whether version read should be skipped.
      * @throws IgniteCheckedException If failed.
      */
     private void doInitFromLink(
@@ -197,7 +233,8 @@ public class CacheDataRowAdapter implements CacheDataRow {
         IoStatisticsHolder statHolder,
         boolean readCacheId,
         RowData rowData,
-        IncompleteObject<?> incomplete
+        IncompleteObject<?> incomplete,
+        boolean skipVer
     ) throws IgniteCheckedException {
         assert link != 0 : "link";
         assert key == null : "key";
@@ -220,7 +257,7 @@ public class CacheDataRowAdapter implements CacheDataRow {
                     int itemId = itemId(nextLink);
 
                     incomplete = readIncomplete(incomplete, sharedCtx, coctx, pageMem,
-                        grpId, pageAddr, itemId, io, rowData, readCacheId);
+                        grpId, pageAddr, itemId, io, rowData, readCacheId, skipVer);
 
                     if (incomplete == null || (rowData == KEY_ONLY && key != null))
                         return;
@@ -235,7 +272,7 @@ public class CacheDataRowAdapter implements CacheDataRow {
                 pageMem.releasePage(grpId, pageId, page);
             }
         }
-        while(nextLink != 0);
+        while (nextLink != 0);
 
         assert isReady() : "ready";
     }
@@ -250,6 +287,7 @@ public class CacheDataRowAdapter implements CacheDataRow {
      * @param io Page IO.
      * @param rowData Required row data.
      * @param readCacheId {@code true} If need to read cache ID.
+     * @param skipVer Whether version read should be skipped.
      * @return Incomplete object.
      * @throws IgniteCheckedException If failed.
      */
@@ -263,7 +301,8 @@ public class CacheDataRowAdapter implements CacheDataRow {
         int itemId,
         DataPageIO io,
         RowData rowData,
-        boolean readCacheId
+        boolean readCacheId,
+        boolean skipVer
     ) throws IgniteCheckedException {
         DataPagePayload data = io.readPayload(pageAddr, itemId, pageMem.realPageSize(grpId));
 
@@ -274,7 +313,7 @@ public class CacheDataRowAdapter implements CacheDataRow {
         if (incomplete == null) {
             if (nextLink == 0) {
                 // Fast path for a single page row.
-                readFullRow(sharedCtx, coctx, pageAddr + data.offset(), rowData, readCacheId);
+                readFullRow(sharedCtx, coctx, pageAddr + data.offset(), rowData, readCacheId, skipVer);
 
                 return null;
             }
@@ -296,7 +335,7 @@ public class CacheDataRowAdapter implements CacheDataRow {
 
         boolean keyOnly = rowData == RowData.KEY_ONLY;
 
-        incomplete = readFragment(sharedCtx, coctx, buf, keyOnly, readCacheId, incomplete);
+        incomplete = readFragment(sharedCtx, coctx, buf, keyOnly, readCacheId, incomplete, skipVer);
 
         if (incomplete != null)
             incomplete.setNextLink(nextLink);
@@ -323,6 +362,7 @@ public class CacheDataRowAdapter implements CacheDataRow {
      * @param keyOnly {@code true} If need to read only key object.
      * @param readCacheId {@code true} If need to read cache ID.
      * @param incomplete Incomplete object.
+     * @param skipVer Whether version read should be skipped.
      * @throws IgniteCheckedException If failed.
      * @return Read object.
      */
@@ -332,7 +372,8 @@ public class CacheDataRowAdapter implements CacheDataRow {
         ByteBuffer buf,
         boolean keyOnly,
         boolean readCacheId,
-        IncompleteObject<?> incomplete
+        IncompleteObject<?> incomplete,
+        boolean skipVer
     ) throws IgniteCheckedException {
         if (readCacheId && cacheId == 0) {
             incomplete = readIncompleteCacheId(buf, incomplete);
@@ -392,10 +433,10 @@ public class CacheDataRowAdapter implements CacheDataRow {
         }
 
         // Read version.
-        if (ver == null) {
-            incomplete = readIncompleteVersion(buf, incomplete);
+        if (!verReady) {
+            incomplete = readIncompleteVersion(buf, incomplete, skipVer);
 
-            assert ver != null || incomplete != null;
+            assert skipVer || ver != null || incomplete != null;
         }
 
         return incomplete;
@@ -407,6 +448,7 @@ public class CacheDataRowAdapter implements CacheDataRow {
      * @param addr Address.
      * @param rowData Required row data.
      * @param readCacheId {@code true} If need to read cache ID.
+     * @param skipVer Whether version read should be skipped.
      * @throws IgniteCheckedException If failed.
      */
     protected void readFullRow(
@@ -414,8 +456,9 @@ public class CacheDataRowAdapter implements CacheDataRow {
         CacheObjectContext coctx,
         long addr,
         RowData rowData,
-        boolean readCacheId)
-        throws IgniteCheckedException {
+        boolean readCacheId,
+        boolean skipVer
+    ) throws IgniteCheckedException {
         int off = 0;
 
         off += readHeader(addr, off);
@@ -461,9 +504,22 @@ public class CacheDataRowAdapter implements CacheDataRow {
 
         val = coctx.kernalContext().cacheObjects().toCacheObject(coctx, type, bytes);
 
-        ver = CacheVersionIO.read(addr + off, false);
+        int verLen;
+
+        if (skipVer) {
+            ver = null;
+
+            verLen = CacheVersionIO.readSize(addr + off, false);
+        }
+        else {
+            ver = CacheVersionIO.read(addr + off, false);
+
+            verLen = CacheVersionIO.size(ver, false);
+        }
 
-        off += CacheVersionIO.size(ver, false);
+        verReady = true;
+
+        off += verLen;
 
         expireTime = PageUtils.getLong(addr, off);
     }
@@ -604,12 +660,14 @@ public class CacheDataRowAdapter implements CacheDataRow {
     /**
      * @param buf Buffer.
      * @param incomplete Incomplete object.
+     * @param skip Whether version should be skipped.
      * @return Incomplete object.
      * @throws IgniteCheckedException If failed.
      */
     protected IncompleteObject<?> readIncompleteVersion(
         ByteBuffer buf,
-        IncompleteObject<?> incomplete
+        IncompleteObject<?> incomplete,
+        boolean skip
     ) throws IgniteCheckedException {
         if (incomplete == null || incomplete.data() == null) {
             int remaining = buf.remaining();
@@ -621,10 +679,16 @@ public class CacheDataRowAdapter implements CacheDataRow {
 
             if (remaining >= size) {
                 // If the whole version is on a single page, just read it.
-                ver = CacheVersionIO.read(buf, false);
+                if (skip)
+                    buf.position(buf.position() + size);
+                else {
+                    ver = CacheVersionIO.read(buf, false);
 
-                assert !buf.hasRemaining(): buf.remaining();
-                assert ver != null;
+                    assert !buf.hasRemaining(): buf.remaining();
+                    assert ver != null;
+                }
+
+                verReady = true;
 
                 return null;
             }
@@ -636,13 +700,17 @@ public class CacheDataRowAdapter implements CacheDataRow {
         incomplete.readData(buf);
 
         if (incomplete.isReady()) {
-            final ByteBuffer verBuf = ByteBuffer.wrap(incomplete.data());
+            if (!skip) {
+                ByteBuffer verBuf = ByteBuffer.wrap(incomplete.data());
+
+                verBuf.order(buf.order());
 
-            verBuf.order(buf.order());
+                ver = CacheVersionIO.read(verBuf, false);
 
-            ver = CacheVersionIO.read(verBuf, false);
+                assert ver != null;
+            }
 
-            assert ver != null;
+            verReady = true;
         }
 
         assert !buf.hasRemaining();
@@ -654,7 +722,7 @@ public class CacheDataRowAdapter implements CacheDataRow {
      * @return {@code True} if entry is ready.
      */
     public boolean isReady() {
-        return ver != null && val != null && key != null;
+        return verReady && val != null && key != null;
     }
 
     /** {@inheritDoc} */
@@ -687,7 +755,7 @@ public class CacheDataRowAdapter implements CacheDataRow {
 
     /** {@inheritDoc} */
     @Override public GridCacheVersion version() {
-        assert ver != null : "Version is not ready: " + this;
+        assert verReady : "Version is not ready: " + this;
 
         return ver;
     }
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/evict/PageAbstractEvictionTracker.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/evict/PageAbstractEvictionTracker.java
index 5142c59..41731b1 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/evict/PageAbstractEvictionTracker.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/evict/PageAbstractEvictionTracker.java
@@ -102,7 +102,7 @@ public abstract class PageAbstractEvictionTracker implements PageEvictionTracker
                     @Override public CacheDataRowAdapter apply(long link) throws IgniteCheckedException {
                         CacheDataRowAdapter row = new CacheDataRowAdapter(link);
 
-                        row.initFromLink(null, sharedCtx, pageMem, CacheDataRowAdapter.RowData.KEY_ONLY);
+                        row.initFromLink(null, sharedCtx, pageMem, CacheDataRowAdapter.RowData.KEY_ONLY, false);
 
                         assert row.cacheId() != 0 : "Cache ID should be stored in rows of evictable cache";
 
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/io/CacheVersionIO.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/io/CacheVersionIO.java
index d9fdf0e..fd7f2f5 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/io/CacheVersionIO.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/io/CacheVersionIO.java
@@ -155,6 +155,31 @@ public class CacheVersionIO {
     public static int readSize(ByteBuffer buf, boolean allowNull) throws IgniteCheckedException {
         byte protoVer = checkProtocolVersion(buf.get(buf.position()), allowNull);
 
+        return sizeForVersion(protoVer);
+    }
+
+    /**
+     * Gets needed buffer size to read the whole version instance.
+     * Does not change buffer position.
+     *
+     * @param pageAddr Page address.
+     * @param allowNull Is {@code null} version allowed.
+     * @return Size of serialized version.
+     * @throws IgniteCheckedException If failed.
+     */
+    public static int readSize(long pageAddr, boolean allowNull) throws IgniteCheckedException {
+        byte protoVer = checkProtocolVersion(PageUtils.getByte(pageAddr, 0), allowNull);
+
+        return sizeForVersion(protoVer);
+    }
+
+    /**
+     * Get size for protocol version.
+     *
+     * @param protoVer Protocol version.
+     * @return Size.
+     */
+    private static int sizeForVersion(int protoVer) {
         switch (protoVer) {
             case NULL_PROTO_VER:
                 return NULL_SIZE;
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/tree/CacheDataRowStore.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/tree/CacheDataRowStore.java
index 7aa7068..0c460ee 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/tree/CacheDataRowStore.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/tree/CacheDataRowStore.java
@@ -30,6 +30,23 @@ import org.apache.ignite.internal.util.typedef.internal.CU;
  *
  */
 public class CacheDataRowStore extends RowStore {
+    /** Whether version should be skipped. */
+    private static ThreadLocal<Boolean> SKIP_VER = ThreadLocal.withInitial(() -> false);
+
+    /**
+     * @return Skip version flag.
+     */
+    public static boolean getSkipVersion() {
+        return SKIP_VER.get();
+    }
+
+    /**
+     * @param skipVer Skip version flag.
+     */
+    public static void setSkipVersion(boolean skipVer) {
+        SKIP_VER.set(skipVer);
+    }
+
     /** */
     private final int partId;
 
@@ -62,7 +79,16 @@ public class CacheDataRowStore extends RowStore {
      * @return Search row.
      */
     CacheSearchRow keySearchRow(int cacheId, int hash, long link) {
-        return initDataRow(new DataRow(grp, hash, link, partId, CacheDataRowAdapter.RowData.KEY_ONLY), cacheId);
+        DataRow dataRow = new DataRow(
+            grp,
+            hash,
+            link,
+            partId,
+            CacheDataRowAdapter.RowData.KEY_ONLY,
+            SKIP_VER.get()
+        );
+
+        return initDataRow(dataRow, cacheId);
     }
 
     /**
@@ -76,14 +102,17 @@ public class CacheDataRowStore extends RowStore {
      * @return Search row.
      */
     MvccDataRow mvccRow(int cacheId, int hash, long link, CacheDataRowAdapter.RowData rowData, long crdVer, long mvccCntr, int opCntr) {
-        MvccDataRow dataRow = new MvccDataRow(grp,
+        MvccDataRow dataRow = new MvccDataRow(
+            grp,
             hash,
             link,
             partId,
             rowData,
             crdVer,
             mvccCntr,
-            opCntr);
+            opCntr,
+            SKIP_VER.get()
+        );
 
         return initDataRow(dataRow, cacheId);
     }
@@ -96,7 +125,16 @@ public class CacheDataRowStore extends RowStore {
      * @return Data row.
      */
     CacheDataRow dataRow(int cacheId, int hash, long link, CacheDataRowAdapter.RowData rowData) {
-        return initDataRow(new DataRow(grp, hash, link, partId, rowData), cacheId);
+        DataRow dataRow = new DataRow(
+            grp,
+            hash,
+            link,
+            partId,
+            rowData,
+            SKIP_VER.get()
+        );
+
+        return initDataRow(dataRow, cacheId);
     }
 
     /**
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/tree/CacheDataTree.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/tree/CacheDataTree.java
index 4d01494..71c8a86 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/tree/CacheDataTree.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/tree/CacheDataTree.java
@@ -223,6 +223,8 @@ public class CacheDataTree extends BPlusTree<CacheSearchRow, CacheDataRow> {
                     long page = pageMem.acquirePage(grpId, pageId);
 
                     try {
+                        boolean skipVer = CacheDataRowStore.getSkipVersion();
+
                         long pageAddr = ((PageMemoryEx)pageMem).readLock(page, pageId, true, false);
 
                         try {
@@ -246,7 +248,18 @@ public class CacheDataTree extends BPlusTree<CacheSearchRow, CacheDataRow> {
                             for (int i = 0; i < rowsCnt; i++) {
                                 if (c == null || c.applyMvcc(io, pageAddr, i, pageSize)) {
                                     DataRow row = mvccEnabled ? new MvccDataRow() : new DataRow();
-                                    row.initFromDataPage(io, pageAddr, i, grp, shared, pageMem, rowData);
+
+                                    row.initFromDataPage(
+                                        io,
+                                        pageAddr,
+                                        i,
+                                        grp,
+                                        shared,
+                                        pageMem,
+                                        rowData,
+                                        skipVer
+                                    );
+
                                     rows[r++] = row;
                                 }
                             }
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/tree/DataRow.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/tree/DataRow.java
index ca6061b..add2abe 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/tree/DataRow.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/tree/DataRow.java
@@ -41,18 +41,18 @@ public class DataRow extends CacheDataRowAdapter {
      * @param link Link.
      * @param part Partition.
      * @param rowData Required row data.
+     * @param skipVer Whether version read should be skipped.
      */
-    protected DataRow(CacheGroupContext grp, int hash, long link, int part, RowData rowData) {
+    protected DataRow(CacheGroupContext grp, int hash, long link, int part, RowData rowData, boolean skipVer) {
         super(link);
 
         this.hash = hash;
-
         this.part = part;
 
         try {
             // We can not init data row lazily outside of entry lock because underlying buffer can be concurrently cleared.
             if (rowData != RowData.LINK_ONLY)
-                initFromLink(grp, rowData);
+                initFromLink(grp, rowData, skipVer);
         }
         catch (IgniteCheckedException e) {
             throw new IgniteException(e);
@@ -80,6 +80,8 @@ public class DataRow extends CacheDataRowAdapter {
         this.part = part;
         this.expireTime = expireTime;
         this.cacheId = cacheId;
+
+        verReady = true;
     }
 
     /**
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/tree/mvcc/data/MvccDataRow.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/tree/mvcc/data/MvccDataRow.java
index cb4bc87..a3ee923 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/tree/mvcc/data/MvccDataRow.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/tree/mvcc/data/MvccDataRow.java
@@ -92,17 +92,20 @@ public class MvccDataRow extends DataRow {
      * @param crdVer Mvcc coordinator version.
      * @param mvccCntr Mvcc counter.
      * @param mvccOpCntr Mvcc operation counter.
+     * @param skipVer Skip version flag.
      */
-    public MvccDataRow(CacheGroupContext grp,
+    public MvccDataRow(
+        CacheGroupContext grp,
         int hash,
         long link,
         int part,
         RowData rowData,
         long crdVer,
         long mvccCntr,
-        int mvccOpCntr
+        int mvccOpCntr,
+        boolean skipVer
     ) {
-        super(grp, hash, link, part, rowData);
+        super(grp, hash, link, part, rowData, skipVer);
 
         assert MvccUtils.mvccVersionIsValid(crdVer, mvccCntr, mvccOpCntr);
 
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2PkHashIndex.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2PkHashIndex.java
index 1add933..6aa9ebf 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2PkHashIndex.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2PkHashIndex.java
@@ -29,6 +29,7 @@ import org.apache.ignite.internal.processors.cache.IgniteCacheOffheapManager;
 import org.apache.ignite.internal.processors.cache.KeyCacheObject;
 import org.apache.ignite.internal.processors.cache.mvcc.MvccSnapshot;
 import org.apache.ignite.internal.processors.cache.persistence.CacheDataRow;
+import org.apache.ignite.internal.processors.cache.tree.CacheDataRowStore;
 import org.apache.ignite.internal.processors.query.GridQueryTypeDescriptor;
 import org.apache.ignite.internal.processors.query.h2.opt.GridH2IndexBase;
 import org.apache.ignite.internal.processors.query.h2.opt.GridH2QueryContext;
@@ -117,6 +118,8 @@ public class H2PkHashIndex extends GridH2IndexBase {
         KeyCacheObject upperObj = upper != null ? cctx.toCacheKeyObject(upper.getValue(0).getObject()) : null;
 
         try {
+            CacheDataRowStore.setSkipVersion(true);
+
             Collection<GridCursor<? extends CacheDataRow>> cursors = new ArrayList<>();
 
             for (IgniteCacheOffheapManager.CacheDataStore store : cctx.offheap().cacheDataStores()) {
@@ -134,6 +137,9 @@ public class H2PkHashIndex extends GridH2IndexBase {
         catch (IgniteCheckedException e) {
             throw DbException.convert(e);
         }
+        finally {
+            CacheDataRowStore.setSkipVersion(false);
+        }
     }
 
     /** {@inheritDoc} */
@@ -248,6 +254,8 @@ public class H2PkHashIndex extends GridH2IndexBase {
         /** {@inheritDoc} */
         @Override public boolean next() {
             try {
+                CacheDataRowStore.setSkipVersion(true);
+
                 GridQueryTypeDescriptor type = desc.type();
 
                 for (;;) {
@@ -269,6 +277,9 @@ public class H2PkHashIndex extends GridH2IndexBase {
             catch (IgniteCheckedException e) {
                 throw DbException.convert(e);
             }
+            finally {
+                CacheDataRowStore.setSkipVersion(false);
+            }
         }
 
         /** {@inheritDoc} */
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2RowFactory.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2RowFactory.java
index 724de7e..fb7ff0b 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2RowFactory.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2RowFactory.java
@@ -54,18 +54,15 @@ public class H2RowFactory {
      * @throws IgniteCheckedException If failed.
      */
     public GridH2Row getRow(long link) throws IgniteCheckedException {
-        // TODO Avoid extra garbage generation. In upcoming H2 1.4.193 Row will become an interface,
-        // TODO we need to refactor all this to return CacheDataRowAdapter implementing Row here.
+        CacheDataRowAdapter row = new CacheDataRowAdapter(link);
 
-        final CacheDataRowAdapter rowBuilder = new CacheDataRowAdapter(link);
+        row.initFromLink(
+            cctx.group(),
+            CacheDataRowAdapter.RowData.FULL,
+            true
+        );
 
-        rowBuilder.initFromLink(cctx.group(), CacheDataRowAdapter.RowData.FULL);
-
-        GridH2Row row = rowDesc.createRow(rowBuilder);
-
-        assert row.version() != null;
-
-        return row;
+        return rowDesc.createRow(row);
     }
 
     /**
@@ -76,8 +73,22 @@ public class H2RowFactory {
      * @return Row.
      * @throws IgniteCheckedException If failed.
      */
-    public GridH2Row getMvccRow(long link, long mvccCrdVer, long mvccCntr, int mvccOpCntr) throws IgniteCheckedException {
-        return rowDesc.createRow(new MvccDataRow(cctx.group(),0, link,
-            PageIdUtils.partId(PageIdUtils.pageId(link)),null, mvccCrdVer, mvccCntr, mvccOpCntr));
+    public GridH2Row getMvccRow(long link, long mvccCrdVer, long mvccCntr, int mvccOpCntr)
+        throws IgniteCheckedException {
+        int partId = PageIdUtils.partId(PageIdUtils.pageId(link));
+
+        MvccDataRow row = new MvccDataRow(
+            cctx.group(),
+            0,
+            link,
+            partId,
+            null,
+            mvccCrdVer,
+            mvccCntr,
+            mvccOpCntr,
+            true
+        );
+
+        return rowDesc.createRow(row);
     }
 }