http://git-wip-us.apache.org/repos/asf/ignite/blob/6150f3a0/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/mvcc/CacheMvccTransactionsTest.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/mvcc/CacheMvccTransactionsTest.java
 
b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/mvcc/CacheMvccTransactionsTest.java
index dbe4ce5..df9f21e 100644
--- 
a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/mvcc/CacheMvccTransactionsTest.java
+++ 
b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/mvcc/CacheMvccTransactionsTest.java
@@ -36,26 +36,24 @@ import java.util.concurrent.ThreadLocalRandom;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.locks.ReadWriteLock;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
+import javax.cache.expiry.Duration;
+import javax.cache.expiry.TouchedExpiryPolicy;
 import org.apache.ignite.Ignite;
 import org.apache.ignite.IgniteCache;
 import org.apache.ignite.IgniteCheckedException;
 import org.apache.ignite.IgniteDataStreamer;
 import org.apache.ignite.IgniteException;
 import org.apache.ignite.IgniteTransactions;
-import org.apache.ignite.cache.CacheMode;
-import org.apache.ignite.cache.CacheWriteSynchronizationMode;
 import org.apache.ignite.cache.affinity.rendezvous.RendezvousAffinityFunction;
 import org.apache.ignite.cluster.ClusterNode;
 import org.apache.ignite.cluster.ClusterTopologyException;
 import org.apache.ignite.configuration.CacheConfiguration;
-import org.apache.ignite.configuration.IgniteConfiguration;
-import org.apache.ignite.configuration.MemoryConfiguration;
+import org.apache.ignite.internal.IgniteEx;
 import org.apache.ignite.internal.IgniteInternalFuture;
 import org.apache.ignite.internal.IgniteKernal;
 import org.apache.ignite.internal.TestRecordingCommunicationSpi;
 import org.apache.ignite.internal.processors.cache.GridCacheContext;
+import org.apache.ignite.internal.processors.cache.GridCacheMapEntry;
 import org.apache.ignite.internal.processors.cache.KeyCacheObject;
 import 
org.apache.ignite.internal.processors.cache.distributed.TestCacheNodeExcludingFilter;
 import 
org.apache.ignite.internal.processors.cache.distributed.near.GridNearGetRequest;
@@ -275,6 +273,13 @@ public class CacheMvccTransactionsTest extends 
CacheMvccAbstractTest {
     /**
      * @throws Exception If failed.
      */
+    public void testCacheRecreate() throws Exception {
+        cacheRecreate(null);
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
     public void testActiveQueriesCleanup() throws Exception {
         activeQueriesCleanup(false);
     }
@@ -3626,6 +3631,67 @@ public class CacheMvccTransactionsTest extends 
CacheMvccAbstractTest {
                     checkRow(cctx, row, key0, vers.get(v + 1).get1());
             }
         }
+
+        KeyCacheObject key = cctx.toCacheKeyObject(KEYS);
+
+        cache.put(key, 0);
+
+        cache.remove(key);
+
+        
cctx.offheap().mvccRemoveAll((GridCacheMapEntry)cctx.cache().entryEx(key));
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testExpiration() throws Exception {
+        final IgniteEx node = startGrid(0);
+
+        IgniteCache cache = node.createCache(cacheConfiguration(PARTITIONED, 
FULL_SYNC, 1, 64));
+
+        final IgniteCache expiryCache =
+            cache.withExpiryPolicy(new TouchedExpiryPolicy(new 
Duration(TimeUnit.SECONDS, 1)));
+
+        for (int i = 0; i < 10; i++)
+            expiryCache.put(1, i);
+
+        assertTrue("Failed to wait for expiration", 
GridTestUtils.waitForCondition(new GridAbsPredicate() {
+            @Override public boolean apply() {
+                return expiryCache.localPeek(1) == null;
+            }
+        }, 5000));
+
+        for (int i = 0; i < 11; i++) {
+            if (i % 2 == 0)
+                expiryCache.put(1, i);
+            else
+                expiryCache.remove(1);
+        }
+
+        assertTrue("Failed to wait for expiration", 
GridTestUtils.waitForCondition(new GridAbsPredicate() {
+            @Override public boolean apply() {
+                return expiryCache.localPeek(1) == null;
+            }
+        }, 5000));
+
+        expiryCache.put(1, 1);
+
+        assertTrue("Failed to wait for expiration", 
GridTestUtils.waitForCondition(new GridAbsPredicate() {
+            @Override public boolean apply() {
+                try {
+                    GridCacheContext cctx = 
node.context().cache().context().cacheContext(CU.cacheId(DEFAULT_CACHE_NAME));
+
+                    KeyCacheObject key = cctx.toCacheKeyObject(1);
+
+                    return cctx.offheap().read(cctx, key) == null;
+                }
+                catch (Exception e) {
+                    fail();
+
+                    return false;
+                }
+            }
+        }, 5000));
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/ignite/blob/6150f3a0/modules/core/src/test/java/org/apache/ignite/internal/processors/database/BPlusTreeSelfTest.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/test/java/org/apache/ignite/internal/processors/database/BPlusTreeSelfTest.java
 
b/modules/core/src/test/java/org/apache/ignite/internal/processors/database/BPlusTreeSelfTest.java
index 27804d9..335279f 100644
--- 
a/modules/core/src/test/java/org/apache/ignite/internal/processors/database/BPlusTreeSelfTest.java
+++ 
b/modules/core/src/test/java/org/apache/ignite/internal/processors/database/BPlusTreeSelfTest.java
@@ -18,11 +18,14 @@
 package org.apache.ignite.internal.processors.database;
 
 import java.util.Collection;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Map;
 import java.util.Random;
+import java.util.Set;
 import java.util.TreeMap;
+import java.util.TreeSet;
 import java.util.concurrent.Callable;
 import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.ThreadLocalRandom;
@@ -218,6 +221,53 @@ public class BPlusTreeSelfTest extends 
GridCommonAbstractTest {
     /**
      * @throws IgniteCheckedException If failed.
      */
+    public void testFindWithClosure() throws IgniteCheckedException {
+        TestTree tree = createTestTree(true);
+        TreeMap<Long, Long> map = new TreeMap<>();
+
+        long size = CNT * CNT;
+
+        for (long i = 1; i <= size; i++) {
+            tree.put(i);
+            map.put(i, i);
+        }
+
+        checkCursor(tree.find(null, null, new 
TestTreeFindFilteredClosure(Collections.<Long>emptySet()), null),
+            Collections.<Long>emptyList().iterator());
+
+        checkCursor(tree.find(null, null, new 
TestTreeFindFilteredClosure(map.keySet()), null),
+            map.values().iterator());
+
+        ThreadLocalRandom rnd = ThreadLocalRandom.current();
+
+        for (int i = 0; i < 100; i++) {
+            Long val = rnd.nextLong(size) + 1;
+
+            checkCursor(tree.find(null, null, new 
TestTreeFindFilteredClosure(Collections.singleton(val)), null),
+                Collections.singleton(val).iterator());
+        }
+
+        for (int i = 0; i < 200; i++) {
+            long vals = rnd.nextLong(size) + 1;
+
+            TreeSet<Long> exp = new TreeSet<>();
+
+            for (long k = 0; k < vals; k++)
+                exp.add(rnd.nextLong(size) + 1);
+
+            checkCursor(tree.find(null, null, new 
TestTreeFindFilteredClosure(exp), null), exp.iterator());
+
+            checkCursor(tree.find(0L, null, new 
TestTreeFindFilteredClosure(exp), null), exp.iterator());
+
+            checkCursor(tree.find(0L, size, new 
TestTreeFindFilteredClosure(exp), null), exp.iterator());
+
+            checkCursor(tree.find(null, size, new 
TestTreeFindFilteredClosure(exp), null), exp.iterator());
+        }
+    }
+
+    /**
+     * @throws IgniteCheckedException If failed.
+     */
     public void _testBenchInvoke() throws IgniteCheckedException {
         MAX_PER_PAGE = 10;
 
@@ -625,12 +675,12 @@ public class BPlusTreeSelfTest extends 
GridCommonAbstractTest {
     }
 
     /**
-     * @param tree
-     * @param lower
-     * @param upper
-     * @param exp
-     * @param expFound
-     * @throws IgniteCheckedException
+     * @param tree Tree.
+     * @param lower Lower bound.
+     * @param upper Upper bound.
+     * @param exp Value to find.
+     * @param expFound {@code True} if value should be found.
+     * @throws IgniteCheckedException If failed.
      */
     private void checkIterate(TestTree tree, long lower, long upper, Long exp, 
boolean expFound)
         throws IgniteCheckedException {
@@ -641,6 +691,14 @@ public class BPlusTreeSelfTest extends 
GridCommonAbstractTest {
         assertEquals(expFound, c.found);
     }
 
+    /**
+     * @param tree Tree.
+     * @param lower Lower bound.
+     * @param upper Upper bound.
+     * @param c Closure.
+     * @param expFound {@code True} if value should be found.
+     * @throws IgniteCheckedException If failed.
+     */
     private void checkIterateC(TestTree tree, long lower, long upper, 
TestTreeRowClosure c, boolean expFound)
         throws IgniteCheckedException {
         c.found = false;
@@ -1307,7 +1365,7 @@ public class BPlusTreeSelfTest extends 
GridCommonAbstractTest {
      * @throws Exception If failed.
      */
     public void testIterateConcurrentPutRemove() throws Exception {
-        findOneBoundedConcurrentPutRemove();
+        iterateConcurrentPutRemove();
     }
 
     /**
@@ -1316,7 +1374,7 @@ public class BPlusTreeSelfTest extends 
GridCommonAbstractTest {
     public void testIterateConcurrentPutRemove_1() throws Exception {
         MAX_PER_PAGE = 1;
 
-        findOneBoundedConcurrentPutRemove();
+        iterateConcurrentPutRemove();
     }
 
     /**
@@ -1325,7 +1383,7 @@ public class BPlusTreeSelfTest extends 
GridCommonAbstractTest {
     public void testIterateConcurrentPutRemove_5() throws Exception {
         MAX_PER_PAGE = 5;
 
-        findOneBoundedConcurrentPutRemove();
+        iterateConcurrentPutRemove();
     }
 
     /**
@@ -1334,13 +1392,13 @@ public class BPlusTreeSelfTest extends 
GridCommonAbstractTest {
     public void testIteratePutRemove_10() throws Exception {
         MAX_PER_PAGE = 10;
 
-        findOneBoundedConcurrentPutRemove();
+        iterateConcurrentPutRemove();
     }
 
     /**
      * @throws Exception If failed.
      */
-    private void findOneBoundedConcurrentPutRemove() throws Exception {
+    private void iterateConcurrentPutRemove() throws Exception {
         final TestTree tree = createTestTree(true);
 
         final int KEYS = 10_000;
@@ -1474,7 +1532,7 @@ public class BPlusTreeSelfTest extends 
GridCommonAbstractTest {
     }
 
     /**
-     *
+     * @throws Exception If failed.
      */
     public void testConcurrentGrowDegenerateTreeAndConcurrentRemove() throws 
Exception {
         //calculate tree size when split happens
@@ -2132,6 +2190,7 @@ public class BPlusTreeSelfTest extends 
GridCommonAbstractTest {
         /** */
         private Long val;
 
+
         /** {@inheritDoc} */
         @Override public boolean apply(BPlusTree<Long, Long> tree, 
BPlusIO<Long> io, long pageAddr, int idx)
             throws IgniteCheckedException {
@@ -2142,4 +2201,27 @@ public class BPlusTreeSelfTest extends 
GridCommonAbstractTest {
             return false;
         }
     }
+
+    /**
+     *
+     */
+    static class TestTreeFindFilteredClosure implements 
BPlusTree.TreeRowClosure<Long, Long> {
+        /** */
+        private final Set<Long> vals;
+
+        /**
+         * @param vals Values to allow in filter.
+         */
+        TestTreeFindFilteredClosure(Set<Long> vals) {
+            this.vals = vals;
+        }
+
+        /** {@inheritDoc} */
+        @Override public boolean apply(BPlusTree<Long, Long> tree, 
BPlusIO<Long> io, long pageAddr, int idx)
+            throws IgniteCheckedException {
+            Long val = io.getLookupRow(tree, pageAddr, idx);
+
+            return vals.contains(val);
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/6150f3a0/modules/geospatial/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2SpatialIndex.java
----------------------------------------------------------------------
diff --git 
a/modules/geospatial/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2SpatialIndex.java
 
b/modules/geospatial/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2SpatialIndex.java
index 2cd36b3..fce18f1 100644
--- 
a/modules/geospatial/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2SpatialIndex.java
+++ 
b/modules/geospatial/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2SpatialIndex.java
@@ -200,6 +200,11 @@ public class GridH2SpatialIndex extends GridH2IndexBase 
implements SpatialIndex
         }
     }
 
+    /** {@inheritDoc} */
+    @Override public boolean putx(GridH2Row row) {
+        return put(row) != null;
+    }
+
     /**
      * @param row Row.
      * @param rowId Row id.

http://git-wip-us.apache.org/repos/asf/ignite/blob/6150f3a0/modules/indexing/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheTwoStepQuery.java
----------------------------------------------------------------------
diff --git 
a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheTwoStepQuery.java
 
b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheTwoStepQuery.java
index 4a93aaf..f5c5e60 100644
--- 
a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheTwoStepQuery.java
+++ 
b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheTwoStepQuery.java
@@ -65,6 +65,9 @@ public class GridCacheTwoStepQuery {
     /** */
     private CacheQueryPartitionInfo[] derivedPartitions;
 
+    /** */
+    private boolean mvccEnabled;
+
     /**
      * @param originalSql Original query SQL.
      * @param tbls Tables in query.
@@ -241,6 +244,7 @@ public class GridCacheTwoStepQuery {
         cp.distributedJoins = distributedJoins;
         cp.derivedPartitions = derivedPartitions;
         cp.local = local;
+        cp.mvccEnabled = mvccEnabled;
 
         for (int i = 0; i < mapQrys.size(); i++)
             cp.mapQrys.add(mapQrys.get(i).copy());
@@ -262,6 +266,20 @@ public class GridCacheTwoStepQuery {
         return tbls;
     }
 
+    /**
+     * @return Mvcc flag.
+     */
+    public boolean mvccEnabled() {
+        return mvccEnabled;
+    }
+
+    /**
+     * @param mvccEnabled Mvcc flag.
+     */
+    public void mvccEnabled(boolean mvccEnabled) {
+        this.mvccEnabled = mvccEnabled;
+    }
+
     /** {@inheritDoc} */
     @Override public String toString() {
         return S.toString(GridCacheTwoStepQuery.class, this);

http://git-wip-us.apache.org/repos/asf/ignite/blob/6150f3a0/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 eed1f19..6dc93c4 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
@@ -71,6 +71,7 @@ import 
org.apache.ignite.internal.processors.cache.IgniteCacheOffheapManager;
 import org.apache.ignite.internal.processors.cache.KeyCacheObject;
 import org.apache.ignite.internal.processors.cache.QueryCursorImpl;
 import 
org.apache.ignite.internal.processors.cache.distributed.dht.GridDhtInvalidPartitionException;
+import org.apache.ignite.internal.processors.cache.mvcc.MvccCoordinatorVersion;
 import org.apache.ignite.internal.processors.cache.persistence.CacheDataRow;
 import org.apache.ignite.internal.processors.cache.persistence.tree.io.PageIO;
 import 
org.apache.ignite.internal.processors.cache.query.CacheQueryPartitionInfo;
@@ -98,6 +99,8 @@ import 
org.apache.ignite.internal.processors.query.h2.database.io.H2ExtrasInnerI
 import 
org.apache.ignite.internal.processors.query.h2.database.io.H2ExtrasLeafIO;
 import org.apache.ignite.internal.processors.query.h2.database.io.H2InnerIO;
 import org.apache.ignite.internal.processors.query.h2.database.io.H2LeafIO;
+import 
org.apache.ignite.internal.processors.query.h2.database.io.H2MvccInnerIO;
+import org.apache.ignite.internal.processors.query.h2.database.io.H2MvccLeafIO;
 import 
org.apache.ignite.internal.processors.query.h2.ddl.DdlStatementsProcessor;
 import org.apache.ignite.internal.processors.query.h2.opt.DistributedJoinMode;
 import 
org.apache.ignite.internal.processors.query.h2.opt.GridH2DefaultTableEngine;
@@ -183,7 +186,7 @@ public class IgniteH2Indexing implements GridQueryIndexing {
      * Register IO for indexes.
      */
     static {
-        PageIO.registerH2(H2InnerIO.VERSIONS, H2LeafIO.VERSIONS);
+        PageIO.registerH2(H2InnerIO.VERSIONS, H2LeafIO.VERSIONS, 
H2MvccInnerIO.VERSIONS, H2MvccLeafIO.VERSIONS);
         H2ExtrasInnerIO.register();
         H2ExtrasLeafIO.register();
 
@@ -537,8 +540,11 @@ public class IgniteH2Indexing implements GridQueryIndexing 
{
     }
 
     /** {@inheritDoc} */
-    @Override public void store(GridCacheContext cctx, GridQueryTypeDescriptor 
type, CacheDataRow row)
-        throws IgniteCheckedException {
+    @Override public void store(GridCacheContext cctx,
+        GridQueryTypeDescriptor type,
+        CacheDataRow row,
+        @Nullable MvccCoordinatorVersion newVer) throws IgniteCheckedException
+    {
         String cacheName = cctx.name();
 
         H2TableDescriptor tbl = tableDescriptor(schema(cacheName), cacheName, 
type.name());
@@ -546,7 +552,7 @@ public class IgniteH2Indexing implements GridQueryIndexing {
         if (tbl == null)
             return; // Type was rejected.
 
-        tbl.table().update(row, false);
+        tbl.table().update(row, newVer, false);
 
         if (tbl.luceneIndex() != null) {
             long expireTime = row.expireTime();
@@ -575,7 +581,7 @@ public class IgniteH2Indexing implements GridQueryIndexing {
         if (tbl == null)
             return;
 
-        if (tbl.table().update(row, true)) {
+        if (tbl.table().update(row, null, true)) {
             if (tbl.luceneIndex() != null)
                 tbl.luceneIndex().remove(row.key());
         }
@@ -671,7 +677,7 @@ public class IgniteH2Indexing implements GridQueryIndexing {
 
             SchemaIndexCacheVisitorClosure clo = new 
SchemaIndexCacheVisitorClosure() {
                 @Override public void apply(CacheDataRow row) throws 
IgniteCheckedException {
-                    GridH2Row h2Row = rowDesc.createRow(row);
+                    GridH2Row h2Row = rowDesc.createRow(row, null);
 
                     h2Idx.put(h2Row);
                 }
@@ -1546,7 +1552,8 @@ public class IgniteH2Indexing implements 
GridQueryIndexing {
         if (partitions == null && twoStepQry.derivedPartitions() != null) {
             try {
                 partitions = 
calculateQueryPartitions(twoStepQry.derivedPartitions(), args);
-            } catch (IgniteCheckedException e) {
+            }
+            catch (IgniteCheckedException e) {
                 throw new CacheException("Failed to calculate derived 
partitions: [qry=" + sqlQry + ", params=" +
                     Arrays.deepToString(args) + "]", e);
             }
@@ -1585,9 +1592,11 @@ public class IgniteH2Indexing implements 
GridQueryIndexing {
     }
 
     /**
+     * @param cacheIds Cache IDs.
+     * @param twoStepQry Query.
      * @throws IllegalStateException if segmented indices used with 
non-segmented indices.
      */
-    private void checkCacheIndexSegmentation(List<Integer> cacheIds) {
+    private void processCaches(List<Integer> cacheIds, GridCacheTwoStepQuery 
twoStepQry) {
         if (cacheIds.isEmpty())
             return; // Nothing to check
 
@@ -1595,11 +1604,21 @@ public class IgniteH2Indexing implements 
GridQueryIndexing {
 
         int expectedParallelism = 0;
 
-        for (Integer cacheId : cacheIds) {
+        boolean mvccEnabled = false;
+
+        for (int i = 0; i < cacheIds.size(); i++) {
+            Integer cacheId = cacheIds.get(i);
+
             GridCacheContext cctx = sharedCtx.cacheContext(cacheId);
 
             assert cctx != null;
 
+            if (i == 0)
+                mvccEnabled = cctx.mvccEnabled();
+            else if (cctx.mvccEnabled() != mvccEnabled)
+                throw new IllegalStateException("Using caches with different 
mvcc settings in same query is " +
+                    "forbidden.");
+
             if (!cctx.isPartitioned())
                 continue;
 
@@ -1610,6 +1629,8 @@ public class IgniteH2Indexing implements 
GridQueryIndexing {
                     "forbidden.");
             }
         }
+
+        twoStepQry.mvccEnabled(mvccEnabled);
     }
 
     /**
@@ -2522,7 +2543,7 @@ public class IgniteH2Indexing implements 
GridQueryIndexing {
             //Prohibit usage indices with different numbers of segments in 
same query.
             List<Integer> cacheIds = new ArrayList<>(caches0);
 
-            checkCacheIndexSegmentation(cacheIds);
+            processCaches(cacheIds, twoStepQry);
 
             return cacheIds;
         }

http://git-wip-us.apache.org/repos/asf/ignite/blob/6150f3a0/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2PkHashIndex.java
----------------------------------------------------------------------
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 59bf153..9a99c62 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
@@ -124,13 +124,20 @@ public class H2PkHashIndex extends GridH2IndexBase {
     @SuppressWarnings("StatementWithEmptyBody")
     @Override public GridH2Row put(GridH2Row row) {
         // Should not be called directly. Rows are inserted into underlying 
cache data stores.
-
         assert false;
 
         throw DbException.getUnsupportedException("put");
     }
 
     /** {@inheritDoc} */
+    @Override public boolean putx(GridH2Row row) {
+        // Should not be called directly. Rows are inserted into underlying 
cache data stores.
+        assert false;
+
+        throw DbException.getUnsupportedException("putx");
+    }
+
+    /** {@inheritDoc} */
     @Override public GridH2Row remove(SearchRow row) {
         // Should not be called directly. Rows are removed from underlying 
cache data stores.
 
@@ -197,7 +204,7 @@ public class H2PkHashIndex extends GridH2IndexBase {
             try {
                 CacheDataRow dataRow = cursor.get();
 
-                return tbl.rowDescriptor().createRow(dataRow);
+                return tbl.rowDescriptor().createRow(dataRow, null);
             }
             catch (IgniteCheckedException e) {
                 throw DbException.convert(e);

http://git-wip-us.apache.org/repos/asf/ignite/blob/6150f3a0/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2RowFactory.java
----------------------------------------------------------------------
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 40b9b0a..e9ec9e6 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
@@ -18,9 +18,9 @@
 package org.apache.ignite.internal.processors.query.h2.database;
 
 import org.apache.ignite.IgniteCheckedException;
-import org.apache.ignite.IgniteException;
 import org.apache.ignite.internal.processors.cache.GridCacheContext;
 import 
org.apache.ignite.internal.processors.cache.persistence.CacheDataRowAdapter;
+import org.apache.ignite.internal.processors.cache.tree.MvccDataRow;
 import org.apache.ignite.internal.processors.query.h2.opt.GridH2Row;
 import org.apache.ignite.internal.processors.query.h2.opt.GridH2RowDescriptor;
 
@@ -60,17 +60,29 @@ public class H2RowFactory {
 
         rowBuilder.initFromLink(cctx.group(), 
CacheDataRowAdapter.RowData.FULL);
 
-        GridH2Row row;
-
-        try {
-            row = rowDesc.createRow(rowBuilder);
-        }
-        catch (IgniteCheckedException e) {
-            throw new IgniteException(e);
-        }
+        GridH2Row row = rowDesc.createRow(rowBuilder, null);
 
         assert row.version() != null;
 
         return row;
     }
+
+    /**
+     * @param link Link.
+     * @param mvccCrdVer Mvcc coordinator version.
+     * @param mvccCntr Mvcc counter.
+     * @return Row.
+     * @throws IgniteCheckedException If failed.
+     */
+    public GridH2Row getMvccRow(long link, long mvccCrdVer, long mvccCntr) 
throws IgniteCheckedException {
+        MvccDataRow row = new MvccDataRow(cctx.group(),
+            0,
+            link,
+            -1, // TODO IGNITE-3478: get partition from link.
+            null,
+            mvccCrdVer,
+            mvccCntr);
+
+        return rowDesc.createRow(row, null);
+    }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/6150f3a0/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 fcfeb16..df77f7a 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
@@ -29,15 +29,22 @@ import 
org.apache.ignite.internal.processors.cache.persistence.tree.io.BPlusMeta
 import 
org.apache.ignite.internal.processors.cache.persistence.tree.reuse.ReuseList;
 import 
org.apache.ignite.internal.processors.query.h2.database.io.H2ExtrasInnerIO;
 import 
org.apache.ignite.internal.processors.query.h2.database.io.H2ExtrasLeafIO;
+import org.apache.ignite.internal.processors.query.h2.database.io.H2RowLinkIO;
 import org.apache.ignite.internal.processors.query.h2.opt.GridH2Row;
+import org.apache.ignite.internal.processors.query.h2.opt.GridH2SearchRow;
+import org.apache.ignite.internal.util.typedef.internal.S;
 import org.apache.ignite.internal.util.typedef.internal.U;
 import org.h2.result.SearchRow;
 import org.h2.table.IndexColumn;
 import org.h2.value.Value;
 
+import static 
org.apache.ignite.internal.processors.cache.mvcc.CacheCoordinatorsProcessor.MVCC_COUNTER_NA;
+import static 
org.apache.ignite.internal.processors.cache.mvcc.CacheCoordinatorsProcessor.assertMvccVersionValid;
+import static 
org.apache.ignite.internal.processors.cache.mvcc.CacheCoordinatorsProcessor.unmaskCoordinatorVersion;
+
 /**
  */
-public abstract class H2Tree extends BPlusTree<SearchRow, GridH2Row> {
+public abstract class H2Tree extends BPlusTree<GridH2SearchRow, GridH2Row> {
     /** */
     private final H2RowFactory rowStore;
 
@@ -54,6 +61,9 @@ public abstract class H2Tree extends BPlusTree<SearchRow, 
GridH2Row> {
     private final int[] columnIds;
 
     /** */
+    private final boolean mvccEnabled;
+
+    /** */
     private final Comparator<Value> comp = new Comparator<Value>() {
         @Override public int compare(Value o1, Value o2) {
             return compareValues(o1, o2);
@@ -69,9 +79,10 @@ public abstract class H2Tree extends BPlusTree<SearchRow, 
GridH2Row> {
      * @param rowStore Row data store.
      * @param metaPageId Meta page ID.
      * @param initNew Initialize new index.
+     * @param mvccEnabled Mvcc flag.
      * @throws IgniteCheckedException If failed.
      */
-    protected H2Tree(
+    H2Tree(
         String name,
         ReuseList reuseList,
         int grpId,
@@ -83,7 +94,8 @@ public abstract class H2Tree extends BPlusTree<SearchRow, 
GridH2Row> {
         boolean initNew,
         IndexColumn[] cols,
         List<InlineIndexHelper> inlineIdxs,
-        int inlineSize
+        int inlineSize,
+        boolean mvccEnabled
     ) throws IgniteCheckedException {
         super(name, grpId, pageMem, wal, globalRmvId, metaPageId, reuseList);
 
@@ -93,6 +105,7 @@ public abstract class H2Tree extends BPlusTree<SearchRow, 
GridH2Row> {
         }
 
         this.inlineSize = inlineSize;
+        this.mvccEnabled = mvccEnabled;
 
         assert rowStore != null;
 
@@ -105,7 +118,7 @@ public abstract class H2Tree extends BPlusTree<SearchRow, 
GridH2Row> {
         for (int i = 0; i < cols.length; i++)
             columnIds[i] = cols[i].column.getColumnId();
 
-        setIos(H2ExtrasInnerIO.getVersions(inlineSize), 
H2ExtrasLeafIO.getVersions(inlineSize));
+        setIos(H2ExtrasInnerIO.getVersions(inlineSize, mvccEnabled), 
H2ExtrasLeafIO.getVersions(inlineSize, mvccEnabled));
 
         initTree(initNew, inlineSize);
     }
@@ -118,7 +131,7 @@ public abstract class H2Tree extends BPlusTree<SearchRow, 
GridH2Row> {
     }
 
     /** {@inheritDoc} */
-    @Override protected GridH2Row getRow(BPlusIO<SearchRow> io, long pageAddr, 
int idx, Object ignore)
+    @Override protected GridH2Row getRow(BPlusIO<GridH2SearchRow> io, long 
pageAddr, int idx, Object ignore)
         throws IgniteCheckedException {
         return (GridH2Row)io.getLookupRow(this, pageAddr, idx);
     }
@@ -159,8 +172,8 @@ public abstract class H2Tree extends BPlusTree<SearchRow, 
GridH2Row> {
 
     /** {@inheritDoc} */
     @SuppressWarnings("ForLoopReplaceableByForEach")
-    @Override protected int compare(BPlusIO<SearchRow> io, long pageAddr, int 
idx,
-        SearchRow row) throws IgniteCheckedException {
+    @Override protected int compare(BPlusIO<GridH2SearchRow> io, long 
pageAddr, int idx,
+        GridH2SearchRow row) throws IgniteCheckedException {
         if (inlineSize() == 0)
             return compareRows(getRow(io, pageAddr, idx), row);
         else {
@@ -195,7 +208,7 @@ public abstract class H2Tree extends BPlusTree<SearchRow, 
GridH2Row> {
             }
 
             if (lastIdxUsed == cols.length)
-                return 0;
+                return mvccCompare((H2RowLinkIO)io, pageAddr, idx, row);
 
             SearchRow rowData = getRow(io, pageAddr, idx);
 
@@ -207,7 +220,7 @@ public abstract class H2Tree extends BPlusTree<SearchRow, 
GridH2Row> {
 
                 if (v2 == null) {
                     // Can't compare further.
-                    return 0;
+                    return mvccCompare((H2RowLinkIO)io, pageAddr, idx, row);
                 }
 
                 Value v1 = rowData.getValue(idx0);
@@ -218,7 +231,7 @@ public abstract class H2Tree extends BPlusTree<SearchRow, 
GridH2Row> {
                     return InlineIndexHelper.fixSort(c, col.sortType);
             }
 
-            return 0;
+            return mvccCompare((H2RowLinkIO)io, pageAddr, idx, row);
         }
     }
 
@@ -229,7 +242,9 @@ public abstract class H2Tree extends BPlusTree<SearchRow, 
GridH2Row> {
      * @param r2 Row 2.
      * @return Compare result.
      */
-    private int compareRows(GridH2Row r1, SearchRow r2) {
+    private int compareRows(GridH2Row r1, GridH2SearchRow r2) {
+        assert !mvccEnabled || r2.indexSearchRow() || 
assertMvccVersionValid(r2.mvccCoordinatorVersion(), r2.mvccCounter()) : r2;
+
         if (r1 == r2)
             return 0;
 
@@ -241,7 +256,7 @@ public abstract class H2Tree extends BPlusTree<SearchRow, 
GridH2Row> {
 
             if (v1 == null || v2 == null) {
                 // Can't compare further.
-                return 0;
+                return mvccCompare(r1, r2);
             }
 
             int c = compareValues(v1, v2);
@@ -250,6 +265,64 @@ public abstract class H2Tree extends BPlusTree<SearchRow, 
GridH2Row> {
                 return InlineIndexHelper.fixSort(c, cols[i].sortType);
         }
 
+        return mvccCompare(r1, r2);
+    }
+
+    /**
+     * @param io IO.
+     * @param pageAddr Page address.
+     * @param idx Item index.
+     * @param r2 Search row.
+     * @return Comparison result.
+     */
+    private int mvccCompare(H2RowLinkIO io, long pageAddr, int idx, 
GridH2SearchRow r2) {
+        if (mvccEnabled && !r2.indexSearchRow()) {
+            long crdVer1 = io.getMvccCoordinatorVersion(pageAddr, idx);
+            long crdVer2 = r2.mvccCoordinatorVersion();
+
+            assert crdVer1 != 0;
+            assert crdVer2 != 0 : r2;
+
+            int c = Long.compare(unmaskCoordinatorVersion(crdVer1), 
unmaskCoordinatorVersion(crdVer2));
+
+            if (c != 0)
+                return c;
+
+            long cntr = io.getMvccCounter(pageAddr, idx);
+
+            assert cntr != MVCC_COUNTER_NA;
+            assert r2.mvccCounter() != MVCC_COUNTER_NA : r2;
+
+            return Long.compare(cntr, r2.mvccCounter());
+        }
+
+        return 0;
+    }
+
+    /**
+     * @param r1 First row.
+     * @param r2 Second row.
+     * @return Comparison result.
+     */
+    private int mvccCompare(GridH2Row r1, GridH2SearchRow r2) {
+        if (mvccEnabled && !r2.indexSearchRow()) {
+            long crdVer1 = r1.mvccCoordinatorVersion();
+            long crdVer2 = r2.mvccCoordinatorVersion();
+
+            assert crdVer1 != 0 : r1;
+            assert crdVer2 != 0 : r2;
+
+            int c = Long.compare(unmaskCoordinatorVersion(crdVer1), 
unmaskCoordinatorVersion(crdVer2));
+
+            if (c != 0)
+                return c;
+
+            assert r1.mvccCounter() != MVCC_COUNTER_NA : r1;
+            assert r2.mvccCounter() != MVCC_COUNTER_NA : r2;
+
+            return Long.compare(r1.mvccCounter(), r2.mvccCounter());
+        }
+
         return 0;
     }
 
@@ -259,4 +332,9 @@ public abstract class H2Tree extends BPlusTree<SearchRow, 
GridH2Row> {
      * @return Comparison result.
      */
     public abstract int compareValues(Value v1, Value v2);
+
+    /** {@inheritDoc} */
+    @Override public String toString() {
+        return S.toString(H2Tree.class, this, "super", super.toString());
+    }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/6150f3a0/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 3c0ab5e..87a6eca 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
@@ -29,7 +29,9 @@ import 
org.apache.ignite.internal.processors.cache.persistence.tree.BPlusTree;
 import org.apache.ignite.internal.processors.cache.persistence.tree.io.PageIO;
 import org.apache.ignite.internal.processors.query.h2.H2Cursor;
 import org.apache.ignite.internal.processors.query.h2.opt.GridH2IndexBase;
+import org.apache.ignite.internal.processors.query.h2.opt.GridH2QueryContext;
 import org.apache.ignite.internal.processors.query.h2.opt.GridH2Row;
+import org.apache.ignite.internal.processors.query.h2.opt.GridH2SearchRow;
 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;
@@ -118,7 +120,8 @@ public class H2TreeIndex extends GridH2IndexBase {
                     page.isAllocated(),
                     cols,
                     inlineIdxs,
-                    computeInlineSize(inlineIdxs, inlineSize)) {
+                    computeInlineSize(inlineIdxs, inlineSize),
+                    cctx.mvccEnabled()) {
                     @Override public int compareValues(Value v1, Value v2) {
                         return v1 == v2 ? 0 : table.compareTypeSafe(v1, v2);
                     }
@@ -165,20 +168,33 @@ public class H2TreeIndex extends GridH2IndexBase {
     /** {@inheritDoc} */
     @Override public Cursor find(Session ses, SearchRow lower, SearchRow 
upper) {
         try {
-            IndexingQueryFilter f = threadLocalFilter();
+            assert lower == null || lower instanceof GridH2SearchRow : lower;
+            assert upper == null || upper instanceof GridH2SearchRow : upper;
+
             IndexingQueryCacheFilter p = null;
+            H2TreeMvccFilterClosure mvccFilter = null;
+
+            GridH2QueryContext qctx = GridH2QueryContext.get();
+
+            if (qctx != null) {
+                IndexingQueryFilter f = qctx.filter();
+
+                if (f != null) {
+                    String cacheName = getTable().cacheName();
 
-            if (f != null) {
-                String cacheName = getTable().cacheName();
+                    p = f.forCache(cacheName);
+                }
 
-                p = f.forCache(cacheName);
+                mvccFilter = qctx.mvccFilter();
             }
 
             int seg = threadLocalSegment();
 
             H2Tree tree = treeForRead(seg);
 
-            return new H2Cursor(tree.find(lower, upper), p);
+            assert !cctx.mvccEnabled() || mvccFilter != null;
+
+            return new H2Cursor(tree.find((GridH2SearchRow)lower, 
(GridH2SearchRow)upper, mvccFilter, null), p);
         }
         catch (IgniteCheckedException e) {
             throw DbException.convert(e);
@@ -205,7 +221,28 @@ public class H2TreeIndex extends GridH2IndexBase {
     }
 
     /** {@inheritDoc} */
+    @Override public boolean putx(GridH2Row row) {
+        try {
+            InlineIndexHelper.setCurrentInlineIndexes(inlineIdxs);
+
+            int seg = segmentForRow(row);
+
+            H2Tree tree = treeForRead(seg);
+
+            return tree.putx(row);
+        }
+        catch (IgniteCheckedException e) {
+            throw DbException.convert(e);
+        }
+        finally {
+            InlineIndexHelper.clearCurrentInlineIndexes();
+        }
+    }
+
+    /** {@inheritDoc} */
     @Override public GridH2Row remove(SearchRow row) {
+        assert row instanceof GridH2SearchRow : row;
+
         try {
             InlineIndexHelper.setCurrentInlineIndexes(inlineIdxs);
 
@@ -213,7 +250,7 @@ public class H2TreeIndex extends GridH2IndexBase {
 
             H2Tree tree = treeForRead(seg);
 
-            return tree.remove(row);
+            return tree.remove((GridH2SearchRow)row);
         }
         catch (IgniteCheckedException e) {
             throw DbException.convert(e);
@@ -225,6 +262,8 @@ public class H2TreeIndex extends GridH2IndexBase {
 
     /** {@inheritDoc} */
     @Override public void removex(SearchRow row) {
+        assert row instanceof GridH2SearchRow : row;
+
         try {
             InlineIndexHelper.setCurrentInlineIndexes(inlineIdxs);
 
@@ -232,7 +271,7 @@ public class H2TreeIndex extends GridH2IndexBase {
 
             H2Tree tree = treeForRead(seg);
 
-            tree.removex(row);
+            tree.removex((GridH2SearchRow)row);
         }
         catch (IgniteCheckedException e) {
             throw DbException.convert(e);
@@ -282,6 +321,17 @@ public class H2TreeIndex extends GridH2IndexBase {
 
             H2Tree tree = treeForRead(seg);
 
+            if (cctx.mvccEnabled()) {
+                GridH2QueryContext qctx = GridH2QueryContext.get();
+
+                assert qctx != null;
+
+                H2TreeMvccFilterClosure mvccFilter = qctx.mvccFilter();
+
+                assert mvccFilter != null;
+                // TODO IGNITE-3478 (support filter for first/last)
+            }
+
             GridH2Row row = b ? tree.findFirst(): tree.findLast();
 
             return new SingleRowCursor(row);
@@ -321,11 +371,13 @@ public class H2TreeIndex extends GridH2IndexBase {
     @Override protected GridCursor<GridH2Row> doFind0(
         IgniteTree t,
         @Nullable SearchRow first,
-        boolean includeFirst,
         @Nullable SearchRow last,
-        IndexingQueryFilter filter) {
+        IndexingQueryFilter filter,
+        H2TreeMvccFilterClosure mvccFilter) {
         try {
-            GridCursor<GridH2Row> range = t.find(first, last);
+            assert !cctx.mvccEnabled() || mvccFilter != null;
+
+            GridCursor<GridH2Row> range = ((BPlusTree)t).find(first, last, 
mvccFilter, null);
 
             if (range == null)
                 return EMPTY_CURSOR;

http://git-wip-us.apache.org/repos/asf/ignite/blob/6150f3a0/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2TreeMvccFilterClosure.java
----------------------------------------------------------------------
diff --git 
a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2TreeMvccFilterClosure.java
 
b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2TreeMvccFilterClosure.java
new file mode 100644
index 0000000..6ae2312
--- /dev/null
+++ 
b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2TreeMvccFilterClosure.java
@@ -0,0 +1,106 @@
+/*
+ * 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;
+
+import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.internal.processors.cache.mvcc.MvccCoordinatorVersion;
+import org.apache.ignite.internal.processors.cache.persistence.tree.BPlusTree;
+import org.apache.ignite.internal.processors.cache.persistence.tree.io.BPlusIO;
+import org.apache.ignite.internal.processors.query.h2.database.io.H2RowLinkIO;
+import org.apache.ignite.internal.processors.query.h2.opt.GridH2Row;
+import org.apache.ignite.internal.processors.query.h2.opt.GridH2SearchRow;
+import org.apache.ignite.internal.util.typedef.internal.S;
+
+import static 
org.apache.ignite.internal.processors.cache.mvcc.CacheCoordinatorsProcessor.assertMvccVersionValid;
+import static 
org.apache.ignite.internal.processors.cache.mvcc.CacheCoordinatorsProcessor.unmaskCoordinatorVersion;
+
+/**
+ *
+ */
+public class H2TreeMvccFilterClosure implements 
H2Tree.TreeRowClosure<GridH2SearchRow, GridH2Row> {
+    /** */
+    private final MvccCoordinatorVersion mvccVer;
+
+    /**
+     * @param mvccVer Mvcc version.
+     */
+    public H2TreeMvccFilterClosure(MvccCoordinatorVersion mvccVer) {
+        assert mvccVer != null;
+
+        this.mvccVer = mvccVer;
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean apply(BPlusTree<GridH2SearchRow, GridH2Row> tree,
+        BPlusIO<GridH2SearchRow> io,
+        long pageAddr,
+        int idx)  throws IgniteCheckedException {
+        H2RowLinkIO rowIo = (H2RowLinkIO)io;
+
+        assert rowIo.storeMvccInfo() : rowIo;
+
+        long rowCrdVer = rowIo.getMvccCoordinatorVersion(pageAddr, idx);
+
+        assert unmaskCoordinatorVersion(rowCrdVer) == rowCrdVer : rowCrdVer;
+        assert rowCrdVer > 0 : rowCrdVer;
+
+        int cmp = Long.compare(mvccVer.coordinatorVersion(), rowCrdVer);
+
+        if (cmp == 0) {
+            long rowCntr = rowIo.getMvccCounter(pageAddr, idx);
+
+            cmp = Long.compare(mvccVer.counter(), rowCntr);
+
+            return cmp >= 0 &&
+                !newVersionAvailable(rowIo, pageAddr, idx) &&
+                !mvccVer.activeTransactions().contains(rowCntr);
+        }
+        else
+            return cmp > 0;
+    }
+
+    /**
+     * @param rowIo Row IO.
+     * @param pageAddr Page address.
+     * @param idx Item index.
+     * @return {@code True}
+     */
+    private boolean newVersionAvailable(H2RowLinkIO rowIo, long pageAddr, int 
idx) {
+        long newCrdVer = rowIo.getNewMvccCoordinatorVersion(pageAddr, idx);
+
+        if (newCrdVer == 0)
+            return false;
+
+        int cmp = Long.compare(mvccVer.coordinatorVersion(), newCrdVer);
+
+        if (cmp == 0) {
+            long newCntr = rowIo.getNewMvccCounter(pageAddr, idx);
+
+            assert assertMvccVersionValid(newCrdVer, newCntr);
+
+            return newCntr <= mvccVer.counter() && 
!mvccVer.activeTransactions().contains(newCntr);
+        }
+        else
+            return cmp < 0;
+    }
+
+    /** {@inheritDoc} */
+    @Override public String toString() {
+        return S.toString(H2TreeMvccFilterClosure.class, this);
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/6150f3a0/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/io/AbstractH2ExtrasInnerIO.java
----------------------------------------------------------------------
diff --git 
a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/io/AbstractH2ExtrasInnerIO.java
 
b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/io/AbstractH2ExtrasInnerIO.java
new file mode 100644
index 0000000..550aade
--- /dev/null
+++ 
b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/io/AbstractH2ExtrasInnerIO.java
@@ -0,0 +1,190 @@
+/*
+ * 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.io;
+
+import java.util.List;
+import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.internal.pagemem.PageUtils;
+import org.apache.ignite.internal.processors.cache.persistence.tree.BPlusTree;
+import org.apache.ignite.internal.processors.cache.persistence.tree.io.BPlusIO;
+import 
org.apache.ignite.internal.processors.cache.persistence.tree.io.BPlusInnerIO;
+import 
org.apache.ignite.internal.processors.cache.persistence.tree.io.IOVersions;
+import org.apache.ignite.internal.processors.cache.persistence.tree.io.PageIO;
+import org.apache.ignite.internal.processors.query.h2.database.H2Tree;
+import 
org.apache.ignite.internal.processors.query.h2.database.InlineIndexHelper;
+import org.apache.ignite.internal.processors.query.h2.opt.GridH2Row;
+import org.apache.ignite.internal.processors.query.h2.opt.GridH2SearchRow;
+
+import static 
org.apache.ignite.internal.processors.cache.mvcc.CacheCoordinatorsProcessor.MVCC_COUNTER_NA;
+
+/**
+ * Inner page for H2 row references.
+ */
+public abstract class AbstractH2ExtrasInnerIO extends 
BPlusInnerIO<GridH2SearchRow> implements H2RowLinkIO {
+    /** Payload size. */
+    private final int payloadSize;
+
+    /** */
+    public static void register() {
+        register(false);
+
+        register(true);
+    }
+
+    /**
+     * @param mvcc Mvcc flag.
+     */
+    private static void register(boolean mvcc) {
+        short type = mvcc ? PageIO.T_H2_EX_REF_MVCC_INNER_START : 
PageIO.T_H2_EX_REF_INNER_START;
+
+        for (short payload = 1; payload <= PageIO.MAX_PAYLOAD_SIZE; payload++) 
{
+            IOVersions<? extends AbstractH2ExtrasInnerIO> io =
+                getVersions((short)(type + payload - 1), payload, mvcc);
+
+            PageIO.registerH2ExtraInner(io, mvcc);
+        }
+    }
+
+    /**
+     * @param payload Payload size.
+     * @param mvccEnabled Mvcc flag.
+     * @return IOVersions for given payload.
+     */
+    @SuppressWarnings("unchecked")
+    public static IOVersions<? extends BPlusInnerIO<GridH2SearchRow>> 
getVersions(int payload, boolean mvccEnabled) {
+        assert payload >= 0 && payload <= PageIO.MAX_PAYLOAD_SIZE;
+
+        if (payload == 0)
+            return mvccEnabled ? H2MvccInnerIO.VERSIONS : H2InnerIO.VERSIONS;
+        else
+            return 
(IOVersions<BPlusInnerIO<GridH2SearchRow>>)PageIO.getInnerVersions((short)(payload
 - 1), mvccEnabled);
+    }
+
+    /**
+     * @param type Type.
+     * @param payload Payload size.
+     * @param mvcc Mvcc flag.
+     * @return Instance of IO versions.
+     */
+    private static IOVersions<? extends AbstractH2ExtrasInnerIO> 
getVersions(short type, short payload, boolean mvcc) {
+        return new IOVersions<>(mvcc ? new H2MvccExtrasInnerIO(type, 1, 
payload) : new H2ExtrasInnerIO(type, 1, payload));
+    }
+
+    /**
+     * @param type Page type.
+     * @param ver Page format version.
+     * @param itemSize Item size.
+     * @param payloadSize Payload size.
+     */
+    AbstractH2ExtrasInnerIO(short type, int ver, int itemSize, int 
payloadSize) {
+        super(type, ver, true, itemSize + payloadSize);
+
+        this.payloadSize = payloadSize;
+    }
+
+    /** {@inheritDoc} */
+    @SuppressWarnings("ForLoopReplaceableByForEach")
+    @Override public final void storeByOffset(long pageAddr, int off, 
GridH2SearchRow row) {
+        GridH2Row row0 = (GridH2Row)row;
+
+        assert row0.link() != 0 : row0;
+
+        List<InlineIndexHelper> inlineIdxs = 
InlineIndexHelper.getCurrentInlineIndexes();
+
+        assert inlineIdxs != null : "no inline index helpers";
+
+
+        int fieldOff = 0;
+
+        for (int i = 0; i < inlineIdxs.size(); i++) {
+            InlineIndexHelper idx = inlineIdxs.get(i);
+
+            int size = idx.put(pageAddr, off + fieldOff, 
row.getValue(idx.columnIndex()), payloadSize - fieldOff);
+
+            if (size == 0)
+                break;
+
+            fieldOff += size;
+        }
+
+        H2IOUtils.storeRow(row0, pageAddr, off + payloadSize, storeMvccInfo());
+    }
+
+    /** {@inheritDoc} */
+    @Override public final GridH2SearchRow 
getLookupRow(BPlusTree<GridH2SearchRow, ?> tree, long pageAddr, int idx)
+        throws IgniteCheckedException {
+        long link = getLink(pageAddr, idx);
+
+        assert link != 0;
+
+        if (storeMvccInfo()) {
+            long mvccCrdVer = getMvccCoordinatorVersion(pageAddr, idx);
+            long mvccCntr = getMvccCounter(pageAddr, idx);
+
+            return ((H2Tree)tree).getRowFactory().getMvccRow(link, mvccCrdVer, 
mvccCntr);
+        }
+
+        return ((H2Tree)tree).getRowFactory().getRow(link);
+    }
+
+    /** {@inheritDoc} */
+    @Override public final void store(long dstPageAddr, int dstIdx, 
BPlusIO<GridH2SearchRow> srcIo, long srcPageAddr, int srcIdx) {
+        int srcOff = srcIo.offset(srcIdx);
+
+        byte[] payload = PageUtils.getBytes(srcPageAddr, srcOff, payloadSize);
+        long link = PageUtils.getLong(srcPageAddr, srcOff + payloadSize);
+
+        assert link != 0;
+
+        int dstOff = offset(dstIdx);
+
+        PageUtils.putBytes(dstPageAddr, dstOff, payload);
+
+        H2IOUtils.store(dstPageAddr, dstOff + payloadSize, srcIo, srcPageAddr, 
srcIdx, storeMvccInfo());
+    }
+
+    /** {@inheritDoc} */
+    @Override public final long getLink(long pageAddr, int idx) {
+        return PageUtils.getLong(pageAddr, offset(idx) + payloadSize);
+    }
+
+    /** {@inheritDoc} */
+    @Override public long getMvccCoordinatorVersion(long pageAddr, int idx) {
+        return 0;
+    }
+
+    /** {@inheritDoc} */
+    @Override public long getMvccCounter(long pageAddr, int idx) {
+        return MVCC_COUNTER_NA;
+    }
+
+    /** {@inheritDoc} */
+    @Override public long getNewMvccCoordinatorVersion(long pageAddr, int idx) 
{
+        return 0;
+    }
+
+    /** {@inheritDoc} */
+    @Override public long getNewMvccCounter(long pageAddr, int idx) {
+        return MVCC_COUNTER_NA;
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean storeMvccInfo() {
+        return false;
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/6150f3a0/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/io/AbstractH2ExtrasLeafIO.java
----------------------------------------------------------------------
diff --git 
a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/io/AbstractH2ExtrasLeafIO.java
 
b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/io/AbstractH2ExtrasLeafIO.java
new file mode 100644
index 0000000..7beecf2
--- /dev/null
+++ 
b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/io/AbstractH2ExtrasLeafIO.java
@@ -0,0 +1,187 @@
+/*
+ * 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.io;
+
+import java.util.List;
+import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.internal.pagemem.PageUtils;
+import org.apache.ignite.internal.processors.cache.persistence.tree.BPlusTree;
+import org.apache.ignite.internal.processors.cache.persistence.tree.io.BPlusIO;
+import 
org.apache.ignite.internal.processors.cache.persistence.tree.io.BPlusLeafIO;
+import 
org.apache.ignite.internal.processors.cache.persistence.tree.io.IOVersions;
+import org.apache.ignite.internal.processors.cache.persistence.tree.io.PageIO;
+import org.apache.ignite.internal.processors.query.h2.database.H2Tree;
+import 
org.apache.ignite.internal.processors.query.h2.database.InlineIndexHelper;
+import org.apache.ignite.internal.processors.query.h2.opt.GridH2Row;
+import org.apache.ignite.internal.processors.query.h2.opt.GridH2SearchRow;
+
+import static 
org.apache.ignite.internal.processors.cache.mvcc.CacheCoordinatorsProcessor.MVCC_COUNTER_NA;
+
+/**
+ * Leaf page for H2 row references.
+ */
+public class AbstractH2ExtrasLeafIO extends BPlusLeafIO<GridH2SearchRow> 
implements H2RowLinkIO {
+    /** Payload size. */
+    private final int payloadSize;
+
+    /** */
+    public static void register() {
+        register(false);
+
+        register(true);
+    }
+
+    /**
+     * @param mvcc Mvcc flag.
+     */
+    private static void register(boolean mvcc) {
+        short type = mvcc ? PageIO.T_H2_EX_REF_MVCC_LEAF_START : 
PageIO.T_H2_EX_REF_LEAF_START;
+
+        for (short payload = 1; payload <= PageIO.MAX_PAYLOAD_SIZE; payload++) 
{
+            IOVersions<? extends AbstractH2ExtrasLeafIO> io =
+                getVersions((short)(type + payload - 1), payload, mvcc);
+
+            PageIO.registerH2ExtraLeaf(io, mvcc);
+        }
+    }
+
+    /**
+     * @param payload Payload size.
+     * @param mvccEnabled Mvcc flag.
+     * @return IOVersions for given payload.
+     */
+    @SuppressWarnings("unchecked")
+    public static IOVersions<? extends BPlusLeafIO<GridH2SearchRow>> 
getVersions(int payload, boolean mvccEnabled) {
+        assert payload >= 0 && payload <= PageIO.MAX_PAYLOAD_SIZE;
+
+        if (payload == 0)
+            return mvccEnabled ? H2MvccLeafIO.VERSIONS : H2LeafIO.VERSIONS;
+        else
+            return 
(IOVersions<BPlusLeafIO<GridH2SearchRow>>)PageIO.getLeafVersions((short)(payload
 - 1), mvccEnabled);
+    }
+
+    /**
+     * @param type Type.
+     * @param payload Payload size.
+     * @param mvcc Mvcc flag.
+     * @return Versions.
+     */
+    private static IOVersions<? extends AbstractH2ExtrasLeafIO> 
getVersions(short type, short payload, boolean mvcc) {
+        return new IOVersions<>(mvcc ? new H2MvccExtrasLeafIO(type, 1, 
payload) : new H2ExtrasLeafIO(type, 1, payload));
+    }
+
+    /**
+     * @param type Page type.
+     * @param ver Page format version.
+     * @param itemSize Item size.
+     * @param payloadSize Payload size.
+     */
+    AbstractH2ExtrasLeafIO(short type, int ver, int itemSize, int payloadSize) 
{
+        super(type, ver, itemSize + payloadSize);
+
+        this.payloadSize = payloadSize;
+    }
+
+    /** {@inheritDoc} */
+    @SuppressWarnings("ForLoopReplaceableByForEach")
+    @Override public final void storeByOffset(long pageAddr, int off, 
GridH2SearchRow row) {
+        GridH2Row row0 = (GridH2Row)row;
+
+        assert row0.link() != 0;
+
+        List<InlineIndexHelper> inlineIdxs = 
InlineIndexHelper.getCurrentInlineIndexes();
+
+        assert inlineIdxs != null : "no inline index helpers";
+
+        int fieldOff = 0;
+
+        for (int i = 0; i < inlineIdxs.size(); i++) {
+            InlineIndexHelper idx = inlineIdxs.get(i);
+
+            int size = idx.put(pageAddr, off + fieldOff, 
row.getValue(idx.columnIndex()), payloadSize - fieldOff);
+
+            if (size == 0)
+                break;
+
+            fieldOff += size;
+        }
+
+        H2IOUtils.storeRow(row0, pageAddr, off + payloadSize, storeMvccInfo());
+    }
+
+    /** {@inheritDoc} */
+    @Override public final void store(long dstPageAddr, int dstIdx, 
BPlusIO<GridH2SearchRow> srcIo, long srcPageAddr, int srcIdx) {
+        int srcOff = srcIo.offset(srcIdx);
+
+        byte[] payload = PageUtils.getBytes(srcPageAddr, srcOff, payloadSize);
+        long link = PageUtils.getLong(srcPageAddr, srcOff + payloadSize);
+
+        assert link != 0;
+
+        int dstOff = offset(dstIdx);
+
+        PageUtils.putBytes(dstPageAddr, dstOff, payload);
+
+        H2IOUtils.store(dstPageAddr, dstOff + payloadSize, srcIo, srcPageAddr, 
srcIdx, storeMvccInfo());
+    }
+
+    /** {@inheritDoc} */
+    @Override public final GridH2SearchRow 
getLookupRow(BPlusTree<GridH2SearchRow, ?> tree, long pageAddr, int idx)
+        throws IgniteCheckedException {
+        long link = getLink(pageAddr, idx);
+
+        if (storeMvccInfo()) {
+            long mvccCrdVer = getMvccCoordinatorVersion(pageAddr, idx);
+            long mvccCntr = getMvccCounter(pageAddr, idx);
+
+            return ((H2Tree)tree).getRowFactory().getMvccRow(link, mvccCrdVer, 
mvccCntr);
+        }
+
+        return ((H2Tree)tree).getRowFactory().getRow(link);
+    }
+
+    /** {@inheritDoc} */
+    @Override public final long getLink(long pageAddr, int idx) {
+        return PageUtils.getLong(pageAddr, offset(idx) + payloadSize);
+    }
+
+    /** {@inheritDoc} */
+    @Override public long getMvccCoordinatorVersion(long pageAddr, int idx) {
+        return 0;
+    }
+
+    /** {@inheritDoc} */
+    @Override public long getMvccCounter(long pageAddr, int idx) {
+        return MVCC_COUNTER_NA;
+    }
+
+    /** {@inheritDoc} */
+    @Override public long getNewMvccCoordinatorVersion(long pageAddr, int idx) 
{
+        return 0;
+    }
+
+    /** {@inheritDoc} */
+    @Override public long getNewMvccCounter(long pageAddr, int idx) {
+        return MVCC_COUNTER_NA;
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean storeMvccInfo() {
+        return false;
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/6150f3a0/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/io/AbstractH2InnerIO.java
----------------------------------------------------------------------
diff --git 
a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/io/AbstractH2InnerIO.java
 
b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/io/AbstractH2InnerIO.java
new file mode 100644
index 0000000..2f12e75
--- /dev/null
+++ 
b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/io/AbstractH2InnerIO.java
@@ -0,0 +1,106 @@
+/*
+ * 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.io;
+
+import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.internal.pagemem.PageUtils;
+import org.apache.ignite.internal.processors.cache.persistence.tree.BPlusTree;
+import org.apache.ignite.internal.processors.cache.persistence.tree.io.BPlusIO;
+import 
org.apache.ignite.internal.processors.cache.persistence.tree.io.BPlusInnerIO;
+import org.apache.ignite.internal.processors.query.h2.database.H2Tree;
+import org.apache.ignite.internal.processors.query.h2.opt.GridH2Row;
+import org.apache.ignite.internal.processors.query.h2.opt.GridH2SearchRow;
+
+/**
+ * Inner page for H2 row references.
+ */
+public abstract class AbstractH2InnerIO extends BPlusInnerIO<GridH2SearchRow> 
implements H2RowLinkIO {
+    /**
+     * @param type Page type.
+     * @param ver Page format version.
+     * @param itemSize Single item size on page.
+     */
+    AbstractH2InnerIO(int type, int ver, int itemSize) {
+        super(type, ver, true, itemSize);
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean storeMvccInfo() {
+        return false;
+    }
+
+    /** {@inheritDoc} */
+    @Override public void storeByOffset(long pageAddr, int off, 
GridH2SearchRow row) {
+        GridH2Row row0 = (GridH2Row)row;
+
+        H2IOUtils.storeRow(row0, pageAddr, off, storeMvccInfo());
+    }
+
+    /** {@inheritDoc} */
+    @Override public GridH2SearchRow getLookupRow(BPlusTree<GridH2SearchRow, 
?> tree, long pageAddr, int idx)
+        throws IgniteCheckedException {
+        long link = getLink(pageAddr, idx);
+
+        if (storeMvccInfo()) {
+            long mvccCrdVer = getMvccCoordinatorVersion(pageAddr, idx);
+            long mvccCntr = getMvccCounter(pageAddr, idx);
+
+            return ((H2Tree)tree).getRowFactory().getMvccRow(link, mvccCrdVer, 
mvccCntr);
+        }
+
+        return ((H2Tree)tree).getRowFactory().getRow(link);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void store(long dstPageAddr, int dstIdx, 
BPlusIO<GridH2SearchRow> srcIo, long srcPageAddr, int srcIdx) {
+        H2IOUtils.store(dstPageAddr, offset(dstIdx), srcIo, srcPageAddr, 
srcIdx, storeMvccInfo());
+    }
+
+    /** {@inheritDoc} */
+    @Override public long getLink(long pageAddr, int idx) {
+        return PageUtils.getLong(pageAddr, offset(idx));
+    }
+
+    /** {@inheritDoc} */
+    @Override public long getMvccCoordinatorVersion(long pageAddr, int idx) {
+        assert storeMvccInfo();
+
+        return PageUtils.getLong(pageAddr, offset(idx) + 8);
+    }
+
+    /** {@inheritDoc} */
+    @Override public long getMvccCounter(long pageAddr, int idx) {
+        assert storeMvccInfo();
+
+        return PageUtils.getLong(pageAddr, offset(idx) + 16);
+    }
+
+    /** {@inheritDoc} */
+    @Override public long getNewMvccCoordinatorVersion(long pageAddr, int idx) 
{
+        assert storeMvccInfo();
+
+        return PageUtils.getLong(pageAddr, offset(idx) + 24);
+    }
+
+    /** {@inheritDoc} */
+    @Override public long getNewMvccCounter(long pageAddr, int idx) {
+        assert storeMvccInfo();
+
+        return PageUtils.getLong(pageAddr, offset(idx) + 32);
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/6150f3a0/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/io/AbstractH2LeafIO.java
----------------------------------------------------------------------
diff --git 
a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/io/AbstractH2LeafIO.java
 
b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/io/AbstractH2LeafIO.java
new file mode 100644
index 0000000..a5cf7c2
--- /dev/null
+++ 
b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/io/AbstractH2LeafIO.java
@@ -0,0 +1,108 @@
+/*
+ * 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.io;
+
+import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.internal.pagemem.PageUtils;
+import org.apache.ignite.internal.processors.cache.persistence.tree.BPlusTree;
+import org.apache.ignite.internal.processors.cache.persistence.tree.io.BPlusIO;
+import 
org.apache.ignite.internal.processors.cache.persistence.tree.io.BPlusLeafIO;
+import org.apache.ignite.internal.processors.query.h2.database.H2Tree;
+import org.apache.ignite.internal.processors.query.h2.opt.GridH2Row;
+import org.apache.ignite.internal.processors.query.h2.opt.GridH2SearchRow;
+
+/**
+ * Leaf page for H2 row references.
+ */
+public abstract class AbstractH2LeafIO extends BPlusLeafIO<GridH2SearchRow> 
implements H2RowLinkIO {
+    /**
+     * @param type Page type.
+     * @param ver Page format version.
+     * @param itemSize Single item size on page.
+     */
+    AbstractH2LeafIO(int type, int ver, int itemSize) {
+        super(type, ver, itemSize);
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean storeMvccInfo() {
+        return false;
+    }
+
+    /** {@inheritDoc} */
+    @Override public final void storeByOffset(long pageAddr, int off, 
GridH2SearchRow row) {
+        GridH2Row row0 = (GridH2Row)row;
+
+        H2IOUtils.storeRow(row0, pageAddr, off, storeMvccInfo());
+    }
+
+    /** {@inheritDoc} */
+    @Override public final void store(long dstPageAddr, int dstIdx, 
BPlusIO<GridH2SearchRow> srcIo, long srcPageAddr, int srcIdx) {
+        assert srcIo == this;
+
+        H2IOUtils.store(dstPageAddr, offset(dstIdx), srcIo, srcPageAddr, 
srcIdx, storeMvccInfo());
+    }
+
+    /** {@inheritDoc} */
+    @Override public final GridH2SearchRow 
getLookupRow(BPlusTree<GridH2SearchRow,?> tree, long pageAddr, int idx)
+        throws IgniteCheckedException {
+        long link = getLink(pageAddr, idx);
+
+        if (storeMvccInfo()) {
+            long mvccCrdVer = getMvccCoordinatorVersion(pageAddr, idx);
+            long mvccCntr = getMvccCounter(pageAddr, idx);
+
+            return ((H2Tree)tree).getRowFactory().getMvccRow(link, mvccCrdVer, 
mvccCntr);
+        }
+
+        return ((H2Tree)tree).getRowFactory().getRow(link);
+    }
+
+    /** {@inheritDoc} */
+    @Override public long getLink(long pageAddr, int idx) {
+        return PageUtils.getLong(pageAddr, offset(idx));
+    }
+
+    /** {@inheritDoc} */
+    @Override public long getMvccCoordinatorVersion(long pageAddr, int idx) {
+        assert storeMvccInfo();
+
+        return PageUtils.getLong(pageAddr, offset(idx) + 8);
+    }
+
+    /** {@inheritDoc} */
+    @Override public long getMvccCounter(long pageAddr, int idx) {
+        assert storeMvccInfo();
+
+        return PageUtils.getLong(pageAddr, offset(idx) + 16);
+    }
+
+    /** {@inheritDoc} */
+    @Override public long getNewMvccCoordinatorVersion(long pageAddr, int idx) 
{
+        assert storeMvccInfo();
+
+        return PageUtils.getLong(pageAddr, offset(idx) + 24);
+    }
+
+    /** {@inheritDoc} */
+    @Override public long getNewMvccCounter(long pageAddr, int idx) {
+        assert storeMvccInfo();
+
+        return PageUtils.getLong(pageAddr, offset(idx) + 32);
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/6150f3a0/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/io/H2ExtrasInnerIO.java
----------------------------------------------------------------------
diff --git 
a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/io/H2ExtrasInnerIO.java
 
b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/io/H2ExtrasInnerIO.java
index b8877e9..8dc8c96 100644
--- 
a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/io/H2ExtrasInnerIO.java
+++ 
b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/io/H2ExtrasInnerIO.java
@@ -17,124 +17,17 @@
 
 package org.apache.ignite.internal.processors.query.h2.database.io;
 
-import java.util.List;
-import org.apache.ignite.IgniteCheckedException;
-import org.apache.ignite.internal.pagemem.PageUtils;
-import org.apache.ignite.internal.processors.cache.persistence.tree.BPlusTree;
-import org.apache.ignite.internal.processors.cache.persistence.tree.io.BPlusIO;
-import 
org.apache.ignite.internal.processors.cache.persistence.tree.io.BPlusInnerIO;
-import 
org.apache.ignite.internal.processors.cache.persistence.tree.io.IOVersions;
-import org.apache.ignite.internal.processors.cache.persistence.tree.io.PageIO;
-import org.apache.ignite.internal.processors.query.h2.database.H2Tree;
-import 
org.apache.ignite.internal.processors.query.h2.database.InlineIndexHelper;
-import org.apache.ignite.internal.processors.query.h2.opt.GridH2Row;
-import org.h2.result.SearchRow;
-
 /**
  * Inner page for H2 row references.
  */
-public class H2ExtrasInnerIO extends BPlusInnerIO<SearchRow> {
-    /** Payload size. */
-    private final int payloadSize;
-
-    /** */
-    public static void register() {
-        for (short payload = 1; payload <= PageIO.MAX_PAYLOAD_SIZE; payload++)
-            
PageIO.registerH2ExtraInner(getVersions((short)(PageIO.T_H2_EX_REF_INNER_START 
+ payload - 1), payload));
-    }
-
-    /**
-     * @param payload Payload size.
-     * @return IOVersions for given payload.
-     */
-    @SuppressWarnings("unchecked")
-    public static IOVersions<? extends BPlusInnerIO<SearchRow>> 
getVersions(int payload) {
-        assert payload >= 0 && payload <= PageIO.MAX_PAYLOAD_SIZE;
-
-        if (payload == 0)
-            return H2InnerIO.VERSIONS;
-        else
-            return 
(IOVersions<BPlusInnerIO<SearchRow>>)PageIO.getInnerVersions((short)(payload - 
1));
-    }
-
-    /**
-     * @param type Type.
-     * @param payload Payload size.
-     * @return Instance of IO versions.
-     */
-    private static IOVersions<H2ExtrasInnerIO> getVersions(short type, short 
payload) {
-        return new IOVersions<>(new H2ExtrasInnerIO(type, 1, payload));
-    }
-
+public class H2ExtrasInnerIO extends AbstractH2ExtrasInnerIO implements 
H2RowLinkIO {
     /**
      * @param type Page type.
      * @param ver Page format version.
      * @param payloadSize Payload size.
      */
-    private H2ExtrasInnerIO(short type, int ver, int payloadSize) {
-        super(type, ver, true, 8 + payloadSize);
-        this.payloadSize = payloadSize;
-    }
-
-    /** {@inheritDoc} */
-    @SuppressWarnings("ForLoopReplaceableByForEach")
-    @Override public void storeByOffset(long pageAddr, int off, SearchRow row) 
{
-        GridH2Row row0 = (GridH2Row)row;
-
-        assert row0.link() != 0 : row0;
-
-        List<InlineIndexHelper> inlineIdxs = 
InlineIndexHelper.getCurrentInlineIndexes();
-
-        assert inlineIdxs != null : "no inline index helpers";
-
-
-        int fieldOff = 0;
-
-        for (int i = 0; i < inlineIdxs.size(); i++) {
-            InlineIndexHelper idx = inlineIdxs.get(i);
-
-            int size = idx.put(pageAddr, off + fieldOff, 
row.getValue(idx.columnIndex()), payloadSize - fieldOff);
-
-            if (size == 0)
-                break;
-
-            fieldOff += size;
-        }
-
-        PageUtils.putLong(pageAddr, off + payloadSize, row0.link());
-    }
-
-    /** {@inheritDoc} */
-    @Override public SearchRow getLookupRow(BPlusTree<SearchRow, ?> tree, long 
pageAddr, int idx)
-        throws IgniteCheckedException {
-        long link = getLink(pageAddr, idx);
-
-        assert link != 0;
-
-        return ((H2Tree)tree).getRowFactory().getRow(link);
-    }
-
-    /** {@inheritDoc} */
-    @Override public void store(long dstPageAddr, int dstIdx, 
BPlusIO<SearchRow> srcIo, long srcPageAddr, int srcIdx) {
-        int srcOff = srcIo.offset(srcIdx);
-
-        byte[] payload = PageUtils.getBytes(srcPageAddr, srcOff, payloadSize);
-        long link = PageUtils.getLong(srcPageAddr, srcOff + payloadSize);
-
-        assert link != 0;
-
-        int dstOff = offset(dstIdx);
-
-        PageUtils.putBytes(dstPageAddr, dstOff, payload);
-        PageUtils.putLong(dstPageAddr, dstOff + payloadSize, link);
-    }
-
-    /**
-     * @param pageAddr Page address.
-     * @param idx Index.
-     * @return Link to row.
-     */
-    private long getLink(long pageAddr, int idx) {
-        return PageUtils.getLong(pageAddr, offset(idx) + payloadSize);
+    H2ExtrasInnerIO(short type, int ver, int payloadSize) {
+        super(type, ver, 8, payloadSize);
     }
 }
+

http://git-wip-us.apache.org/repos/asf/ignite/blob/6150f3a0/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/io/H2ExtrasLeafIO.java
----------------------------------------------------------------------
diff --git 
a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/io/H2ExtrasLeafIO.java
 
b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/io/H2ExtrasLeafIO.java
index 6161f8d..085f98b 100644
--- 
a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/io/H2ExtrasLeafIO.java
+++ 
b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/io/H2ExtrasLeafIO.java
@@ -17,121 +17,16 @@
 
 package org.apache.ignite.internal.processors.query.h2.database.io;
 
-import java.util.List;
-import org.apache.ignite.IgniteCheckedException;
-import org.apache.ignite.internal.pagemem.PageUtils;
-import org.apache.ignite.internal.processors.cache.persistence.tree.BPlusTree;
-import org.apache.ignite.internal.processors.cache.persistence.tree.io.BPlusIO;
-import 
org.apache.ignite.internal.processors.cache.persistence.tree.io.BPlusLeafIO;
-import 
org.apache.ignite.internal.processors.cache.persistence.tree.io.IOVersions;
-import org.apache.ignite.internal.processors.cache.persistence.tree.io.PageIO;
-import org.apache.ignite.internal.processors.query.h2.database.H2Tree;
-import 
org.apache.ignite.internal.processors.query.h2.database.InlineIndexHelper;
-import org.apache.ignite.internal.processors.query.h2.opt.GridH2Row;
-import org.h2.result.SearchRow;
-
 /**
  * Leaf page for H2 row references.
  */
-public class H2ExtrasLeafIO extends BPlusLeafIO<SearchRow> {
-    /** Payload size. */
-    private final int payloadSize;
-
-    /** */
-    public static void register() {
-        for (short payload = 1; payload <= PageIO.MAX_PAYLOAD_SIZE; payload++)
-            
PageIO.registerH2ExtraLeaf(getVersions((short)(PageIO.T_H2_EX_REF_LEAF_START + 
payload - 1), payload));
-    }
-
-    /**
-     * @param payload Payload size.
-     * @return IOVersions for given payload.
-     */
-    @SuppressWarnings("unchecked")
-    public static IOVersions<? extends BPlusLeafIO<SearchRow>> getVersions(int 
payload) {
-        assert payload >= 0 && payload <= PageIO.MAX_PAYLOAD_SIZE;
-
-        if (payload == 0)
-            return H2LeafIO.VERSIONS;
-        else
-            return 
(IOVersions<BPlusLeafIO<SearchRow>>)PageIO.getLeafVersions((short)(payload - 
1));
-    }
-
-    /**
-     * @param type Type.
-     * @param payload Payload size.
-     * @return Versions.
-     */
-    private static IOVersions<H2ExtrasLeafIO> getVersions(short type, short 
payload) {
-        return new IOVersions<>(new H2ExtrasLeafIO(type, 1, payload));
-    }
-
+public class H2ExtrasLeafIO extends AbstractH2ExtrasLeafIO {
     /**
      * @param type Page type.
      * @param ver Page format version.
      * @param payloadSize Payload size.
      */
-    private H2ExtrasLeafIO(short type, int ver, int payloadSize) {
-        super(type, ver, 8 + payloadSize);
-        this.payloadSize = payloadSize;
-    }
-
-    /** {@inheritDoc} */
-    @SuppressWarnings("ForLoopReplaceableByForEach")
-    @Override public void storeByOffset(long pageAddr, int off, SearchRow row) 
{
-        GridH2Row row0 = (GridH2Row)row;
-
-        assert row0.link() != 0;
-
-        List<InlineIndexHelper> inlineIdxs = 
InlineIndexHelper.getCurrentInlineIndexes();
-
-        assert inlineIdxs != null : "no inline index helpers";
-
-        int fieldOff = 0;
-
-        for (int i = 0; i < inlineIdxs.size(); i++) {
-            InlineIndexHelper idx = inlineIdxs.get(i);
-
-            int size = idx.put(pageAddr, off + fieldOff, 
row.getValue(idx.columnIndex()), payloadSize - fieldOff);
-
-            if (size == 0)
-                break;
-
-            fieldOff += size;
-        }
-
-        PageUtils.putLong(pageAddr, off + payloadSize, row0.link());
-    }
-
-    /** {@inheritDoc} */
-    @Override public void store(long dstPageAddr, int dstIdx, 
BPlusIO<SearchRow> srcIo, long srcPageAddr, int srcIdx) {
-        int srcOff = srcIo.offset(srcIdx);
-
-        byte[] payload = PageUtils.getBytes(srcPageAddr, srcOff, payloadSize);
-        long link = PageUtils.getLong(srcPageAddr, srcOff + payloadSize);
-
-        assert link != 0;
-
-        int dstOff = offset(dstIdx);
-
-        PageUtils.putBytes(dstPageAddr, dstOff, payload);
-        PageUtils.putLong(dstPageAddr, dstOff + payloadSize, link);
-    }
-
-    /** {@inheritDoc} */
-    @Override public SearchRow getLookupRow(BPlusTree<SearchRow, ?> tree, long 
pageAddr, int idx)
-        throws IgniteCheckedException {
-        long link = getLink(pageAddr, idx);
-
-        return ((H2Tree)tree).getRowFactory().getRow(link);
-    }
-
-    /**
-     * @param pageAddr Page address.
-     * @param idx Index.
-     * @return Link to row.
-     */
-    private long getLink(long pageAddr, int idx) {
-        return PageUtils.getLong(pageAddr, offset(idx) + payloadSize);
+    H2ExtrasLeafIO(short type, int ver, int payloadSize) {
+        super(type, ver, 8, payloadSize);
     }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/6150f3a0/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/io/H2IOUtils.java
----------------------------------------------------------------------
diff --git 
a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/io/H2IOUtils.java
 
b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/io/H2IOUtils.java
new file mode 100644
index 0000000..c0b2314
--- /dev/null
+++ 
b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/io/H2IOUtils.java
@@ -0,0 +1,113 @@
+/*
+ * 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.io;
+
+import org.apache.ignite.internal.pagemem.PageUtils;
+import org.apache.ignite.internal.processors.cache.persistence.tree.io.BPlusIO;
+import org.apache.ignite.internal.processors.query.h2.opt.GridH2Row;
+import org.apache.ignite.internal.processors.query.h2.opt.GridH2SearchRow;
+
+import static 
org.apache.ignite.internal.processors.cache.mvcc.CacheCoordinatorsProcessor.assertMvccVersionValid;
+
+/**
+ *
+ */
+class H2IOUtils {
+    /**
+     *
+     */
+    private H2IOUtils() {}
+
+    /**
+     * @param row Row.
+     * @param pageAddr Page address.
+     * @param off Offset.
+     * @param storeMvcc {@code True} to store mvcc data.
+     */
+    static void storeRow(GridH2Row row, long pageAddr, int off, boolean 
storeMvcc) {
+        assert row.link() != 0;
+
+        PageUtils.putLong(pageAddr, off, row.link());
+
+        if (storeMvcc) {
+            long mvccCrdVer = row.mvccCoordinatorVersion();
+            long mvccCntr = row.mvccCounter();
+
+            assert assertMvccVersionValid(mvccCrdVer, mvccCntr);
+
+            PageUtils.putLong(pageAddr, off + 8, mvccCrdVer);
+            PageUtils.putLong(pageAddr, off + 16, mvccCntr);
+
+            long newMvccCrdVer = row.newMvccCoordinatorVersion();
+
+            PageUtils.putLong(pageAddr, off + 24, newMvccCrdVer);
+
+            if (newMvccCrdVer != 0) {
+                long newMvccCntr = row.newMvccCounter();
+
+                assert assertMvccVersionValid(newMvccCrdVer, newMvccCntr);
+
+                PageUtils.putLong(pageAddr, off + 32, newMvccCntr);
+            }
+        }
+    }
+
+    /**
+     * @param dstPageAddr Destination page address.
+     * @param dstOff Destination page offset.
+     * @param srcIo Source IO.
+     * @param srcPageAddr Source page address.
+     * @param srcIdx Source index.
+     * @param storeMvcc {@code True} to store mvcc data.
+     */
+    static void store(long dstPageAddr,
+        int dstOff,
+        BPlusIO<GridH2SearchRow> srcIo,
+        long srcPageAddr,
+        int srcIdx,
+        boolean storeMvcc)
+    {
+        H2RowLinkIO rowIo = (H2RowLinkIO)srcIo;
+
+        long link = rowIo.getLink(srcPageAddr, srcIdx);
+
+        PageUtils.putLong(dstPageAddr, dstOff, link);
+
+        if (storeMvcc) {
+            long mvccCrdVer = rowIo.getMvccCoordinatorVersion(srcPageAddr, 
srcIdx);
+            long mvccCntr = rowIo.getMvccCounter(srcPageAddr, srcIdx);
+
+            assert assertMvccVersionValid(mvccCrdVer, mvccCntr);
+
+            PageUtils.putLong(dstPageAddr, dstOff + 8, mvccCrdVer);
+            PageUtils.putLong(dstPageAddr, dstOff + 16, mvccCntr);
+
+            long newMvccCrdVer = 
rowIo.getNewMvccCoordinatorVersion(srcPageAddr, srcIdx);
+
+            PageUtils.putLong(dstPageAddr, dstOff + 24, newMvccCrdVer);
+
+            if (newMvccCrdVer != 0) {
+                long newMvccCntr = rowIo.getNewMvccCounter(srcPageAddr, 
srcIdx);
+
+                assertMvccVersionValid(newMvccCrdVer, newMvccCntr);
+
+                PageUtils.putLong(dstPageAddr, dstOff + 32, newMvccCntr);
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/6150f3a0/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/io/H2InnerIO.java
----------------------------------------------------------------------
diff --git 
a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/io/H2InnerIO.java
 
b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/io/H2InnerIO.java
index a1f1ce9..9baff7a 100644
--- 
a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/io/H2InnerIO.java
+++ 
b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/io/H2InnerIO.java
@@ -17,20 +17,12 @@
 
 package org.apache.ignite.internal.processors.query.h2.database.io;
 
-import org.apache.ignite.IgniteCheckedException;
-import org.apache.ignite.internal.pagemem.PageUtils;
-import org.apache.ignite.internal.processors.cache.persistence.tree.BPlusTree;
-import org.apache.ignite.internal.processors.cache.persistence.tree.io.BPlusIO;
-import 
org.apache.ignite.internal.processors.cache.persistence.tree.io.BPlusInnerIO;
 import 
org.apache.ignite.internal.processors.cache.persistence.tree.io.IOVersions;
-import org.apache.ignite.internal.processors.query.h2.database.H2Tree;
-import org.apache.ignite.internal.processors.query.h2.opt.GridH2Row;
-import org.h2.result.SearchRow;
 
 /**
  * Inner page for H2 row references.
  */
-public class H2InnerIO extends BPlusInnerIO<SearchRow> implements H2RowLinkIO {
+public class H2InnerIO extends AbstractH2InnerIO {
     /** */
     public static final IOVersions<H2InnerIO> VERSIONS = new IOVersions<>(
         new H2InnerIO(1)
@@ -40,35 +32,6 @@ public class H2InnerIO extends BPlusInnerIO<SearchRow> 
implements H2RowLinkIO {
      * @param ver Page format version.
      */
     private H2InnerIO(int ver) {
-        super(T_H2_REF_INNER, ver, true, 8);
-    }
-
-    /** {@inheritDoc} */
-    @Override public void storeByOffset(long pageAddr, int off, SearchRow row) 
{
-        GridH2Row row0 = (GridH2Row)row;
-
-        assert row0.link() != 0;
-
-        PageUtils.putLong(pageAddr, off, row0.link());
-    }
-
-    /** {@inheritDoc} */
-    @Override public SearchRow getLookupRow(BPlusTree<SearchRow,?> tree, long 
pageAddr, int idx)
-        throws IgniteCheckedException {
-        long link = getLink(pageAddr, idx);
-
-        return ((H2Tree)tree).getRowFactory().getRow(link);
-    }
-
-    /** {@inheritDoc} */
-    @Override public void store(long dstPageAddr, int dstIdx, 
BPlusIO<SearchRow> srcIo, long srcPageAddr, int srcIdx) {
-        long link = ((H2RowLinkIO)srcIo).getLink(srcPageAddr, srcIdx);
-
-        PageUtils.putLong(dstPageAddr, offset(dstIdx), link);
-    }
-
-    /** {@inheritDoc} */
-    @Override public long getLink(long pageAddr, int idx) {
-        return PageUtils.getLong(pageAddr, offset(idx));
+        super(T_H2_REF_INNER, ver, 8);
     }
 }

Reply via email to