Merge branch 'master' into ignite-11464-modules-indexing

# Conflicts:
#	modules/dev-utils/ignite-modules-test/src/test/java/module-info.java
#	modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java
diff --git a/modules/clients/src/test/java/org/apache/ignite/internal/jdbc2/JdbcAbstractSchemaCaseTest.java b/modules/clients/src/test/java/org/apache/ignite/internal/jdbc2/JdbcAbstractSchemaCaseTest.java
new file mode 100644
index 0000000..5995010
--- /dev/null
+++ b/modules/clients/src/test/java/org/apache/ignite/internal/jdbc2/JdbcAbstractSchemaCaseTest.java
@@ -0,0 +1,228 @@
+/*
+ * 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.jdbc2;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.Callable;
+import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.testframework.GridTestUtils;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+import org.jetbrains.annotations.NotNull;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Base (for v2 and thin drivers) test for the case (in)sensitivity of schema name.
+ */
+public abstract class JdbcAbstractSchemaCaseTest extends GridCommonAbstractTest {
+    /** Grid count. */
+    private static final int GRID_CNT = 2;
+
+    /** {@inheritDoc} */
+    @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception {
+        IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName);
+
+        cfg.setCacheConfiguration(
+            cacheConfiguration("test0", "test0"),
+            cacheConfiguration("test1", "tEst1"),
+            cacheConfiguration("test2", "\"TestCase\""));
+
+        return cfg;
+    }
+
+    /**
+     * Set up connection with specified schema as default JDBC connection schema.
+     */
+    protected abstract Connection connect(String schema) throws SQLException;
+
+    /**
+     * @param name Cache name.
+     * @param schema Schema name.
+     * @return Cache configuration.
+     * @throws Exception In case of error.
+     */
+    @SuppressWarnings("unchecked")
+    private CacheConfiguration cacheConfiguration(@NotNull String name, @NotNull String schema) throws Exception {
+        CacheConfiguration cfg = defaultCacheConfiguration();
+
+        cfg.setIndexedTypes(Integer.class, Integer.class);
+
+        cfg.setName(name);
+
+        cfg.setSqlSchema(schema);
+
+        return cfg;
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void beforeTestsStarted() throws Exception {
+        super.beforeTestsStarted();
+
+        startGridsMultiThreaded(GRID_CNT);
+    }
+
+    /**
+     * Cleanup.
+     */
+    @Before
+    public void dropTables() throws Exception {
+        List<String> schemas = getSchemasWithTestTable();
+
+        try (Connection conn = connect("PUBLIC")) {
+            Statement stmt = conn.createStatement();
+
+            for (String schema : schemas)
+                stmt.executeUpdate("DROP TABLE IF EXISTS \"" + schema + "\".TAB");
+        }
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    @SuppressWarnings({"unused"})
+    @Test
+    public void testSchemaName() throws Exception {
+        checkSchemaConnection("test0");
+        checkSchemaConnection("test1");
+        checkSchemaConnection("\"TestCase\"");
+        checkSchemaConnection("\"TEST0\"");
+        checkSchemaConnection("\"TEST1\"");
+
+        GridTestUtils.assertThrows(log, new Callable<Object>() {
+            @Override public Object call() throws Exception {
+                checkSchemaConnection("TestCase");
+
+                return null;
+            }
+        }, SQLException.class, null);
+    }
+
+    /**
+     * Check case (in)sensitivity of schema name that is specified in the connection url.
+     */
+    @Test
+    public void testSchemaNameWithCreateTableIfNotExists() throws Exception {
+        createTableWithImplicitSchema("test0");
+
+        assertTablesInSchemasPresented("TEST0"); // due to its normalized.
+
+        createTableWithImplicitSchema("test1");
+
+        assertTablesInSchemasPresented("TEST0", "TEST1");
+
+        createTableWithImplicitSchema("\"TestCase\"");
+
+        assertTablesInSchemasPresented("TEST0", "TEST1", "TestCase");
+
+        createTableWithImplicitSchema("\"TEST0\"");
+
+        assertTablesInSchemasPresented("TEST0", "TEST1", "TestCase");
+
+        createTableWithImplicitSchema("\"TEST1\"");
+
+        assertTablesInSchemasPresented("TEST0", "TEST1", "TestCase");
+
+        GridTestUtils.assertThrows(log, new Callable<Object>() {
+            @Override public Object call() throws Exception {
+                createTableWithImplicitSchema("TestCase"); // due to normalization it is converted to "TESTCASE".
+
+                return null;
+            }
+        }, SQLException.class, null);
+    }
+
+    /**
+     * @param schema Schema name.
+     * @throws SQLException If failed.
+     */
+    private void checkSchemaConnection(String schema) throws SQLException {
+        try (Connection conn = connect(schema)) {
+            Statement stmt = conn.createStatement();
+
+            assertNotNull(stmt);
+            assertFalse(stmt.isClosed());
+
+            stmt.execute("select t._key, t._val from Integer t");
+        }
+    }
+
+    /**
+     * Create table with schema that is specified in connection properties.
+     *
+     * @param schema Schema.
+     */
+    private void createTableWithImplicitSchema(String schema) throws SQLException {
+        try (Connection conn = connect(schema)) {
+            execute(conn, "CREATE TABLE IF NOT EXISTS TAB (id INT PRIMARY KEY, val INT);");
+            execute(conn, "CREATE TABLE IF NOT EXISTS TAB (id INT PRIMARY KEY, val INT);");
+            execute(conn, "CREATE TABLE IF NOT EXISTS TAB (newId VARCHAR PRIMARY KEY, val VARCHAR);");
+            execute(conn, "CREATE TABLE IF NOT EXISTS TAB (newId VARCHAR PRIMARY KEY, val VARCHAR);");
+        }
+    }
+
+    /**
+     * Shortcut to execute prepared statement.
+     */
+    private void execute(Connection conn, String sql) throws SQLException {
+        try (PreparedStatement stmt = conn.prepareStatement(sql)) {
+            stmt.execute();
+        }
+    }
+
+    /**
+     * Retrieves list of schemas, each schema contain test table "TAB".
+     */
+    List<String> getSchemasWithTestTable() throws SQLException {
+        try (Connection conn = connect("PUBLIC")) {
+            Statement stmt = conn.createStatement();
+
+            ArrayList<String> schemasWithTab = new ArrayList<>();
+
+            try (ResultSet tabs = stmt.executeQuery(
+                "SELECT SCHEMA_NAME, TABLE_NAME FROM IGNITE.TABLES " +
+                    "WHERE TABLE_NAME = 'TAB' ORDER BY SCHEMA_NAME;")) {
+                while (tabs.next())
+                    schemasWithTab.add(tabs.getString("SCHEMA_NAME"));
+            }
+
+            return schemasWithTab;
+        }
+    }
+
+    /**
+     * Assert that table with name "TAB" is presented exactly in specified schemas. Order of specified schemas is
+     * ignored.
+     *
+     * @param schemas Schemas.
+     */
+    void assertTablesInSchemasPresented(String... schemas) throws SQLException {
+        Arrays.sort(schemas);
+
+        List<String> exp = Arrays.asList(schemas);
+
+        assertEqualsCollections(exp, getSchemasWithTestTable());
+    }
+}
diff --git a/modules/clients/src/test/java/org/apache/ignite/internal/jdbc2/JdbcMetadataSelfTest.java b/modules/clients/src/test/java/org/apache/ignite/internal/jdbc2/JdbcMetadataSelfTest.java
index ad21e6a..5172cf7 100755
--- a/modules/clients/src/test/java/org/apache/ignite/internal/jdbc2/JdbcMetadataSelfTest.java
+++ b/modules/clients/src/test/java/org/apache/ignite/internal/jdbc2/JdbcMetadataSelfTest.java
@@ -495,7 +495,7 @@
     @Test
     public void testParametersMetadata() throws Exception {
         try (Connection conn = DriverManager.getConnection(BASE_URL)) {
-            conn.setSchema("pers");
+            conn.setSchema("\"pers\"");
 
             PreparedStatement stmt = conn.prepareStatement("select orgId from Person p where p.name > ? and p.orgId > ?");
 
diff --git a/modules/clients/src/test/java/org/apache/ignite/internal/jdbc2/JdbcSchemaCaseSelfTest.java b/modules/clients/src/test/java/org/apache/ignite/internal/jdbc2/JdbcSchemaCaseSelfTest.java
new file mode 100644
index 0000000..49fb9cd
--- /dev/null
+++ b/modules/clients/src/test/java/org/apache/ignite/internal/jdbc2/JdbcSchemaCaseSelfTest.java
@@ -0,0 +1,41 @@
+/*
+ * 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.jdbc2;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+
+import static org.apache.ignite.IgniteJdbcDriver.CFG_URL_PREFIX;
+
+/**
+ * Jdbc v2 test for schema name case (in)sensitivity.
+ */
+public class JdbcSchemaCaseSelfTest extends JdbcAbstractSchemaCaseTest {
+    /** JDBC URL. */
+    private static final String BASE_URL = CFG_URL_PREFIX + "cache=test0@modules/clients/src/test/config/jdbc-config.xml";
+
+    /** {@inheritDoc} */
+    @Override protected Connection connect(String schema) throws SQLException {
+        Connection conn = DriverManager.getConnection(BASE_URL);
+
+        conn.setSchema(schema);
+
+        return conn;
+    }
+}
diff --git a/modules/clients/src/test/java/org/apache/ignite/internal/processors/rest/protocols/tcp/redis/RedisProtocolGetAllAsArrayTest.java b/modules/clients/src/test/java/org/apache/ignite/internal/processors/rest/protocols/tcp/redis/RedisProtocolGetAllAsArrayTest.java
index f892ca5..608abf9 100644
--- a/modules/clients/src/test/java/org/apache/ignite/internal/processors/rest/protocols/tcp/redis/RedisProtocolGetAllAsArrayTest.java
+++ b/modules/clients/src/test/java/org/apache/ignite/internal/processors/rest/protocols/tcp/redis/RedisProtocolGetAllAsArrayTest.java
@@ -18,22 +18,13 @@
 package org.apache.ignite.internal.processors.rest.protocols.tcp.redis;
 
 import org.apache.ignite.IgniteSystemProperties;
+import org.apache.ignite.testframework.junits.WithSystemProperty;
+
+import static org.apache.ignite.IgniteSystemProperties.IGNITE_REST_GETALL_AS_ARRAY;
 
 /**
  * Test for being unaffected by {@link IgniteSystemProperties#IGNITE_REST_GETALL_AS_ARRAY}.
  */
+@WithSystemProperty(key = IGNITE_REST_GETALL_AS_ARRAY, value = "true")
 public class RedisProtocolGetAllAsArrayTest extends RedisProtocolStringSelfTest {
-    /** {@inheritDoc} */
-    @Override protected void beforeTestsStarted() throws Exception {
-        System.setProperty(IgniteSystemProperties.IGNITE_REST_GETALL_AS_ARRAY, "true");
-
-        super.beforeTestsStarted();
-    }
-
-    /** {@inheritDoc} */
-    @Override protected void afterTestsStopped() throws Exception {
-        super.afterTestsStopped();
-
-        System.clearProperty(IgniteSystemProperties.IGNITE_REST_GETALL_AS_ARRAY);
-    }
 }
diff --git a/modules/clients/src/test/java/org/apache/ignite/jdbc/AbstractJdbcPojoQuerySelfTest.java b/modules/clients/src/test/java/org/apache/ignite/jdbc/AbstractJdbcPojoQuerySelfTest.java
index a8dc862..44fa5ba 100644
--- a/modules/clients/src/test/java/org/apache/ignite/jdbc/AbstractJdbcPojoQuerySelfTest.java
+++ b/modules/clients/src/test/java/org/apache/ignite/jdbc/AbstractJdbcPojoQuerySelfTest.java
@@ -30,8 +30,6 @@
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.ConnectorConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
-import org.apache.ignite.internal.binary.BinaryMarshaller;
-import org.apache.ignite.testframework.config.GridTestProperties;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
 
 import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL;
@@ -50,13 +48,8 @@
     /** Statement. */
     protected Statement stmt;
 
-    /** */
-    private String marshallerBackup = GridTestProperties.getProperty(GridTestProperties.MARSH_CLASS_NAME);
-
     /** {@inheritDoc} */
     @Override protected IgniteConfiguration getConfiguration(String gridName) throws Exception {
-        GridTestProperties.setProperty(GridTestProperties.MARSH_CLASS_NAME, BinaryMarshaller.class.getName());
-
         IgniteConfiguration cfg = super.getConfiguration(gridName);
 
         CacheConfiguration<?,?> cache = defaultCacheConfiguration();
@@ -103,11 +96,6 @@
     }
 
     /** {@inheritDoc} */
-    @Override protected void afterTestsStopped() throws Exception {
-        GridTestProperties.setProperty(GridTestProperties.MARSH_CLASS_NAME, marshallerBackup);
-    }
-
-    /** {@inheritDoc} */
     @Override protected void beforeTest() throws Exception {
         stmt = DriverManager.getConnection(getURL()).createStatement();
 
diff --git a/modules/clients/src/test/java/org/apache/ignite/jdbc/JdbcErrorsAbstractSelfTest.java b/modules/clients/src/test/java/org/apache/ignite/jdbc/JdbcErrorsAbstractSelfTest.java
index 8915244..7235309 100644
--- a/modules/clients/src/test/java/org/apache/ignite/jdbc/JdbcErrorsAbstractSelfTest.java
+++ b/modules/clients/src/test/java/org/apache/ignite/jdbc/JdbcErrorsAbstractSelfTest.java
@@ -108,7 +108,7 @@
             "Value for INSERT, COPY, MERGE, or UPDATE must not be null");
 
         checkErrorState("INSERT INTO \"test\".INTEGER(_key, _val) values(1, 'zzz')", "0700B",
-            "Value conversion failed [from=java.lang.String, to=java.lang.Integer]");
+            "Value conversion failed [column=_VAL, from=java.lang.String, to=java.lang.Integer]");
     }
 
     /**
diff --git a/modules/clients/src/test/java/org/apache/ignite/jdbc/suite/IgniteJdbcDriverTestSuite.java b/modules/clients/src/test/java/org/apache/ignite/jdbc/suite/IgniteJdbcDriverTestSuite.java
index bdd3700..c5d56d7 100644
--- a/modules/clients/src/test/java/org/apache/ignite/jdbc/suite/IgniteJdbcDriverTestSuite.java
+++ b/modules/clients/src/test/java/org/apache/ignite/jdbc/suite/IgniteJdbcDriverTestSuite.java
@@ -21,6 +21,7 @@
 import org.apache.ignite.internal.jdbc2.JdbcBulkLoadSelfTest;
 import org.apache.ignite.internal.jdbc2.JdbcConnectionReopenTest;
 import org.apache.ignite.internal.jdbc2.JdbcDistributedJoinsQueryTest;
+import org.apache.ignite.internal.jdbc2.JdbcSchemaCaseSelfTest;
 import org.apache.ignite.jdbc.JdbcComplexQuerySelfTest;
 import org.apache.ignite.jdbc.JdbcConnectionSelfTest;
 import org.apache.ignite.jdbc.JdbcDefaultNoOpCacheTest;
@@ -75,11 +76,12 @@
 import org.apache.ignite.jdbc.thin.JdbcThinNoDefaultSchemaTest;
 import org.apache.ignite.jdbc.thin.JdbcThinPreparedStatementSelfTest;
 import org.apache.ignite.jdbc.thin.JdbcThinResultSetSelfTest;
-import org.apache.ignite.jdbc.thin.JdbcThinSchemaCaseTest;
+import org.apache.ignite.jdbc.thin.JdbcThinSchemaCaseSelfTest;
 import org.apache.ignite.jdbc.thin.JdbcThinSelectAfterAlterTable;
 import org.apache.ignite.jdbc.thin.JdbcThinStatementCancelSelfTest;
 import org.apache.ignite.jdbc.thin.JdbcThinStatementSelfTest;
 import org.apache.ignite.jdbc.thin.JdbcThinStatementTimeoutSelfTest;
+import org.apache.ignite.jdbc.thin.JdbcThinStreamingResetStreamTest;
 import org.apache.ignite.jdbc.thin.JdbcThinStreamingNotOrderedSelfTest;
 import org.apache.ignite.jdbc.thin.JdbcThinStreamingOrderedSelfTest;
 import org.apache.ignite.jdbc.thin.JdbcThinTcpIoTest;
@@ -137,12 +139,14 @@
     org.apache.ignite.internal.jdbc2.JdbcStreamingToPublicCacheTest.class,
     org.apache.ignite.internal.jdbc2.JdbcNoCacheStreamingSelfTest.class,
     JdbcBulkLoadSelfTest.class,
+    JdbcSchemaCaseSelfTest.class,
 
     JdbcBlobTest.class,
     org.apache.ignite.internal.jdbc2.JdbcStreamingSelfTest.class,
     JdbcThinStreamingNotOrderedSelfTest.class,
     JdbcThinStreamingOrderedSelfTest.class,
     JdbcThinDataPageScanPropertySelfTest.class,
+    JdbcThinStreamingResetStreamTest.class,
 
     // DDL tests.
     org.apache.ignite.internal.jdbc2.JdbcDynamicIndexAtomicPartitionedNearSelfTest.class,
@@ -165,7 +169,7 @@
     JdbcThinStatementSelfTest.class,
     JdbcThinComplexQuerySelfTest.class,
     JdbcThinNoDefaultSchemaTest.class,
-    JdbcThinSchemaCaseTest.class,
+    JdbcThinSchemaCaseSelfTest.class,
     JdbcThinEmptyCacheSelfTest.class,
     JdbcThinMetadataSelfTest.class,
     JdbcThinMetadataPrimaryKeysSelfTest.class,
diff --git a/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinBulkLoadAbstractSelfTest.java b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinBulkLoadAbstractSelfTest.java
index 525d89a..f209826 100644
--- a/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinBulkLoadAbstractSelfTest.java
+++ b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinBulkLoadAbstractSelfTest.java
@@ -537,7 +537,7 @@
 
                 return null;
             }
-        }, SQLException.class, "Value conversion failed [from=java.lang.String, to=java.lang.Integer]");
+        }, SQLException.class, "Value conversion failed [column=AGE, from=java.lang.String, to=java.lang.Integer]");
     }
 
     /**
diff --git a/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinDataPageScanPropertySelfTest.java b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinDataPageScanPropertySelfTest.java
index 40e1d78..9bd9064 100644
--- a/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinDataPageScanPropertySelfTest.java
+++ b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinDataPageScanPropertySelfTest.java
@@ -25,7 +25,6 @@
 import org.apache.ignite.IgniteCache;
 import org.apache.ignite.cache.query.FieldsQueryCursor;
 import org.apache.ignite.cache.query.SqlFieldsQuery;
-import org.apache.ignite.internal.processors.cache.mvcc.MvccQueryTracker;
 import org.apache.ignite.internal.processors.query.GridQueryCancel;
 import org.apache.ignite.internal.processors.query.GridQueryProcessor;
 import org.apache.ignite.internal.processors.query.SqlClientContext;
@@ -121,14 +120,19 @@
     private void checkDataPageScanInBatch(String qryWithParam, @Nullable Boolean dps) throws Exception {
         String params = (dps == null) ? null : "dataPageScanEnabled=" + dps;
 
+        int expCnt = 0;
+
         try (Connection conn = GridTestUtils.connect(grid(0), params)) {
             try (PreparedStatement upd = conn.prepareStatement(qryWithParam)) {
                 for (int i = 0; i < TOTAL_QUERIES_TO_EXECUTE; i++) {
                     upd.setInt(1, i);
                     upd.addBatch();
 
-                    if ((i + 1) % BATCH_SIZE == 0 || (i + 1) == TOTAL_QUERIES_TO_EXECUTE)
+                    if ((i + 1) % BATCH_SIZE == 0 || (i + 1) == TOTAL_QUERIES_TO_EXECUTE) {
                         upd.executeBatch();
+
+                        expCnt++;
+                    }
                 }
             }
         }
@@ -146,10 +150,7 @@
 
         int executed = IndexingWithQueries.queries.size();
 
-        assertTrue(
-            "Expected that there are executed at least " + TOTAL_QUERIES_TO_EXECUTE + " queries. " +
-                "But executed only " + executed,
-            executed >= TOTAL_QUERIES_TO_EXECUTE);
+        assertEquals(expCnt, executed);
 
         IndexingWithQueries.queries.clear();
     }
@@ -198,12 +199,24 @@
         static final Queue<SqlFieldsQuery> queries = new LinkedBlockingQueue<>();
 
         /** {@inheritDoc} */
-        @Override public List<FieldsQueryCursor<List<?>>> querySqlFields(String schemaName, SqlFieldsQuery qry,
-            @Nullable SqlClientContext cliCtx, boolean keepBinary, boolean failOnMultipleStmts,
-            MvccQueryTracker tracker, GridQueryCancel cancel, boolean registerAsNewQry) {
+        @Override public List<FieldsQueryCursor<List<?>>> querySqlFields(
+            String schemaName,
+            SqlFieldsQuery qry,
+            @Nullable SqlClientContext cliCtx,
+            boolean keepBinary,
+            boolean failOnMultipleStmts,
+            GridQueryCancel cancel
+        ) {
             queries.add(qry);
 
-            return super.querySqlFields(schemaName, qry, cliCtx, keepBinary, failOnMultipleStmts, tracker, cancel, registerAsNewQry);
+            return super.querySqlFields(
+                schemaName,
+                qry,
+                cliCtx,
+                keepBinary,
+                failOnMultipleStmts,
+                cancel
+            );
         }
     }
 }
diff --git a/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinSchemaCaseSelfTest.java b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinSchemaCaseSelfTest.java
new file mode 100644
index 0000000..5606c11
--- /dev/null
+++ b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinSchemaCaseSelfTest.java
@@ -0,0 +1,33 @@
+/*
+ * 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.jdbc.thin;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+import org.apache.ignite.internal.jdbc2.JdbcAbstractSchemaCaseTest;
+
+/**
+ * Jdbc thin test for schema name case (in)sensitivity.
+ */
+public class JdbcThinSchemaCaseSelfTest extends JdbcAbstractSchemaCaseTest {
+    /** {@inheritDoc} */
+    @Override protected Connection connect(String schema) throws SQLException {
+        return DriverManager.getConnection("jdbc:ignite:thin://127.0.0.1/" + schema);
+    }
+}
diff --git a/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinSchemaCaseTest.java b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinSchemaCaseTest.java
deleted file mode 100644
index c73b0d1..0000000
--- a/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinSchemaCaseTest.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * 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.jdbc.thin;
-
-import java.sql.Connection;
-import java.sql.DriverManager;
-import java.sql.SQLException;
-import java.sql.Statement;
-import java.util.concurrent.Callable;
-import org.apache.ignite.configuration.CacheConfiguration;
-import org.apache.ignite.configuration.IgniteConfiguration;
-import org.apache.ignite.testframework.GridTestUtils;
-import org.jetbrains.annotations.NotNull;
-import org.junit.Test;
-
-/**
- *
- */
-public class JdbcThinSchemaCaseTest extends JdbcThinAbstractSelfTest {
-    /** URL. */
-    private static final String URL = "jdbc:ignite:thin://127.0.0.1";
-
-    /** Grid count. */
-    private static final int GRID_CNT = 2;
-
-    /** {@inheritDoc} */
-    @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception {
-        IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName);
-
-        cfg.setCacheConfiguration(
-            cacheConfiguration("test0", "test0"),
-            cacheConfiguration("test1", "tEst1"),
-            cacheConfiguration("test2", "\"TestCase\""));
-
-        return cfg;
-    }
-
-    /**
-     * @param name Cache name.
-     * @param schema Schema name.
-     * @return Cache configuration.
-     * @throws Exception In case of error.
-     */
-    @SuppressWarnings("unchecked")
-    private CacheConfiguration cacheConfiguration(@NotNull String name, @NotNull String schema) throws Exception {
-        CacheConfiguration cfg = defaultCacheConfiguration();
-
-        cfg.setIndexedTypes(Integer.class, Integer.class);
-
-        cfg.setName(name);
-
-        cfg.setSqlSchema(schema);
-
-        return cfg;
-    }
-
-    /** {@inheritDoc} */
-    @Override protected void beforeTestsStarted() throws Exception {
-        super.beforeTestsStarted();
-
-        startGridsMultiThreaded(GRID_CNT);
-    }
-
-    /**
-     * @throws Exception If failed.
-     */
-    @SuppressWarnings({"unused"})
-    @Test
-    public void testSchemaName() throws Exception {
-        checkSchemaConnection("test0");
-        checkSchemaConnection("test1");
-        checkSchemaConnection("\"TestCase\"");
-        checkSchemaConnection("\"TEST0\"");
-        checkSchemaConnection("\"TEST1\"");
-
-        GridTestUtils.assertThrows(log, new Callable<Object>() {
-            @Override public Object call() throws Exception {
-                checkSchemaConnection("TestCase");
-
-                return null;
-            }
-        }, SQLException.class, null);
-    }
-
-    /**
-     * @param schema Schema name.
-     * @throws SQLException If failed.
-     */
-    void checkSchemaConnection(String schema) throws SQLException {
-        try (Connection conn = DriverManager.getConnection(URL + '/' + schema)) {
-            Statement stmt = conn.createStatement();
-
-            assertNotNull(stmt);
-            assertFalse(stmt.isClosed());
-
-            stmt.execute("select t._key, t._val from Integer t");
-        }
-    }
-}
diff --git a/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinStreamingAbstractSelfTest.java b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinStreamingAbstractSelfTest.java
index 5929839..71b5049 100644
--- a/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinStreamingAbstractSelfTest.java
+++ b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinStreamingAbstractSelfTest.java
@@ -32,7 +32,6 @@
 import org.apache.ignite.cache.query.FieldsQueryCursor;
 import org.apache.ignite.cache.query.SqlFieldsQuery;
 import org.apache.ignite.internal.jdbc2.JdbcStreamingSelfTest;
-import org.apache.ignite.internal.processors.cache.mvcc.MvccQueryTracker;
 import org.apache.ignite.internal.processors.query.GridQueryCancel;
 import org.apache.ignite.internal.processors.query.GridQueryProcessor;
 import org.apache.ignite.internal.processors.query.SqlClientContext;
@@ -517,13 +516,24 @@
         }
 
         /** {@inheritDoc} */
-        @Override public List<FieldsQueryCursor<List<?>>> querySqlFields(String schemaName, SqlFieldsQuery qry,
-            @Nullable SqlClientContext cliCtx, boolean keepBinary, boolean failOnMultipleStmts, MvccQueryTracker tracker,
-            GridQueryCancel cancel, boolean registerAsNewQry) {
+        @Override public List<FieldsQueryCursor<List<?>>> querySqlFields(
+            String schemaName,
+            SqlFieldsQuery qry,
+            @Nullable SqlClientContext cliCtx,
+            boolean keepBinary,
+            boolean failOnMultipleStmts,
+            GridQueryCancel cancel
+        ) {
             IndexingWithContext.cliCtx = cliCtx;
 
-            return super.querySqlFields(schemaName, qry, cliCtx, keepBinary, failOnMultipleStmts, tracker, cancel,
-                registerAsNewQry);
+            return super.querySqlFields(
+                schemaName,
+                qry,
+                cliCtx,
+                keepBinary,
+                failOnMultipleStmts,
+                cancel
+            );
         }
     }
 }
diff --git a/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinStreamingResetStreamTest.java b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinStreamingResetStreamTest.java
new file mode 100644
index 0000000..54a3c7d
--- /dev/null
+++ b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinStreamingResetStreamTest.java
@@ -0,0 +1,142 @@
+/*
+ * 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.jdbc.thin;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.PreparedStatement;
+import java.util.Properties;
+import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+import org.junit.Test;
+
+/**
+ * Test JDBC streaming with restart / reset multiple times.
+ */
+public class JdbcThinStreamingResetStreamTest extends GridCommonAbstractTest {
+    /** JDBC URL. */
+    private static final String URL = "jdbc:ignite:thin://127.0.0.1/";
+
+    /** JDBC Connection. */
+    private Connection conn;
+
+    /** {@inheritDoc} */
+    @Override protected void beforeTestsStarted() throws Exception {
+        super.beforeTestsStarted();
+
+        startGrids(3);
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void afterTestsStopped() throws Exception {
+        stopAllGrids();
+
+        super.afterTestsStopped();
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void beforeTest() throws Exception {
+        super.beforeTest();
+
+        conn = DriverManager.getConnection(URL, new Properties());
+
+        conn.prepareStatement("CREATE TABLE test(id LONG PRIMARY KEY, val0 VARCHAR, val1 VARCHAR) " +
+            "WITH \"template=replicated\"").execute();
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void afterTest() throws Exception {
+        try {
+            conn.prepareStatement("SET STREAMING OFF").execute();
+            conn.prepareStatement("DROP TABLE test").execute();
+        }
+        finally {
+            U.close(conn, log);
+        }
+
+        super.afterTest();
+    }
+
+    /**
+     * @throws Exception On fails.
+     */
+    @Test
+    public void testOrdered() throws Exception {
+        checkStreamReset(true);
+    }
+
+    /**
+     * @throws Exception On fails.
+     */
+    @Test
+    public void testNotOrdered() throws Exception {
+        checkStreamReset(false);
+    }
+
+    /**
+     * @throws Exception On fails.
+     */
+    @Test
+    public void testOrderedResetWorkerCreationRace() throws Exception {
+        final long BATCH_SIZE = 2;
+        final long ITERATIONS = 1000;
+
+        for (int iter = 0; iter < ITERATIONS; ++iter) {
+            conn.prepareStatement("SET STREAMING ON BATCH_SIZE " + BATCH_SIZE + " ORDERED").execute();
+
+            String sql = "INSERT INTO test (id, val0, val1) VALUES (?, ?, ?)";
+
+            PreparedStatement ps = conn.prepareStatement(sql);
+
+            ps.setInt(1, (int)Math.round(Math.random()));
+            ps.setString(2, String.valueOf(Math.random()));
+            ps.setString(3, String.valueOf(Math.random()));
+
+            ps.execute();
+        }
+    }
+
+    /**
+     * @param ordered Use ordered Stream.
+     * @throws Exception On fails.
+     */
+    public void checkStreamReset(boolean ordered) throws Exception {
+        final long BATCH_SIZE = 4096;
+        final long ROWS = BATCH_SIZE * 2 + 1;
+        final long ITERATIONS = 100;
+
+        for (int iter = 0; iter < ITERATIONS; ++iter) {
+            conn.prepareStatement("SET STREAMING ON FLUSH_FREQUENCY 1000 BATCH_SIZE " + BATCH_SIZE
+                + (ordered ? " ORDERED" : "")).execute();
+
+            String sql = "INSERT INTO test (id, val0, val1) VALUES (?, ?, ?)";
+
+            PreparedStatement ps = conn.prepareStatement(sql);
+
+            for (int i = 0; i < ROWS; i++) {
+                ps.setInt(1, i);
+                ps.setString(2, String.valueOf(Math.random()));
+                ps.setString(3, String.valueOf(Math.random()));
+
+                ps.execute();
+            }
+
+            conn.prepareStatement("SET STREAMING OFF").execute();
+        }
+    }
+}
diff --git a/modules/core/src/main/java/org/apache/ignite/IgniteCluster.java b/modules/core/src/main/java/org/apache/ignite/IgniteCluster.java
index 5d6b9f7..591fa5f 100644
--- a/modules/core/src/main/java/org/apache/ignite/IgniteCluster.java
+++ b/modules/core/src/main/java/org/apache/ignite/IgniteCluster.java
@@ -26,7 +26,6 @@
 import org.apache.ignite.cluster.ClusterGroup;
 import org.apache.ignite.cluster.ClusterNode;
 import org.apache.ignite.cluster.ClusterStartNodeResult;
-import org.apache.ignite.internal.cluster.DistributedBaselineConfiguration;
 import org.apache.ignite.lang.IgniteAsyncSupport;
 import org.apache.ignite.lang.IgniteAsyncSupported;
 import org.apache.ignite.lang.IgniteFuture;
@@ -533,9 +532,29 @@
     public boolean isWalEnabled(String cacheName);
 
     /**
-     * All distributed properties of baseline.
-     *
-     * @return Distributed baseline configuration.
+     * @return Value of manual baseline control or auto adjusting baseline. {@code True} If cluster in auto-adjust.
+     * {@code False} If cluster in manuale.
      */
-    public DistributedBaselineConfiguration baselineConfiguration();
+    public boolean isBaselineAutoAdjustEnabled();
+
+    /**
+     * @param baselineAutoAdjustEnabled Value of manual baseline control or auto adjusting baseline. {@code True} If
+     * cluster in auto-adjust. {@code False} If cluster in manuale.
+     * @throws IgniteException If operation failed.
+     */
+    public void baselineAutoAdjustEnabled(boolean baselineAutoAdjustEnabled) throws IgniteException;
+
+    /**
+     * @return Value of time which we would wait before the actual topology change since last server topology change
+     * (node join/left/fail).
+     * @throws IgniteException If operation failed.
+     */
+    public long baselineAutoAdjustTimeout();
+
+    /**
+     * @param baselineAutoAdjustTimeout Value of time which we would wait before the actual topology change since last
+     * server topology change (node join/left/fail).
+     * @throws IgniteException If failed.
+     */
+    public void baselineAutoAdjustTimeout(long baselineAutoAdjustTimeout) throws IgniteException;
 }
diff --git a/modules/core/src/main/java/org/apache/ignite/IgniteSystemProperties.java b/modules/core/src/main/java/org/apache/ignite/IgniteSystemProperties.java
index ff58c60..9f1e063 100644
--- a/modules/core/src/main/java/org/apache/ignite/IgniteSystemProperties.java
+++ b/modules/core/src/main/java/org/apache/ignite/IgniteSystemProperties.java
@@ -1143,6 +1143,11 @@
     public static final String IGNITE_DIAGNOSTIC_WARN_LIMIT = "IGNITE_DIAGNOSTIC_WARN_LIMIT";
 
     /**
+     * Allow use composite _key, _val columns at the INSERT/UPDATE/MERGE statements.
+     */
+    public static final String IGNITE_SQL_ALLOW_KEY_VAL_UPDATES = "IGNITE_SQL_ALLOW_KEY_VAL_UPDATES";
+
+    /**
      * Enforces singleton.
      */
     private IgniteSystemProperties() {
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java b/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java
index 9ef9429..9462c50 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java
@@ -136,10 +136,12 @@
 import org.apache.ignite.internal.processors.cache.persistence.filename.PdsConsistentIdProcessor;
 import org.apache.ignite.internal.processors.cacheobject.IgniteCacheObjectProcessor;
 import org.apache.ignite.internal.processors.closure.GridClosureProcessor;
+import org.apache.ignite.internal.processors.cluster.BaselineConfigurationMXBeanImpl;
 import org.apache.ignite.internal.processors.cluster.ClusterProcessor;
 import org.apache.ignite.internal.processors.cluster.DiscoveryDataClusterState;
 import org.apache.ignite.internal.processors.cluster.GridClusterStateProcessor;
 import org.apache.ignite.internal.processors.cluster.IGridClusterStateProcessor;
+import org.apache.ignite.internal.processors.configuration.distributed.DistributedConfigurationProcessor;
 import org.apache.ignite.internal.processors.continuous.GridContinuousProcessor;
 import org.apache.ignite.internal.processors.datastreamer.DataStreamProcessor;
 import org.apache.ignite.internal.processors.datastructures.DataStructuresProcessor;
@@ -149,7 +151,6 @@
 import org.apache.ignite.internal.processors.job.GridJobProcessor;
 import org.apache.ignite.internal.processors.jobmetrics.GridJobMetricsProcessor;
 import org.apache.ignite.internal.processors.marshaller.GridMarshallerMappingProcessor;
-import org.apache.ignite.internal.processors.configuration.distributed.DistributedConfigurationProcessor;
 import org.apache.ignite.internal.processors.metastorage.persistence.DistributedMetaStorageImpl;
 import org.apache.ignite.internal.processors.nodevalidation.DiscoveryNodeValidationProcessor;
 import org.apache.ignite.internal.processors.nodevalidation.OsDiscoveryNodeValidationProcessor;
@@ -208,6 +209,7 @@
 import org.apache.ignite.marshaller.MarshallerExclusions;
 import org.apache.ignite.marshaller.MarshallerUtils;
 import org.apache.ignite.marshaller.jdk.JdkMarshaller;
+import org.apache.ignite.mxbean.BaselineConfigurationMXBean;
 import org.apache.ignite.mxbean.ClusterMetricsMXBean;
 import org.apache.ignite.mxbean.DataStorageMXBean;
 import org.apache.ignite.mxbean.FailureHandlingMxBean;
@@ -4406,6 +4408,10 @@
             DataStorageMXBean dataStorageMXBean = new DataStorageMXBeanImpl(ctx);
             registerMBean("DataStorage", dataStorageMXBean.getClass().getSimpleName(), dataStorageMXBean, DataStorageMXBean.class);
 
+            // Baseline configuration
+            BaselineConfigurationMXBean baselineConfigurationMXBean = new BaselineConfigurationMXBeanImpl(ctx);
+            registerMBean("Baseline", baselineConfigurationMXBean.getClass().getSimpleName(), baselineConfigurationMXBean, BaselineConfigurationMXBean.class);
+
             // Executors
             registerExecutorMBean("GridUtilityCacheExecutor", utilityCachePool);
             registerExecutorMBean("GridExecutionExecutor", execSvc);
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/cluster/IgniteClusterAsyncImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/cluster/IgniteClusterAsyncImpl.java
index 60eec0b..f35c06a 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/cluster/IgniteClusterAsyncImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/cluster/IgniteClusterAsyncImpl.java
@@ -361,8 +361,41 @@
     }
 
     /** {@inheritDoc} */
-    @Override public DistributedBaselineConfiguration baselineConfiguration() {
-        return cluster.baselineConfiguration();
+    @Override public boolean isBaselineAutoAdjustEnabled() {
+        return cluster.isBaselineAutoAdjustEnabled();
+    }
+
+    /** {@inheritDoc} */
+    @Override public void baselineAutoAdjustEnabled(boolean baselineAutoAdjustEnabled) throws IgniteException {
+        cluster.baselineAutoAdjustEnabled(baselineAutoAdjustEnabled);
+    }
+
+    /**
+     * @param baselineAutoAdjustEnabled Value of manual baseline control or auto adjusting baseline. {@code True} If
+     * cluster in auto-adjust. {@code False} If cluster in manuale.
+     * @return Future for await operation completion.
+     */
+    public IgniteFuture<?> baselineAutoAdjustEnabledAsync(boolean baselineAutoAdjustEnabled) {
+        return cluster.baselineAutoAdjustEnabledAsync(baselineAutoAdjustEnabled);
+    }
+
+    /** {@inheritDoc} */
+    @Override public long baselineAutoAdjustTimeout() {
+        return cluster.baselineAutoAdjustTimeout();
+    }
+
+    /** {@inheritDoc} */
+    @Override public void baselineAutoAdjustTimeout(long baselineAutoAdjustTimeout) throws IgniteException {
+        cluster.baselineAutoAdjustTimeout(baselineAutoAdjustTimeout);
+    }
+
+    /**
+     * @param baselineAutoAdjustTimeout Value of time which we would wait before the actual topology change since last
+     * server topology change (node join/left/fail).
+     * @return Future for await operation completion.
+     */
+    public IgniteFuture<?> baselineAutoAdjustTimeoutAsync(long baselineAutoAdjustTimeout) {
+        return cluster.baselineAutoAdjustTimeoutAsync(baselineAutoAdjustTimeout);
     }
 
     /** {@inheritDoc} */
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/cluster/IgniteClusterImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/cluster/IgniteClusterImpl.java
index 2eaf715..a3ee11a 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/cluster/IgniteClusterImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/cluster/IgniteClusterImpl.java
@@ -51,6 +51,7 @@
 import org.apache.ignite.internal.processors.cluster.BaselineTopology;
 import org.apache.ignite.internal.util.future.GridCompoundFuture;
 import org.apache.ignite.internal.util.future.GridFinishedFuture;
+import org.apache.ignite.internal.util.future.GridFutureAdapter;
 import org.apache.ignite.internal.util.future.IgniteFutureImpl;
 import org.apache.ignite.internal.util.nodestart.IgniteRemoteStartSpecification;
 import org.apache.ignite.internal.util.nodestart.IgniteSshHelper;
@@ -603,6 +604,68 @@
     }
 
     /** {@inheritDoc} */
+    @Override public boolean isBaselineAutoAdjustEnabled() {
+        return distributedBaselineConfiguration.isBaselineAutoAdjustEnabled();
+    }
+
+    /** {@inheritDoc} */
+    @Override public void baselineAutoAdjustEnabled(boolean baselineAutoAdjustEnabled) {
+        baselineAutoAdjustEnabledAsync(baselineAutoAdjustEnabled).get();
+    }
+
+    /**
+     * @param baselineAutoAdjustEnabled Value of manual baseline control or auto adjusting baseline. {@code True} If
+     * cluster in auto-adjust. {@code False} If cluster in manuale.
+     * @return Future for await operation completion.
+     */
+    public IgniteFuture<?> baselineAutoAdjustEnabledAsync(boolean baselineAutoAdjustEnabled) {
+        guard();
+
+        try {
+            return new IgniteFutureImpl<>(
+                distributedBaselineConfiguration.updateBaselineAutoAdjustEnabledAsync(baselineAutoAdjustEnabled));
+        }
+        catch (IgniteCheckedException e) {
+            throw U.convertException(e);
+        }
+        finally {
+            unguard();
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override public long baselineAutoAdjustTimeout() {
+        return distributedBaselineConfiguration.getBaselineAutoAdjustTimeout();
+    }
+
+    /** {@inheritDoc} */
+    @Override public void baselineAutoAdjustTimeout(long baselineAutoAdjustTimeout) {
+        baselineAutoAdjustTimeoutAsync(baselineAutoAdjustTimeout).get();
+    }
+
+    /**
+     * @param baselineAutoAdjustTimeout Value of time which we would wait before the actual topology change since last
+     * server topology change (node join/left/fail).
+     * @return Future for await operation completion.
+     */
+    public IgniteFuture<?> baselineAutoAdjustTimeoutAsync(long baselineAutoAdjustTimeout) {
+        A.ensure(baselineAutoAdjustTimeout >= 0, "timeout should be positive or zero");
+
+        guard();
+
+        try {
+            return new IgniteFutureImpl<>(
+                distributedBaselineConfiguration.updateBaselineAutoAdjustTimeoutAsync(baselineAutoAdjustTimeout));
+        }
+        catch (IgniteCheckedException e) {
+            throw U.convertException(e);
+        }
+        finally {
+            unguard();
+        }
+    }
+
+    /** {@inheritDoc} */
     @Override public boolean isAsync() {
         return false;
     }
@@ -820,6 +883,13 @@
         this.reconnecFut = reconnecFut;
     }
 
+    /**
+     * @return Baseline configuration.
+     */
+    public DistributedBaselineConfiguration baselineConfiguration() {
+        return distributedBaselineConfiguration;
+    }
+
     /** {@inheritDoc} */
     @Nullable @Override public IgniteFuture<?> clientReconnectFuture() {
         return reconnecFut;
@@ -841,11 +911,6 @@
     }
 
     /** {@inheritDoc} */
-    @Override public DistributedBaselineConfiguration baselineConfiguration() {
-        return distributedBaselineConfiguration;
-    }
-
-    /** {@inheritDoc} */
     @Override public String toString() {
         return "IgniteCluster [igniteInstanceName=" + ctx.igniteInstanceName() + ']';
     }
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/commandline/Arguments.java b/modules/core/src/main/java/org/apache/ignite/internal/commandline/Arguments.java
index abd27bd..b16a142 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/commandline/Arguments.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/commandline/Arguments.java
@@ -18,6 +18,7 @@
 package org.apache.ignite.internal.commandline;
 
 import org.apache.ignite.internal.client.GridClientConfiguration;
+import org.apache.ignite.internal.commandline.baseline.BaselineArguments;
 import org.apache.ignite.internal.commandline.cache.CacheArguments;
 import org.apache.ignite.internal.visor.tx.VisorTxTaskArg;
 
@@ -44,14 +45,9 @@
     private boolean autoConfirmation;
 
     /**
-     * Action for baseline command.
-     */
-    private String baselineAct;
-
-    /**
      * Arguments for baseline command.
      */
-    private String baselineArgs;
+    private BaselineArguments baselineArgs;
 
     /** Transaction arguments. */
     private final VisorTxTaskArg txArg;
@@ -110,7 +106,6 @@
      * @param port Port.
      * @param user User.
      * @param pwd Password.
-     * @param baselineAct Baseline action.
      * @param baselineArgs Baseline args.
      * @param txArg TX arg.
      * @param cacheArgs --cache subcommand arguments.
@@ -129,8 +124,8 @@
      * @param sslTrustStorePassword Truststore Password.
      * @param sslTrustStoreType Truststore Type.
      */
-    public Arguments(Command cmd, String host, String port, String user, String pwd, String baselineAct,
-        String baselineArgs, VisorTxTaskArg txArg, CacheArguments cacheArgs, String walAct, String walArgs,
+    public Arguments(Command cmd, String host, String port, String user, String pwd,
+        BaselineArguments baselineArgs, VisorTxTaskArg txArg, CacheArguments cacheArgs, String walAct, String walArgs,
         Long pingTimeout, Long pingInterval, boolean autoConfirmation,
         String sslProtocol, String sslCipherSuites, String sslKeyAlgorithm,
         String sslKeyStorePath, char[] sslKeyStorePassword, String sslKeyStoreType,
@@ -142,7 +137,6 @@
         this.user = user;
         this.pwd = pwd;
 
-        this.baselineAct = baselineAct;
         this.baselineArgs = baselineArgs;
 
         this.txArg = txArg;
@@ -219,16 +213,9 @@
     }
 
     /**
-     * @return baseline action
+     * @return Baseline arguments.
      */
-    public String baselineAction() {
-        return baselineAct;
-    }
-
-    /**
-     * @return baseline arguments
-     */
-    public String baselineArguments() {
+    public BaselineArguments baselineArguments() {
         return baselineArgs;
     }
 
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/commandline/CommandHandler.java b/modules/core/src/main/java/org/apache/ignite/internal/commandline/CommandHandler.java
index d8bc471..4ef435d 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/commandline/CommandHandler.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/commandline/CommandHandler.java
@@ -56,6 +56,9 @@
 import org.apache.ignite.internal.client.impl.connection.GridClientConnectionResetException;
 import org.apache.ignite.internal.client.ssl.GridSslBasicContextFactory;
 import org.apache.ignite.internal.commandline.argument.CommandArgUtils;
+import org.apache.ignite.internal.commandline.baseline.AutoAdjustCommandArg;
+import org.apache.ignite.internal.commandline.baseline.BaselineArguments;
+import org.apache.ignite.internal.commandline.baseline.BaselineCommand;
 import org.apache.ignite.internal.commandline.cache.CacheArguments;
 import org.apache.ignite.internal.commandline.cache.CacheCommand;
 import org.apache.ignite.internal.commandline.cache.argument.DistributionCommandArg;
@@ -134,6 +137,7 @@
 import org.apache.ignite.plugin.security.SecurityCredentialsProvider;
 import org.apache.ignite.ssl.SslContextFactory;
 
+import static java.lang.Boolean.TRUE;
 import static org.apache.ignite.IgniteSystemProperties.IGNITE_ENABLE_EXPERIMENTAL_COMMAND;
 import static org.apache.ignite.internal.IgniteVersionUtils.ACK_VER_STR;
 import static org.apache.ignite.internal.IgniteVersionUtils.COPYRIGHT;
@@ -146,6 +150,7 @@
 import static org.apache.ignite.internal.commandline.Command.WAL;
 import static org.apache.ignite.internal.commandline.OutputFormat.MULTI_LINE;
 import static org.apache.ignite.internal.commandline.OutputFormat.SINGLE_LINE;
+import static org.apache.ignite.internal.commandline.baseline.BaselineCommand.of;
 import static org.apache.ignite.internal.commandline.cache.CacheCommand.CONTENTION;
 import static org.apache.ignite.internal.commandline.cache.CacheCommand.DISTRIBUTION;
 import static org.apache.ignite.internal.commandline.cache.CacheCommand.HELP;
@@ -165,12 +170,6 @@
 import static org.apache.ignite.internal.commandline.cache.argument.ListCommandArg.SEQUENCE;
 import static org.apache.ignite.internal.commandline.cache.argument.ValidateIndexesCommandArg.CHECK_FIRST;
 import static org.apache.ignite.internal.commandline.cache.argument.ValidateIndexesCommandArg.CHECK_THROUGH;
-import static org.apache.ignite.internal.visor.baseline.VisorBaselineOperation.ADD;
-import static org.apache.ignite.internal.visor.baseline.VisorBaselineOperation.AUTOADJUST;
-import static org.apache.ignite.internal.visor.baseline.VisorBaselineOperation.COLLECT;
-import static org.apache.ignite.internal.visor.baseline.VisorBaselineOperation.REMOVE;
-import static org.apache.ignite.internal.visor.baseline.VisorBaselineOperation.SET;
-import static org.apache.ignite.internal.visor.baseline.VisorBaselineOperation.VERSION;
 import static org.apache.ignite.internal.visor.verify.VisorViewCacheCmd.CACHES;
 import static org.apache.ignite.internal.visor.verify.VisorViewCacheCmd.GROUPS;
 import static org.apache.ignite.internal.visor.verify.VisorViewCacheCmd.SEQ;
@@ -280,30 +279,6 @@
     public static final String CONFIRM_MSG = "y";
 
     /** */
-    private static final String BASELINE_ADD = "add";
-
-    /** */
-    private static final String BASELINE_REMOVE = "remove";
-
-    /** */
-    private static final String BASELINE_COLLECT = "collect";
-
-    /** */
-    private static final String BASELINE_SET = "set";
-
-    /** */
-    private static final String BASELINE_SET_VERSION = "version";
-
-    /** */
-    private static final String BASELINE_AUTO_ADJUST = "autoadjust";
-
-    /** */
-    private static final String BASELINE_AUTO_ADJUST_ENABLE = "enable";
-
-    /** */
-    private static final String BASELINE_AUTO_ADJUST_DISABLE = "disable";
-
-    /** */
     static final String WAL_PRINT = "print";
 
     /** */
@@ -571,7 +546,7 @@
                 break;
 
             case BASELINE:
-                if (!BASELINE_COLLECT.equals(args.baselineAction()))
+                if (BaselineCommand.COLLECT != args.baselineArguments().getCmd())
                     str = "Warning: the command will perform changes in baseline.";
 
                 break;
@@ -694,8 +669,7 @@
             .flatMap(node -> Stream.concat(
                 node.tcpAddresses() == null ? Stream.empty() : node.tcpAddresses().stream(),
                 node.tcpHostNames() == null ? Stream.empty() : node.tcpHostNames().stream()
-            )
-            .map(addr -> new IgniteBiTuple<>(node, addr + ":" + node.tcpPort())));
+            ).map(addr -> new IgniteBiTuple<>(node, addr + ":" + node.tcpPort())));
     }
 
     /**
@@ -713,7 +687,7 @@
                         node.tcpAddresses() == null ? Stream.empty() : node.tcpAddresses().stream(),
                         node.tcpHostNames() == null ? Stream.empty() : node.tcpHostNames().stream()
                     )
-                    .map(addr -> addr + ":" + node.tcpPort()).collect(Collectors.toList())
+                        .map(addr -> addr + ":" + node.tcpPort()).collect(Collectors.toList())
                 )
             );
     }
@@ -1214,7 +1188,7 @@
         IdleVerifyResultV2 res = executeTask(
             client,
             VisorIdleVerifyTaskV2.class,
-            new VisorIdleVerifyTaskArg(cacheArgs.caches(),cacheArgs.excludeCaches(), cacheArgs.idleCheckCrc())
+            new VisorIdleVerifyTaskArg(cacheArgs.caches(), cacheArgs.excludeCaches(), cacheArgs.idleCheckCrc())
         );
 
         res.print(System.out::print);
@@ -1224,86 +1198,59 @@
      * Change baseline.
      *
      * @param client Client.
-     * @param baselineAct Baseline action to execute.  @throws GridClientException If failed to execute baseline
-     * action.
      * @param baselineArgs Baseline action arguments.
      * @throws Throwable If failed to execute baseline action.
      */
-    private void baseline(GridClient client, String baselineAct, String baselineArgs) throws Throwable {
-        switch (baselineAct) {
-            case BASELINE_ADD:
-                baselineAdd(client, baselineArgs);
-                break;
+    private void baseline(GridClient client, BaselineArguments baselineArgs) throws Throwable {
+        try {
+            VisorBaselineTaskResult res = executeTask(client, VisorBaselineTask.class, toVisorArguments(baselineArgs));
 
-            case BASELINE_REMOVE:
-                baselineRemove(client, baselineArgs);
-                break;
+            baselinePrint0(res);
+        }
+        catch (Throwable e) {
+            log("Failed to execute baseline command='" + baselineArgs.getCmd().text() + "'", e);
 
-            case BASELINE_SET:
-                baselineSet(client, baselineArgs);
-                break;
-
-            case BASELINE_SET_VERSION:
-                baselineVersion(client, baselineArgs);
-                break;
-
-            case BASELINE_AUTO_ADJUST:
-                baselineAutoAdjust(client, baselineArgs);
-                break;
-
-            case BASELINE_COLLECT:
-                baselinePrint(client);
-                break;
+            throw e;
         }
     }
 
     /**
      * Prepare task argument.
      *
-     * @param op Operation.
-     * @param s Argument from command line.
+     * @param args Argument from command line.
      * @return Task argument.
      */
-    private VisorBaselineTaskArg arg(VisorBaselineOperation op, String s) {
-        switch (op) {
+    private VisorBaselineTaskArg toVisorArguments(BaselineArguments args) {
+        VisorBaselineAutoAdjustSettings settings = args.getCmd() == BaselineCommand.AUTO_ADJUST
+            ? new VisorBaselineAutoAdjustSettings(args.getEnableAutoAdjust(), args.getSoftBaselineTimeout())
+            : null;
+
+        return new VisorBaselineTaskArg(toVisorOperation(args.getCmd()), args.getTopVer(), args.getConsistentIds(), settings);
+    }
+
+    /**
+     * Convert {@link BaselineCommand} to {@link VisorBaselineOperation}.
+     *
+     * @param baselineCommand Baseline command for convertion.
+     * @return {@link VisorBaselineOperation}.
+     */
+    private VisorBaselineOperation toVisorOperation(BaselineCommand baselineCommand) {
+        switch (baselineCommand) {
             case ADD:
+                return VisorBaselineOperation.ADD;
+            case AUTO_ADJUST:
+                return VisorBaselineOperation.AUTOADJUST;
             case REMOVE:
+                return VisorBaselineOperation.REMOVE;
             case SET:
-                List<String> consistentIds = getConsistentIds(s);
-
-                return new VisorBaselineTaskArg(op, -1, consistentIds, null);
-
+                return VisorBaselineOperation.SET;
             case VERSION:
-                try {
-                    long topVer = Long.parseLong(s);
-
-                    return new VisorBaselineTaskArg(op, topVer, null, null);
-                }
-                catch (NumberFormatException e) {
-                    throw new IllegalArgumentException("Invalid topology version: " + s, e);
-                }
-
-            case AUTOADJUST:
-                if (BASELINE_AUTO_ADJUST_DISABLE.equals(s)) {
-                    VisorBaselineAutoAdjustSettings settings = new VisorBaselineAutoAdjustSettings(false, -1);
-
-                    return new VisorBaselineTaskArg(op, -1, null, settings);
-                }
-                else {
-                    String[] argsArr = s.split(" ");
-
-                    assert argsArr.length == 2;
-
-                    VisorBaselineAutoAdjustSettings settings = new VisorBaselineAutoAdjustSettings(
-                        true,
-                        Long.parseLong(argsArr[1])
-                    );
-
-                    return new VisorBaselineTaskArg(op, -1, null, settings);
-                }
-            default:
-                return new VisorBaselineTaskArg(op, -1, null, new VisorBaselineAutoAdjustSettings(false, -1));
+                return VisorBaselineOperation.VERSION;
+            case COLLECT:
+                return VisorBaselineOperation.COLLECT;
         }
+
+        return null;
     }
 
     /**
@@ -1333,11 +1280,20 @@
         VisorBaselineAutoAdjustSettings autoAdjustSettings = res.getAutoAdjustSettings();
 
         if (autoAdjustSettings != null) {
-            log("Baseline auto adjustment " + (autoAdjustSettings.isEnabled() ? "enabled" : "disabled") +
-                ": softTimeout=" + autoAdjustSettings.getSoftTimeout()
+            log("Baseline auto adjustment " + (TRUE.equals(autoAdjustSettings.getEnabled()) ? "enabled" : "disabled")
+                + ": softTimeout=" + autoAdjustSettings.getSoftTimeout()
             );
         }
 
+        if (autoAdjustSettings.enabled) {
+            if (res.isBaselineAdjustInProgress())
+                log("Baseline auto-adjust is in progress");
+            else if (res.getRemainingTimeToBaselineAdjust() < 0)
+                log("Baseline auto-adjust are not scheduled");
+            else
+                log("Baseline auto-adjust will happen in '" + res.getRemainingTimeToBaselineAdjust() + "' ms");
+        }
+
         nl();
 
         Map<String, VisorBaselineNode> baseline = res.getBaseline();
@@ -1398,115 +1354,6 @@
     }
 
     /**
-     * Print current baseline.
-     *
-     * @param client Client.
-     */
-    private void baselinePrint(GridClient client) throws GridClientException {
-        VisorBaselineTaskResult res = executeTask(client, VisorBaselineTask.class, arg(COLLECT, ""));
-
-        baselinePrint0(res);
-    }
-
-    /**
-     * Add nodes to baseline.
-     *
-     * @param client Client.
-     * @param baselineArgs Baseline action arguments.
-     * @throws Throwable If failed to add nodes to baseline.
-     */
-    private void baselineAdd(GridClient client, String baselineArgs) throws Throwable {
-        try {
-            VisorBaselineTaskResult res = executeTask(client, VisorBaselineTask.class, arg(ADD, baselineArgs));
-
-            baselinePrint0(res);
-        }
-        catch (Throwable e) {
-            log("Failed to add nodes to baseline.");
-
-            throw e;
-        }
-    }
-
-    /**
-     * Remove nodes from baseline.
-     *
-     * @param client Client.
-     * @param consistentIds Consistent IDs.
-     * @throws Throwable If failed to remove nodes from baseline.
-     */
-    private void baselineRemove(GridClient client, String consistentIds) throws Throwable {
-        try {
-            VisorBaselineTaskResult res = executeTask(client, VisorBaselineTask.class, arg(REMOVE, consistentIds));
-
-            baselinePrint0(res);
-        }
-        catch (Throwable e) {
-            log("Failed to remove nodes from baseline.");
-
-            throw e;
-        }
-    }
-
-    /**
-     * Set baseline.
-     *
-     * @param client Client.
-     * @param consistentIds Consistent IDs.
-     * @throws Throwable If failed to set baseline.
-     */
-    private void baselineSet(GridClient client, String consistentIds) throws Throwable {
-        try {
-            VisorBaselineTaskResult res = executeTask(client, VisorBaselineTask.class, arg(SET, consistentIds));
-
-            baselinePrint0(res);
-        }
-        catch (Throwable e) {
-            log("Failed to set baseline.");
-
-            throw e;
-        }
-    }
-
-    /**
-     * Set baseline by topology version.
-     *
-     * @param client Client.
-     * @param arg Argument from command line.
-     */
-    private void baselineVersion(GridClient client, String arg) throws GridClientException {
-        try {
-            VisorBaselineTaskResult res = executeTask(client, VisorBaselineTask.class, arg(VERSION, arg));
-
-            baselinePrint0(res);
-        }
-        catch (Throwable e) {
-            log("Failed to set baseline with specified topology version.");
-
-            throw e;
-        }
-    }
-
-    /**
-     * Set baseline autoadjustment settings.
-     *
-     * @param client Client.
-     * @param args Argument from command line. Either {@code disable} or {@code enable <softTimeout>}.
-     */
-    private void baselineAutoAdjust(GridClient client, String args) throws GridClientException {
-        try {
-            VisorBaselineTaskResult res = executeTask(client, VisorBaselineTask.class, arg(AUTOADJUST, args));
-
-            baselinePrint0(res);
-        }
-        catch (Throwable e) {
-            log("Failed to update baseline autoadjustment settings.");
-
-            throw e;
-        }
-    }
-
-    /**
      * Dump transactions information.
      *
      * @param client Client.
@@ -1969,10 +1816,6 @@
 
         String pwd = null;
 
-        String baselineAct = "";
-
-        String baselineArgs = "";
-
         Long pingInterval = DFLT_PING_INTERVAL;
 
         Long pingTimeout = DFLT_PING_TIMEOUT;
@@ -1985,6 +1828,8 @@
 
         CacheArguments cacheArgs = null;
 
+        BaselineArguments baselineArgs = null;
+
         List<Command> commands = new ArrayList<>();
 
         initArgIterator(rawArgs);
@@ -2036,51 +1881,7 @@
                     case BASELINE:
                         commands.add(BASELINE);
 
-                        baselineAct = BASELINE_COLLECT; //default baseline action
-
-                        str = peekNextArg();
-
-                        if (str != null) {
-                            switch (str.toLowerCase()) {
-                                case BASELINE_ADD:
-                                case BASELINE_REMOVE:
-                                case BASELINE_SET:
-                                case BASELINE_SET_VERSION:
-                                    baselineAct = nextArg("Expected baseline action");
-
-                                    baselineArgs = nextArg("Expected baseline arguments");
-
-                                    break;
-
-                                case BASELINE_AUTO_ADJUST:
-                                    baselineAct = nextArg("Expected baseline action");
-
-                                    String enableDisable = nextArg("Expected argument for baseline autoadjust (enable|disable)")
-                                        .toLowerCase();
-
-                                    if (BASELINE_AUTO_ADJUST_DISABLE.equals(enableDisable))
-                                        baselineArgs = enableDisable.toLowerCase();
-                                    else {
-                                        if (!BASELINE_AUTO_ADJUST_ENABLE.equals(enableDisable)) {
-                                            String msg = "Argument after \"--baseline autoadjust\" must be" +
-                                                " either \"enable\" or \"disable\"";
-
-                                            throw new IllegalArgumentException(msg);
-                                        }
-
-                                        long softTimeout = nextLongArg("Expected soft timeout" +
-                                            " argument for baseline autoadjust");
-
-                                        if (softTimeout < 0)
-                                            throw new IllegalArgumentException("Soft timeout value for baseline" +
-                                                " autoadjustment can't be negative");
-
-                                        baselineArgs = enableDisable + " " + softTimeout;
-                                    }
-
-                                    break;
-                            }
-                        }
+                        baselineArgs = parseAndValidateBaselineArgs();
 
                         break;
 
@@ -2228,7 +2029,7 @@
         Command cmd = commands.get(0);
 
         return new Arguments(cmd, host, port, user, pwd,
-            baselineAct, baselineArgs,
+            baselineArgs,
             txArgs, cacheArgs,
             walAct, walArgs,
             pingTimeout, pingInterval, autoConfirmation,
@@ -2238,12 +2039,62 @@
     }
 
     /**
+     * Parses and validates baseline arguments.
+     *
+     * @return --baseline subcommand arguments in case validation is successful.
+     */
+    private BaselineArguments parseAndValidateBaselineArgs() {
+        if (!hasNextSubArg())
+            return new BaselineArguments.Builder(BaselineCommand.COLLECT).build();
+
+        BaselineCommand cmd = of(nextArg("Expected baseline action"));
+
+        if (cmd == null)
+            throw new IllegalArgumentException("Expected correct baseline action");
+
+        BaselineArguments.Builder baselineArgs = new BaselineArguments.Builder(cmd);
+
+        switch (cmd) {
+            case ADD:
+            case REMOVE:
+            case SET:
+                return baselineArgs
+                    .withConsistentIds(getConsistentIds(nextArg("Expected list of consistent ids")))
+                    .build();
+            case VERSION:
+                return baselineArgs
+                    .withTopVer(nextLongArg("topology version"))
+                    .build();
+            case AUTO_ADJUST:
+                do {
+                    AutoAdjustCommandArg autoAdjustArg = CommandArgUtils.of(
+                        nextArg("Expected one of auto-adjust arguments"), AutoAdjustCommandArg.class
+                    );
+
+                    if (autoAdjustArg == null)
+                        throw new IllegalArgumentException("Expected one of auto-adjust arguments");
+
+                    if (autoAdjustArg == AutoAdjustCommandArg.ENABLE || autoAdjustArg == AutoAdjustCommandArg.DISABLE)
+                        baselineArgs.withEnable(autoAdjustArg == AutoAdjustCommandArg.ENABLE);
+
+                    if (autoAdjustArg == AutoAdjustCommandArg.TIMEOUT)
+                        baselineArgs.withSoftBaselineTimeout(nextLongArg("soft timeout"));
+                }
+                while (hasNextSubArg());
+
+                return baselineArgs.build();
+        }
+
+        return baselineArgs.build();
+    }
+
+    /**
      * Parses and validates cache arguments.
      *
      * @return --cache subcommand arguments in case validation is successful.
      */
     private CacheArguments parseAndValidateCacheArgs() {
-        if (!hasNextCacheArg()) {
+        if (!hasNextSubArg()) {
             throw new IllegalArgumentException("Arguments are expected for --cache subcommand, " +
                 "run --cache help for more info.");
         }
@@ -2266,12 +2117,12 @@
             case IDLE_VERIFY:
                 int idleVerifyArgsCnt = 3;
 
-                while (hasNextCacheArg() && idleVerifyArgsCnt-- > 0) {
+                while (hasNextSubArg() && idleVerifyArgsCnt-- > 0) {
                     String nextArg = nextArg("");
 
                     IdleVerifyCommandArg arg = CommandArgUtils.of(nextArg, IdleVerifyCommandArg.class);
 
-                    if(arg == null) {
+                    if (arg == null) {
                         if (cacheArgs.excludeCaches() != null || cacheArgs.getCacheFilterEnum() != CacheFilterEnum.ALL)
                             throw new IllegalArgumentException(ONE_CACHE_FILTER_OPT_SHOULD_USED_MSG);
 
@@ -2321,10 +2172,10 @@
             case CONTENTION:
                 cacheArgs.minQueueSize(Integer.parseInt(nextArg("Min queue size expected")));
 
-                if (hasNextCacheArg())
+                if (hasNextSubArg())
                     cacheArgs.nodeId(UUID.fromString(nextArg("")));
 
-                if (hasNextCacheArg())
+                if (hasNextSubArg())
                     cacheArgs.maxPrint(Integer.parseInt(nextArg("")));
                 else
                     cacheArgs.maxPrint(10);
@@ -2334,13 +2185,13 @@
             case VALIDATE_INDEXES:
                 int argsCnt = 0;
 
-                while (hasNextCacheArg() && argsCnt++ < 4) {
+                while (hasNextSubArg() && argsCnt++ < 4) {
                     String nextArg = nextArg("");
 
                     ValidateIndexesCommandArg arg = CommandArgUtils.of(nextArg, ValidateIndexesCommandArg.class);
 
-                    if(arg == CHECK_FIRST || arg == CHECK_THROUGH) {
-                        if (!hasNextCacheArg())
+                    if (arg == CHECK_FIRST || arg == CHECK_THROUGH) {
+                        if (!hasNextSubArg())
                             throw new IllegalArgumentException("Numeric value for '" + nextArg + "' parameter expected.");
 
                         int numVal;
@@ -2386,7 +2237,7 @@
                 if (!NULL.equals(nodeIdStr))
                     cacheArgs.nodeId(UUID.fromString(nodeIdStr));
 
-                while (hasNextCacheArg()) {
+                while (hasNextSubArg()) {
                     String nextArg = nextArg("");
 
                     DistributionCommandArg arg = CommandArgUtils.of(nextArg, DistributionCommandArg.class);
@@ -2401,7 +2252,7 @@
 
                         cacheArgs.setUserAttributes(userAttrs);
 
-                        nextArg = (hasNextCacheArg()) ? nextArg("") : null;
+                        nextArg = (hasNextSubArg()) ? nextArg("") : null;
 
                     }
 
@@ -2423,7 +2274,7 @@
 
                 OutputFormat outputFormat = SINGLE_LINE;
 
-                while (hasNextCacheArg()) {
+                while (hasNextSubArg()) {
                     String nextArg = nextArg("").toLowerCase();
 
                     ListCommandArg arg = CommandArgUtils.of(nextArg, ListCommandArg.class);
@@ -2465,16 +2316,16 @@
                 throw new IllegalArgumentException("Unknown --cache subcommand " + cmd);
         }
 
-        if (hasNextCacheArg())
+        if (hasNextSubArg())
             throw new IllegalArgumentException("Unexpected argument of --cache subcommand: " + peekNextArg());
 
         return cacheArgs;
     }
 
     /**
-     * @return <code>true</code> if there's next argument for --cache subcommand.
+     * @return <code>true</code> if there's next argument for subcommand.
      */
-    private boolean hasNextCacheArg() {
+    private boolean hasNextSubArg() {
         return hasNextArg() && Command.of(peekNextArg()) == null && !AUX_COMMANDS.contains(peekNextArg());
     }
 
@@ -2860,11 +2711,11 @@
         usage(i("Deactivate cluster:"), DEACTIVATE, op(CMD_AUTO_CONFIRMATION));
         usage(i("Print current cluster state:"), STATE);
         usage(i("Print cluster baseline topology:"), BASELINE);
-        usage(i("Add nodes into baseline topology:"), BASELINE, BASELINE_ADD, constistIds, op(CMD_AUTO_CONFIRMATION));
-        usage(i("Remove nodes from baseline topology:"), BASELINE, BASELINE_REMOVE, constistIds, op(CMD_AUTO_CONFIRMATION));
-        usage(i("Set baseline topology:"), BASELINE, BASELINE_SET, constistIds, op(CMD_AUTO_CONFIRMATION));
-        usage(i("Set baseline topology based on version:"), BASELINE, BASELINE_SET_VERSION + " topologyVersion", op(CMD_AUTO_CONFIRMATION));
-        usage(i("Set baseline autoadjustment settings:"), BASELINE, BASELINE_AUTO_ADJUST, "disable|(enable <softTimeout>)", op(CMD_AUTO_CONFIRMATION));
+        usage(i("Add nodes into baseline topology:"), BASELINE, BaselineCommand.ADD.text(), constistIds, op(CMD_AUTO_CONFIRMATION));
+        usage(i("Remove nodes from baseline topology:"), BASELINE, BaselineCommand.REMOVE.text(), constistIds, op(CMD_AUTO_CONFIRMATION));
+        usage(i("Set baseline topology:"), BASELINE, BaselineCommand.SET.text(), constistIds, op(CMD_AUTO_CONFIRMATION));
+        usage(i("Set baseline topology based on version:"), BASELINE, BaselineCommand.VERSION.text() + " topologyVersion", op(CMD_AUTO_CONFIRMATION));
+        usage(i("Set baseline autoadjustment settings:"), BASELINE, BaselineCommand.AUTO_ADJUST.text(), "disable|enable timeout <timeoutValue>", op(CMD_AUTO_CONFIRMATION));
         usage(i("List or kill transactions:"), TX, getTxOptions());
 
         if (enableExperimental) {
@@ -3021,7 +2872,7 @@
                             break;
 
                         case BASELINE:
-                            baseline(client, args.baselineAction(), args.baselineArguments());
+                            baseline(client, args.baselineArguments());
 
                             break;
 
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/commandline/baseline/AutoAdjustCommandArg.java b/modules/core/src/main/java/org/apache/ignite/internal/commandline/baseline/AutoAdjustCommandArg.java
new file mode 100644
index 0000000..7e97d1d
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/commandline/baseline/AutoAdjustCommandArg.java
@@ -0,0 +1,50 @@
+/*
+ * 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.commandline.baseline;
+
+import org.apache.ignite.internal.commandline.argument.CommandArg;
+
+/**
+ * {@link BaselineCommand#AUTO_ADJUST} command arguments.
+ */
+public enum AutoAdjustCommandArg implements CommandArg {
+    /** Enable auto-adjust. */
+    ENABLE("enable"),
+    /** Disable auto-adjust. */
+    DISABLE("disable"),
+    /** Set soft timeout. */
+    TIMEOUT("timeout");
+
+    /** Option name. */
+    private final String name;
+
+    /** */
+    AutoAdjustCommandArg(String name) {
+        this.name = name;
+    }
+
+    /** {@inheritDoc} */
+    @Override public String argName() {
+        return name;
+    }
+
+    /** {@inheritDoc} */
+    @Override public String toString() {
+        return name;
+    }
+}
\ No newline at end of file
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/commandline/baseline/BaselineArguments.java b/modules/core/src/main/java/org/apache/ignite/internal/commandline/baseline/BaselineArguments.java
new file mode 100644
index 0000000..46a9c73
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/commandline/baseline/BaselineArguments.java
@@ -0,0 +1,165 @@
+/*
+ * 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.commandline.baseline;
+
+import java.util.List;
+
+/**
+ * This class contains all possible arguments after parsing baseline command input.
+ */
+public class BaselineArguments {
+    /** Command. */
+    private BaselineCommand cmd;
+    /**
+     * {@code true} if auto-adjust should be enable, {@code false} if it should be disable, {@code null} if no operation
+     * needed.
+     */
+    private Boolean enableAutoAdjust;
+    /** New value of soft timeout. */
+    private Long softBaselineTimeout;
+    /** Requested topology version. */
+    private long topVer = -1;
+    /** List of consistent ids for operation. */
+    List<String> consistentIds;
+
+    /**
+     * @param cmd Command.
+     * @param enableAutoAdjust Auto-adjust enabled feature.
+     * @param softBaselineTimeout New value of soft timeout.
+     * @param topVer Requested topology version.
+     * @param consistentIds List of consistent ids for operation.
+     */
+    public BaselineArguments(BaselineCommand cmd, Boolean enableAutoAdjust, Long softBaselineTimeout,
+        long topVer, List<String> consistentIds) {
+        this.cmd = cmd;
+        this.enableAutoAdjust = enableAutoAdjust;
+        this.softBaselineTimeout = softBaselineTimeout;
+        this.topVer = topVer;
+        this.consistentIds = consistentIds;
+    }
+
+    /**
+     * @return Command.
+     */
+    public BaselineCommand getCmd() {
+        return cmd;
+    }
+
+    /**
+     * @return {@code true} if auto-adjust should be enable, {@code false} if it should be disable, {@code null} if no
+     * operation needed.
+     */
+    public Boolean getEnableAutoAdjust() {
+        return enableAutoAdjust;
+    }
+
+    /**
+     * @return New value of soft timeout.
+     */
+    public Long getSoftBaselineTimeout() {
+        return softBaselineTimeout;
+    }
+
+    /**
+     * @return Requested topology version.
+     */
+    public long getTopVer() {
+        return topVer;
+    }
+
+    /**
+     * @return List of consistent ids for operation.
+     */
+    public List<String> getConsistentIds() {
+        return consistentIds;
+    }
+
+    /**
+     * Builder of {@link BaselineArguments}.
+     */
+    public static class Builder {
+        /** Command. */
+        private BaselineCommand cmd;
+        /**
+         * {@code true} if auto-adjust should be enable, {@code false} if it should be disable, {@code null} if no
+         * operation needed.
+         */
+        private Boolean enable;
+        /** New value of soft timeout. */
+        private Long timeout;
+        /** Requested topology version. */
+        private long ver = -1;
+        /** List of consistent ids for operation. */
+        private List<String> ids;
+
+        /**
+         * @param cmd Command.
+         */
+        public Builder(BaselineCommand cmd) {
+            this.cmd = cmd;
+        }
+
+        /**
+         * @param enable {@code true} if auto-adjust should be enable, {@code false} if it should be disable, {@code
+         * null} if no operation needed.
+         * @return This instance for chaining.
+         */
+        public Builder withEnable(Boolean enable) {
+            this.enable = enable;
+
+            return this;
+        }
+
+        /**
+         * @param timeout New value of soft timeout.
+         * @return This instance for chaining.
+         */
+        public Builder withSoftBaselineTimeout(Long timeout) {
+            this.timeout = timeout;
+
+            return this;
+        }
+
+        /**
+         * @param ver Requested topology version.
+         * @return This instance for chaining.
+         */
+        public Builder withTopVer(long ver) {
+            this.ver = ver;
+
+            return this;
+        }
+
+        /**
+         * @param ids List of consistent ids for operation.
+         * @return This instance for chaining.
+         */
+        public Builder withConsistentIds(List<String> ids) {
+            this.ids = ids;
+
+            return this;
+        }
+
+        /**
+         * @return {@link BaselineArguments}.
+         */
+        public BaselineArguments build() {
+            return new BaselineArguments(cmd, enable, timeout, ver, ids);
+        }
+    }
+}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/commandline/baseline/BaselineCommand.java b/modules/core/src/main/java/org/apache/ignite/internal/commandline/baseline/BaselineCommand.java
new file mode 100644
index 0000000..0b3744b
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/commandline/baseline/BaselineCommand.java
@@ -0,0 +1,103 @@
+/*
+ * 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.commandline.baseline;
+
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * Set of baseline commands.
+ */
+public enum BaselineCommand {
+    /**
+     * Add nodes to baseline.
+     */
+    ADD("add"),
+
+    /**
+     * Remove nodes from baseline.
+     */
+    REMOVE("remove"),
+
+    /**
+     * Collect information about baseline.
+     */
+    COLLECT("collect"),
+
+    /**
+     * Set new baseline.
+     */
+    SET("set"),
+
+    /**
+     * Check current topology version.
+     */
+    VERSION("version"),
+
+    /**
+     * Baseline auto-adjust configuration.
+     */
+    AUTO_ADJUST("auto_adjust");
+
+    /** Enumerated values. */
+    private static final BaselineCommand[] VALS = values();
+
+    /** Name. */
+    private final String name;
+
+    /**
+     * @param name Name.
+     */
+    BaselineCommand(String name) {
+        this.name = name;
+    }
+
+    /**
+     * @param text Command text.
+     * @return Command for the text.
+     */
+    public static BaselineCommand of(String text) {
+        for (BaselineCommand cmd : BaselineCommand.values()) {
+            if (cmd.text().equalsIgnoreCase(text))
+                return cmd;
+        }
+
+        return null;
+    }
+
+    /**
+     * @return Name.
+     */
+    public String text() {
+        return name;
+    }
+
+    /**
+     * Efficiently gets enumerated value from its ordinal.
+     *
+     * @param ord Ordinal value.
+     * @return Enumerated value or {@code null} if ordinal out of range.
+     */
+    @Nullable public static BaselineCommand fromOrdinal(int ord) {
+        return ord >= 0 && ord < VALS.length ? VALS[ord] : null;
+    }
+
+    /** {@inheritDoc} */
+    @Override public String toString() {
+        return name;
+    }
+}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinConnection.java b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinConnection.java
index c4f0652..75e25fe 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinConnection.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinConnection.java
@@ -50,6 +50,7 @@
 import java.util.logging.Logger;
 import org.apache.ignite.IgniteCheckedException;
 import org.apache.ignite.cache.query.QueryCancelledException;
+import org.apache.ignite.internal.jdbc2.JdbcUtils;
 import org.apache.ignite.internal.processors.cache.query.IgniteQueryErrorCode;
 import org.apache.ignite.internal.processors.odbc.ClientListenerResponse;
 import org.apache.ignite.internal.processors.odbc.SqlStateCode;
@@ -63,7 +64,6 @@
 import org.apache.ignite.internal.processors.odbc.jdbc.JdbcResponse;
 import org.apache.ignite.internal.processors.odbc.jdbc.JdbcResult;
 import org.apache.ignite.internal.processors.odbc.jdbc.JdbcStatementType;
-import org.apache.ignite.internal.processors.query.QueryUtils;
 import org.apache.ignite.internal.sql.command.SqlCommand;
 import org.apache.ignite.internal.sql.command.SqlSetStreamingCommand;
 import org.apache.ignite.internal.util.future.GridFutureAdapter;
@@ -148,7 +148,7 @@
         autoCommit = true;
         txIsolation = Connection.TRANSACTION_NONE;
 
-        schema = normalizeSchema(connProps.getSchema());
+        schema = JdbcUtils.normalizeSchema(connProps.getSchema());
 
         cliIo = new JdbcThinTcpIo(connProps);
 
@@ -689,7 +689,7 @@
     @Override public void setSchema(String schema) throws SQLException {
         ensureNotClosed();
 
-        this.schema = normalizeSchema(schema);
+        this.schema = JdbcUtils.normalizeSchema(schema);
     }
 
     /** {@inheritDoc} */
@@ -890,26 +890,6 @@
     }
 
     /**
-     * Normalize schema name. If it is quoted - unquote and leave as is, otherwise - convert to upper case.
-     *
-     * @param schemaName Schema name.
-     * @return Normalized schema name.
-     */
-    private static String normalizeSchema(String schemaName) {
-        if (F.isEmpty(schemaName))
-            return QueryUtils.DFLT_SCHEMA;
-
-        String res;
-
-        if (schemaName.startsWith("\"") && schemaName.endsWith("\""))
-            res = schemaName.substring(1, schemaName.length() - 1);
-        else
-            res = schemaName.toUpperCase();
-
-        return res;
-    }
-
-    /**
      * Streamer state and
      */
     private class StreamState {
@@ -1101,9 +1081,10 @@
                             break;
                         }
                     }
-
-                    if (resp.status() != ClientListenerResponse.STATUS_SUCCESS)
+                    else if (resp.status() != ClientListenerResponse.STATUS_SUCCESS)
                         err = new SQLException(resp.error(), IgniteQueryErrorCode.codeToSqlState(resp.status()));
+                    else
+                        assert false : "Invalid response: " + resp;
                 }
             }
             catch (Exception e) {
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcConnection.java b/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcConnection.java
index 0409c94..e63f426 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcConnection.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcConnection.java
@@ -782,7 +782,7 @@
 
     /** {@inheritDoc} */
     @Override public void setSchema(String schemaName) throws SQLException {
-        this.schemaName = schemaName;
+        this.schemaName = JdbcUtils.normalizeSchema(schemaName);
     }
 
     /** {@inheritDoc} */
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcUtils.java
index 6f7d3a4..9c3b5a1 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcUtils.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcUtils.java
@@ -33,6 +33,7 @@
 import org.apache.ignite.internal.processors.odbc.jdbc.JdbcTableMeta;
 import org.apache.ignite.internal.processors.query.IgniteSQLException;
 import org.apache.ignite.internal.processors.query.QueryUtils;
+import org.apache.ignite.internal.util.typedef.F;
 
 import static java.sql.DatabaseMetaData.columnNullable;
 import static java.sql.DatabaseMetaData.tableIndexOther;
@@ -309,4 +310,25 @@
 
         return row;
     }
+
+
+    /**
+     * Normalize schema name. If it is quoted - unquote and leave as is, otherwise - convert to upper case.
+     *
+     * @param schemaName Schema name.
+     * @return Normalized schema name.
+     */
+    public static String normalizeSchema(String schemaName) {
+        if (F.isEmpty(schemaName))
+            return QueryUtils.DFLT_SCHEMA;
+
+        String res;
+
+        if (schemaName.startsWith("\"") && schemaName.endsWith("\""))
+            res = schemaName.substring(1, schemaName.length() - 1);
+        else
+            res = schemaName.toUpperCase();
+
+        return res;
+    }
 }
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheAdapter.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheAdapter.java
index b6dc9d6..60be9d5 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheAdapter.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheAdapter.java
@@ -4310,6 +4310,16 @@
 
                     throw e;
                 }
+                catch (RuntimeException e) {
+                    try {
+                        tx.rollback();
+                    }
+                    catch (IgniteCheckedException | AssertionError | RuntimeException e1) {
+                        U.error(log, "Failed to rollback transaction " + CU.txString(tx), e1);
+                    }
+
+                    throw e;
+                }
                 finally {
                     ctx.tm().resetContext();
 
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheContext.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheContext.java
index e0b5ee0..2943932 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheContext.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheContext.java
@@ -2227,13 +2227,13 @@
      *
      * @param affNodes All affinity nodes.
      * @param canRemap Flag indicating that 'get' should be done on a locked topology version.
-     * @param partitionId Partition ID.
+     * @param partId Partition ID.
      * @return Affinity node to get key from or {@code null} if there is no suitable alive node.
      */
     @Nullable public ClusterNode selectAffinityNodeBalanced(
         List<ClusterNode> affNodes,
         Set<ClusterNode> invalidNodes,
-        int partitionId,
+        int partId,
         boolean canRemap
     ) {
         if (!readLoadBalancingEnabled) {
@@ -2283,13 +2283,13 @@
     /**
      * Prepare affinity field for builder (if possible).
      *
-     * @param buider Builder.
+     * @param builder Builder.
      */
-    public void prepareAffinityField(BinaryObjectBuilder buider) {
+    public void prepareAffinityField(BinaryObjectBuilder builder) {
         assert binaryMarshaller();
-        assert buider instanceof BinaryObjectBuilderImpl;
+        assert builder instanceof BinaryObjectBuilderImpl;
 
-        BinaryObjectBuilderImpl builder0 = (BinaryObjectBuilderImpl)buider;
+        BinaryObjectBuilderImpl builder0 = (BinaryObjectBuilderImpl)builder;
 
         if (!cacheObjCtx.customAffinityMapper()) {
             CacheDefaultBinaryAffinityKeyMapper mapper =
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheEntryEx.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheEntryEx.java
index 7b6ab9e..9aec399 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheEntryEx.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheEntryEx.java
@@ -1203,6 +1203,17 @@
         throws IgniteCheckedException, GridCacheEntryRemovedException;
 
     /**
+     * Apply entry history if not exists.
+     *
+     * @param entries Entries.
+     * @return {@code True} if initial value was set.
+     * @throws IgniteCheckedException, If failed.
+     * @throws GridCacheEntryRemovedException, If entry has been removed.
+     */
+    public boolean mvccPreloadEntry(List<GridCacheMvccEntryInfo> entries)
+        throws IgniteCheckedException, GridCacheEntryRemovedException;
+
+    /**
      * Touch this entry in its context's eviction manager.
      *
      */
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMapEntry.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMapEntry.java
index 64e436f..a3eda18 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMapEntry.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMapEntry.java
@@ -102,6 +102,7 @@
 import org.apache.ignite.lang.IgnitePredicate;
 import org.apache.ignite.lang.IgniteUuid;
 import org.apache.ignite.thread.IgniteThread;
+import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
 import static org.apache.ignite.events.EventType.EVT_CACHE_OBJECT_EXPIRED;
@@ -3368,18 +3369,9 @@
                     }
 
                     if (cctx.mvccEnabled()) {
-                        if (preload && mvccVer != null) {
-                            cctx.offheap().mvccInitialValueIfAbsent(this,
-                                val,
-                                ver,
-                                expTime,
-                                mvccVer,
-                                newMvccVer,
-                                mvccTxState,
-                                newMvccTxState);
-                        }
-                        else
-                            cctx.offheap().mvccInitialValue(this, val, ver, expTime, mvccVer, newMvccVer);
+                        assert !preload;
+
+                        cctx.offheap().mvccInitialValue(this, val, ver, expTime, mvccVer, newMvccVer);
                     }
                     else
                         storeValue(val, expTime, ver);
@@ -3406,18 +3398,9 @@
                             }
                         }
 
-                        if (preload && mvccVer != null) {
-                            cctx.offheap().mvccInitialValueIfAbsent(this,
-                                val,
-                                ver,
-                                expTime,
-                                mvccVer,
-                                newMvccVer,
-                                mvccTxState,
-                                newMvccTxState);
-                        }
-                        else
-                            cctx.offheap().mvccInitialValue(this, val, ver, expTime, mvccVer, newMvccVer);
+                        assert !preload;
+
+                        cctx.offheap().mvccInitialValue(this, val, ver, expTime, mvccVer, newMvccVer);
                     }
                 }
                 else
@@ -6718,6 +6701,9 @@
         IgniteUuid futId,
         int batchNum)
         throws IgniteCheckedException, GridCacheEntryRemovedException {
+        assert mvccVer != null &&
+            MvccUtils.mvccVersionIsValid(mvccVer.coordinatorVersion(), mvccVer.counter(), mvccVer.operationCounter());
+        assert !F.isEmpty(entries);
 
         WALPointer logPtr = null;
 
@@ -6731,17 +6717,23 @@
         try {
             checkObsolete();
 
+            boolean walEnabled = cctx.group().persistenceEnabled() && cctx.group().walEnabled();
 
+            List<DataEntry> walEntries = walEnabled ? new ArrayList<>(entries.size() + 1) : Collections.EMPTY_LIST;
+
+            // Apply updates in reverse order (oldest is last) until any of previous versions found.
+            // If we found prev version then it means history has been actualized either with previous update
+            // or via rebalance.
             for (int i = 0; i < entries.size(); i++) {
                 GridCacheMvccEntryInfo info = (GridCacheMvccEntryInfo)entries.get(i);
 
-                if (val == null && op != DELETE && MvccUtils.compare(info.mvccVersion(),
-                    mvccVer.coordinatorVersion(),
-                    mvccVer.counter(),
-                    mvccVer.operationCounter()) == 0)
-                    val = info.value();
+                assert info.mvccTxState() == TxState.COMMITTED ||
+                    MvccUtils.compare(info, mvccVer.coordinatorVersion(), mvccVer.counter()) == 0;
+                assert info.newMvccTxState() == TxState.COMMITTED ||
+                    MvccUtils.compareNewVersion(info, mvccVer.coordinatorVersion(), mvccVer.counter()) == 0 ||
+                    info.newMvccCoordinatorVersion() == MvccUtils.MVCC_CRD_COUNTER_NA;
 
-                cctx.offheap().mvccUpdateRowWithPreloadInfo(this,
+                boolean added = cctx.offheap().mvccUpdateRowWithPreloadInfo(this,
                     info.value(),
                     info.version(),
                     info.expireTime(),
@@ -6749,45 +6741,53 @@
                     info.newMvccVersion(),
                     info.mvccTxState(),
                     info.newMvccTxState());
-            }
 
+                if (walEnabled)
+                    walEntries.add(toMvccDataEntry(info, tx));
 
-            // Assume list contains  only previous committed row and rows changed by the current tx.
-            if (!entries.isEmpty()) {
-                // Assume the oldest value is the last one.
-                GridCacheMvccEntryInfo last = (GridCacheMvccEntryInfo)entries.get(entries.size() - 1);
-
-                if (MvccUtils.compare(last.mvccVersion(),
+                if (oldVal == null
+                    && MvccUtils.compare(info.mvccVersion(),
                     mvccVer.coordinatorVersion(),
-                    mvccVer.counter(),
-                    mvccVer.operationCounter()) != 0)
-                    oldVal = last.value();
+                    mvccVer.counter()) != 0
+                    && MvccUtils.compareNewVersion(info,
+                    mvccVer.coordinatorVersion(),
+                    mvccVer.counter()) == 0)
+                    oldVal = info.value(); // Old means a value before current transaction.
+
+                if (!added)
+                    break;
             }
 
-            if (cctx.deferredDelete() && deletedUnlocked() && !detached())
-                deletedUnlocked(false);
+            GridCacheMvccEntryInfo last = (GridCacheMvccEntryInfo)entries.get(0);
 
-            long expireTime = CU.EXPIRE_TIME_ETERNAL;
-            long ttl = CU.TTL_ETERNAL;
+            if (walEnabled)
+                Collections.reverse(walEntries);
 
-            GridCacheVersion ver = tx.writeVersion();
+            if (op == DELETE) {
+                assert MvccUtils.compareNewVersion(last, mvccVer) == 0;
 
-            if (cctx.group().persistenceEnabled() && cctx.group().walEnabled())
-                logPtr = cctx.shared().wal().log(new MvccDataRecord(new MvccDataEntry(
-                    cctx.cacheId(),
-                    key,
-                    val,
-                    op,
-                    tx.nearXidVersion(),
-                    ver,
-                    CU.EXPIRE_TIME_ETERNAL,
-                    key.partition(),
-                    0L,
-                    mvccVer)));
+                if (walEnabled)
+                    walEntries.add(new MvccDataEntry(
+                        cctx.cacheId(),
+                        key,
+                        null,
+                        DELETE,
+                        tx.nearXidVersion(),
+                        last.version(),
+                        last.expireTime(),
+                        key.partition(),
+                        0,
+                        last.mvccVersion()));
+            }
+            else {
+                assert last.newMvccCoordinatorVersion() == MvccUtils.MVCC_CRD_COUNTER_NA;
+                assert MvccUtils.compare(last, mvccVer) == 0;
 
-            update(val, expireTime, ttl, ver, true);
+                val = last.value();
+            }
 
-            recordNodeId(affNodeId, topVer);
+            if (walEnabled)
+                logPtr = cctx.shared().wal().log(new MvccDataRecord(walEntries));
         }
         finally {
             if (lockedByCurrentThread()) {
@@ -6805,6 +6805,83 @@
         return res;
     }
 
+    /** {@inheritDoc} */
+    @Override public boolean mvccPreloadEntry(List<GridCacheMvccEntryInfo> entryHist)
+        throws IgniteCheckedException, GridCacheEntryRemovedException {
+        assert !entryHist.isEmpty();
+
+        WALPointer logPtr = null;
+
+        ensureFreeSpace();
+
+        boolean updated = false;
+
+        lockEntry();
+
+        try {
+            checkObsolete();
+
+            key.valueBytes(cctx.cacheObjectContext());
+
+            if (cctx.offheap().mvccApplyHistoryIfAbsent(this, entryHist)) {
+                updated = true;
+
+                if (!cctx.isNear() && cctx.group().persistenceEnabled() && cctx.group().walEnabled()) {
+                    MvccDataRecord rec;
+
+                    if (entryHist.size() == 1) {
+                        GridCacheMvccEntryInfo info = entryHist.get(0);
+
+                        rec = new MvccDataRecord(toMvccDataEntry(info, null));
+                    }
+                    else {
+                        // Batched WAL update.
+                        List<DataEntry> dataEntries = new ArrayList<>(entryHist.size());
+
+                        for (GridCacheMvccEntryInfo info : entryHist)
+                            dataEntries.add(toMvccDataEntry(info, null));
+
+                        rec = new MvccDataRecord(dataEntries);
+                    }
+
+                    logPtr = cctx.shared().wal().log(rec);
+                }
+            }
+        }
+        finally {
+            if (lockedByCurrentThread()) {
+                unlockEntry();
+
+                cctx.evicts().touch(this);
+            }
+        }
+
+        if (logPtr != null)
+            cctx.shared().wal().flush(logPtr, false);
+
+        return updated;
+    }
+
+    /**
+     * Converts mvcc entry info to WAL record entry.
+     * @param info Mvcc entry info.
+     * @return Mvcc data entry.
+     */
+    private @NotNull MvccDataEntry toMvccDataEntry(@NotNull  GridCacheMvccEntryInfo info, @Nullable IgniteInternalTx tx) {
+        return new MvccDataEntry(
+            cctx.cacheId(),
+            key,
+            info.value(),
+            CREATE,
+            tx == null ? null : tx.nearXidVersion(),
+            info.version(),
+            info.expireTime(),
+            key.partition(),
+            0,
+            info.mvccVersion()
+        );
+    }
+
     /**
      * @return Common serialization error.
      */
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMvccEntryInfo.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMvccEntryInfo.java
index b9589de..4e844f8 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMvccEntryInfo.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMvccEntryInfo.java
@@ -18,6 +18,7 @@
 package org.apache.ignite.internal.processors.cache;
 
 import java.nio.ByteBuffer;
+import org.apache.ignite.IgniteCheckedException;
 import org.apache.ignite.internal.processors.cache.mvcc.MvccUpdateVersionAware;
 import org.apache.ignite.internal.processors.cache.mvcc.MvccVersionAware;
 import org.apache.ignite.internal.util.typedef.internal.S;
@@ -36,6 +37,9 @@
     private static final long serialVersionUID = 0L;
 
     /** */
+    private static final int SIZE_OVERHEAD = 4 * 8 /* long */ + 2 * 4 /* int */;
+
+    /** */
     private long mvccCrdVer;
 
     /** */
@@ -122,6 +126,11 @@
     }
 
     /** {@inheritDoc} */
+    @Override public int marshalledSize(CacheObjectContext ctx) throws IgniteCheckedException {
+        return SIZE_OVERHEAD + super.marshalledSize(ctx);
+    }
+
+    /** {@inheritDoc} */
     @Override public boolean writeTo(ByteBuffer buf, MessageWriter writer) {
         writer.setBuffer(buf);
 
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java
index 3e3d0d4..40454fb 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java
@@ -177,6 +177,8 @@
 import org.apache.ignite.spi.discovery.DiscoveryDataBag.GridDiscoveryData;
 import org.apache.ignite.spi.discovery.DiscoveryDataBag.JoiningNodeDiscoveryData;
 import org.apache.ignite.spi.encryption.EncryptionSpi;
+import org.apache.ignite.spi.indexing.IndexingSpi;
+import org.apache.ignite.spi.indexing.noop.NoopIndexingSpi;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
@@ -188,6 +190,7 @@
 import static org.apache.ignite.cache.CacheMode.LOCAL;
 import static org.apache.ignite.cache.CacheMode.PARTITIONED;
 import static org.apache.ignite.cache.CacheMode.REPLICATED;
+import static org.apache.ignite.cache.CacheRebalanceMode.NONE;
 import static org.apache.ignite.cache.CacheRebalanceMode.SYNC;
 import static org.apache.ignite.cache.CacheWriteSynchronizationMode.FULL_ASYNC;
 import static org.apache.ignite.cache.CacheWriteSynchronizationMode.FULL_SYNC;
@@ -534,6 +537,9 @@
             assertParameter(!cc.isWriteBehindEnabled(),
                 "writeBehindEnabled cannot be used with TRANSACTIONAL_SNAPSHOT atomicity mode");
 
+            assertParameter(cc.getRebalanceMode() != NONE,
+                "Rebalance mode NONE cannot be used with TRANSACTIONAL_SNAPSHOT atomicity mode");
+
             ExpiryPolicy expPlc = null;
 
             if (cc.getExpiryPolicyFactory() instanceof FactoryBuilder.SingletonFactory)
@@ -559,6 +565,11 @@
                     ", dataRegionName=" + memPlcName + ", pageEvictionMode=" +
                     dataRegion.config().getPageEvictionMode() + ']');
             }
+
+            IndexingSpi idxSpi = ctx.config().getIndexingSpi();
+
+            assertParameter(idxSpi == null || idxSpi instanceof NoopIndexingSpi,
+                "Custom IndexingSpi cannot be used with TRANSACTIONAL_SNAPSHOT atomicity mode");
         }
 
         if (cc.isWriteBehindEnabled()) {
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManager.java
index c495e12..b7e8ec7 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManager.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManager.java
@@ -241,27 +241,14 @@
     ) throws IgniteCheckedException;
 
     /**
-     * @param entry Entry.
-     * @param val Value.
-     * @param ver Version.
-     * @param expireTime Expire time.
-     * @param mvccVer MVCC version.
-     * @param newMvccVer New MVCC version.
-     * @param txState Tx state hint for the mvcc version.
-     * @param newTxState Tx state hint for the new mvcc version.
-     * @return {@code True} if value was inserted.
-     * @throws IgniteCheckedException If failed.
+     * Tries to apply entry history.
+     * Either applies full entry history or do nothing.
+     *
+     * @param entry Entry to update.
+     * @param hist Full entry history.
+     * @return {@code True} if history applied successfully, {@code False} otherwise.
      */
-    public boolean mvccInitialValueIfAbsent(
-        GridCacheMapEntry entry,
-        @Nullable CacheObject val,
-        GridCacheVersion ver,
-        long expireTime,
-        MvccVersion mvccVer,
-        MvccVersion newMvccVer,
-        byte txState,
-        byte newTxState
-    ) throws IgniteCheckedException;
+    boolean mvccApplyHistoryIfAbsent(GridCacheMapEntry entry, List<GridCacheMvccEntryInfo> hist) throws IgniteCheckedException;
 
     /**
      * @param entry Entry.
@@ -329,6 +316,9 @@
     ) throws IgniteCheckedException;
 
     /**
+     * Apply update with full history.
+     * Note: History version may be skipped if it have already been actualized with previous update operation.
+     *
      * @param entry Entry.
      * @param val Value.
      * @param ver Version.
@@ -748,29 +738,22 @@
             MvccVersion newMvccVer) throws IgniteCheckedException;
 
         /**
+         * Tries to apply entry history.
+         * Either applies full entry history or do nothing.
+         *
          * @param cctx Cache context.
          * @param key Key.
-         * @param val Value.
-         * @param ver Version.
-         * @param mvccVer MVCC version.
-         * @param newMvccVer New MVCC version.
-         * @param txState Tx state hint for the mvcc version.
-         * @param newTxState Tx state hint for the new mvcc version.
-         * @return {@code True} if new value was inserted.
-         * @throws IgniteCheckedException If failed.
+         * @param hist Full entry history.
+         * @return {@code True} if entry history applied successfully, {@code False} otherwise.
          */
-        boolean mvccInitialValueIfAbsent(
+        boolean mvccApplyHistoryIfAbsent(
             GridCacheContext cctx,
             KeyCacheObject key,
-            @Nullable CacheObject val,
-            GridCacheVersion ver,
-            long expireTime,
-            MvccVersion mvccVer,
-            MvccVersion newMvccVer,
-            byte txState,
-            byte newTxState) throws IgniteCheckedException;
+            List<GridCacheMvccEntryInfo> hist) throws IgniteCheckedException;
 
         /**
+         * Apply update with full history.
+         * Note: History version may be skipped if it have already been actualized with previous update operation.
          *
          * @param cctx Grid cache context.
          * @param key Key.
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManagerImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManagerImpl.java
index 209c9cf..30fcb7c 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManagerImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManagerImpl.java
@@ -481,25 +481,9 @@
     }
 
     /** {@inheritDoc} */
-    @Override public boolean mvccInitialValueIfAbsent(
-        GridCacheMapEntry entry,
-        CacheObject val,
-        GridCacheVersion ver,
-        long expireTime,
-        MvccVersion mvccVer,
-        MvccVersion newMvccVer,
-        byte txState,
-        byte newTxState) throws IgniteCheckedException {
-        return dataStore(entry.localPartition()).mvccInitialValueIfAbsent(
-            entry.context(),
-            entry.key(),
-            val,
-            ver,
-            expireTime,
-            mvccVer,
-            newMvccVer,
-            txState,
-            newTxState);
+    @Override public boolean mvccApplyHistoryIfAbsent(GridCacheMapEntry entry, List<GridCacheMvccEntryInfo> hist)
+        throws IgniteCheckedException {
+        return dataStore(entry.localPartition()).mvccApplyHistoryIfAbsent(entry.cctx, entry.key(), hist);
     }
 
     /** {@inheritDoc} */
@@ -1159,7 +1143,7 @@
 
         CacheDataStore data = partitionData(part);
 
-        final GridCursor<? extends CacheDataRow> cur = data.cursor();
+        final GridCursor<? extends CacheDataRow> cur = data.cursor(CacheDataRowAdapter.RowData.FULL_WITH_HINTS);
 
         return new GridCloseableIteratorAdapter<CacheDataRow>() {
             /** */
@@ -1630,9 +1614,17 @@
         /** {@inheritDoc} */
         @Override public void invoke(GridCacheContext cctx, KeyCacheObject key, OffheapInvokeClosure c)
             throws IgniteCheckedException {
+            if (!busyLock.enterBusy())
+                throw new NodeStoppingException("Operation has been cancelled (node is stopping).");
+
             int cacheId = grp.sharedGroup() ? cctx.cacheId() : CU.UNDEFINED_CACHE_ID;
 
-            invoke0(cctx, new SearchRow(cacheId, key), c);
+            try {
+                invoke0(cctx, new SearchRow(cacheId, key), c);
+            }
+            finally {
+                busyLock.leaveBusy();
+            }
         }
 
         /**
@@ -1643,42 +1635,34 @@
          */
         private void invoke0(GridCacheContext cctx, CacheSearchRow row, OffheapInvokeClosure c)
             throws IgniteCheckedException {
-            if (!busyLock.enterBusy())
-                throw new NodeStoppingException("Operation has been cancelled (node is stopping).");
+            assert cctx.shared().database().checkpointLockIsHeldByThread();
 
-            try {
-                assert cctx.shared().database().checkpointLockIsHeldByThread();
+            dataTree.invoke(row, CacheDataRowAdapter.RowData.NO_KEY, c);
 
-                dataTree.invoke(row, CacheDataRowAdapter.RowData.NO_KEY, c);
+            switch (c.operationType()) {
+                case PUT: {
+                    assert c.newRow() != null : c;
 
-                switch (c.operationType()) {
-                    case PUT: {
-                        assert c.newRow() != null : c;
+                    CacheDataRow oldRow = c.oldRow();
 
-                        CacheDataRow oldRow = c.oldRow();
+                    finishUpdate(cctx, c.newRow(), oldRow);
 
-                        finishUpdate(cctx, c.newRow(), oldRow);
-
-                        break;
-                    }
-
-                    case REMOVE: {
-                        CacheDataRow oldRow = c.oldRow();
-
-                        finishRemove(cctx, row.key(), oldRow);
-
-                        break;
-                    }
-
-                    case NOOP:
-                        break;
-
-                    default:
-                        assert false : c.operationType();
+                    break;
                 }
-            }
-            finally {
-                busyLock.leaveBusy();
+
+                case REMOVE: {
+                    CacheDataRow oldRow = c.oldRow();
+
+                    finishRemove(cctx, row.key(), oldRow);
+
+                    break;
+                }
+
+                case NOOP:
+                    break;
+
+                default:
+                    assert false : c.operationType();
             }
         }
 
@@ -1802,19 +1786,11 @@
         }
 
         /** {@inheritDoc} */
-        @Override public boolean mvccInitialValueIfAbsent(
+        @Override public boolean mvccApplyHistoryIfAbsent(
             GridCacheContext cctx,
             KeyCacheObject key,
-            @Nullable CacheObject val,
-            GridCacheVersion ver,
-            long expireTime,
-            MvccVersion mvccVer,
-            MvccVersion newMvccVer,
-            byte txState,
-            byte newTxState)
-            throws IgniteCheckedException
-        {
-            assert mvccVer != null;
+            List<GridCacheMvccEntryInfo> hist) throws IgniteCheckedException {
+            assert !F.isEmpty(hist);
 
             if (!busyLock.enterBusy())
                 throw new NodeStoppingException("Operation has been cancelled (node is stopping).");
@@ -1825,28 +1801,53 @@
                 // Make sure value bytes initialized.
                 key.valueBytes(coCtx);
 
-                if (val != null)
-                    val.valueBytes(coCtx);
-
                 assert cctx.shared().database().checkpointLockIsHeldByThread();
 
-                MvccPutIfAbsentClosure clo = new MvccPutIfAbsentClosure(key,
-                    val,
-                    ver,
-                    partId,
-                    expireTime,
-                    cctx.cacheId(),
-                    mvccVer,
-                    newMvccVer,
-                    txState,
-                    newTxState);
+                int cacheId = grp.sharedGroup() ? cctx.cacheId() : CU.UNDEFINED_CACHE_ID;
 
-                dataTree.invoke(clo, CacheDataRowAdapter.RowData.LINK_ONLY, clo);
+                // No cursor needed here  as we won't iterate over whole page items, but just check if page has smth or not.
+                CheckHistoryExistsClosure clo = new CheckHistoryExistsClosure();
 
-                if (clo.operationType() == PUT)
-                    finishUpdate(cctx, clo, null);
+                dataTree.iterate(
+                    new MvccMaxSearchRow(cacheId, key),
+                    new MvccMinSearchRow(cacheId, key),
+                    clo
+                );
 
-                return clo.operationType() == PUT;
+                if (clo.found())
+                    return false;
+
+                for (GridCacheMvccEntryInfo info : hist) {
+                    MvccDataRow row = new MvccDataRow(key,
+                        info.value(),
+                        info.version(),
+                        partId,
+                        info.ttl(),
+                        cacheId,
+                        info.mvccVersion(),
+                        info.newMvccVersion());
+
+                    row.mvccTxState(info.mvccTxState());
+                    row.newMvccTxState(info.newMvccTxState());
+
+                    assert info.newMvccTxState() == TxState.NA || info.newMvccCoordinatorVersion() > MVCC_CRD_COUNTER_NA;
+                    assert MvccUtils.mvccVersionIsValid(info.mvccCoordinatorVersion(), info.mvccCounter(), info.mvccOperationCounter());
+
+                    if (!grp.storeCacheIdInDataPage() && cacheId != CU.UNDEFINED_CACHE_ID)
+                        row.cacheId(CU.UNDEFINED_CACHE_ID);
+
+                    rowStore.addRow(row, grp.statisticsHolderData());
+
+                    row.cacheId(cacheId);
+
+                    boolean hasOld = dataTree.putx(row);
+
+                    assert !hasOld : row;
+
+                    finishUpdate(cctx, row, null);
+                }
+
+                return true;
             }
             finally {
                 busyLock.leaveBusy();
@@ -1888,13 +1889,16 @@
                     mvccTxState,
                     newMvccTxState);
 
+                assert newMvccTxState == TxState.NA || newMvccVer.coordinatorVersion() != 0;
+                assert MvccUtils.mvccVersionIsValid(mvccVer.coordinatorVersion(), mvccVer.counter(), mvccVer.operationCounter());
+
                 invoke0(cctx, clo, clo);
+
+                return clo.operationType() == PUT;
             }
             finally {
                 busyLock.leaveBusy();
             }
-
-            return true;
         }
 
         /** {@inheritDoc} */
@@ -2030,7 +2034,7 @@
                 if (needHistory) {
                     assert updateRow.link() != 0;
 
-                    updateRow.history().add(new MvccLinkAwareSearchRow(cacheId,
+                    updateRow.history().add(0, new MvccLinkAwareSearchRow(cacheId,
                         key,
                         updateRow.mvccCoordinatorVersion(),
                         updateRow.mvccCounter(),
@@ -3000,70 +3004,6 @@
         }
 
         /**
-         * Put row if it doesn't exist yet.
-         */
-        private class MvccPutIfAbsentClosure extends MvccDataRow implements IgniteTree.InvokeClosure<CacheDataRow> {
-            /** */
-            private IgniteTree.OperationType op;
-
-            /**
-             * @param key Key.
-             * @param val Value.
-             * @param ver Version.
-             * @param part Partition.
-             * @param expireTime Expire time.
-             * @param cacheId Cache ID.
-             * @param mvccVer Mvcc version.
-             * @param newMvccVer New mvcc version.
-             * @param txState Tx state hint for mvcc version.
-             * @param newTxState Tx state hint for new mvcc version.
-             */
-            MvccPutIfAbsentClosure(KeyCacheObject key,
-                CacheObject val,
-                GridCacheVersion ver,
-                int part,
-                long expireTime,
-                int cacheId,
-                MvccVersion mvccVer,
-                MvccVersion newMvccVer,
-                byte txState,
-                byte newTxState) {
-                super(key, val, ver, part, expireTime, cacheId, mvccVer, newMvccVer);
-
-                mvccTxState(txState);
-                newMvccTxState(newTxState);
-            }
-
-            /** {@inheritDoc} */
-            @Override public void call(@Nullable CacheDataRow old) throws IgniteCheckedException {
-                if (old == null) {
-                    op = PUT;
-
-                    int cacheId = cacheId();
-
-                    if (!grp.storeCacheIdInDataPage() && cacheId != CU.UNDEFINED_CACHE_ID)
-                        cacheId(CU.UNDEFINED_CACHE_ID);
-
-                    rowStore().addRow(this, grp.statisticsHolderData());
-
-                    cacheId(cacheId);
-                }
-                else
-                    op = NOOP;
-            }
-
-            /** {@inheritDoc} */
-            @Override public MvccDataRow newRow() {
-                return this;
-            }
-
-            /** {@inheritDoc} */
-            @Override public IgniteTree.OperationType operationType() {
-                return op;
-            }
-        }
-
-        /**
          *
          */
         private class MvccUpdateRowWithPreloadInfoClosure extends MvccDataRow implements OffheapInvokeClosure {
@@ -3095,9 +3035,9 @@
                 super(key,
                     val,
                     ver,
-                    CacheDataStoreImpl.this.partId(),
+                    partId,
                     expireTime,
-                    cctx.cacheId(),
+                    grp.sharedGroup() ? cctx.cacheId() : CU.UNDEFINED_CACHE_ID,
                     mvccVer,
                     newMvccVer);
 
@@ -3150,6 +3090,29 @@
                 return op == null ? NOOP : op;
             }
         }
+
+        /**
+         *  Check if any row version exists.
+         */
+        private final class CheckHistoryExistsClosure implements BPlusTree.TreeRowClosure<CacheSearchRow, CacheDataRow> {
+            /** */
+            private boolean found;
+
+            /** {@inheritDoc} */
+            @Override public boolean apply(BPlusTree<CacheSearchRow, CacheDataRow> tree, BPlusIO<CacheSearchRow> io,
+                long pageAddr, int idx) {
+                found = true;
+
+                return false;  // Stop search.
+            }
+
+            /**
+             * @return {@code True} if any row was found, {@code False} otherwise.
+             */
+            public boolean found() {
+                return found;
+            }
+        }
     }
 
     /**
@@ -3268,8 +3231,10 @@
             assert cntr == newRow.mvccCounter();
             assert opCntr == newRow.mvccOperationCounter();
 
+            assert newRow.mvccTxState() != TxState.NA : newRow.mvccTxState();
+
             if (txState != newRow.mvccTxState() && newRow.mvccTxState() != TxState.NA) {
-                assert txState == TxState.NA;
+                assert txState == TxState.NA : txState;
 
                 iox.rawMvccOperationCounter(pageAddr, off, opCntr | (newRow.mvccTxState() << MVCC_HINTS_BIT_OFF));
 
@@ -3284,15 +3249,18 @@
                 newRow.newMvccCounter(),
                 newRow.newMvccOperationCounter()) != 0) {
 
+                assert newRow.newMvccTxState() == TxState.NA ||  newRow.newMvccCoordinatorVersion() != MVCC_CRD_COUNTER_NA;
+
                 iox.updateNewVersion(pageAddr, off, newRow.newMvccCoordinatorVersion(), newRow.newMvccCounter(),
                     newRow.newMvccOperationCounter(), newRow.newMvccTxState());
 
                 if (isWalDeltaRecordNeeded(grp.dataRegion().pageMemory(), cacheId, pageId, page, ctx.wal(), walPlc))
                     ctx.wal().log(new DataPageMvccMarkUpdatedRecord(cacheId, pageId, itemId,
-                        newRow.newMvccCoordinatorVersion(), newRow.newMvccCounter(), newRow.newMvccOperationCounter()));
+                        newRow.newMvccCoordinatorVersion(), newRow.newMvccCounter(),
+                        newRow.newMvccOperationCounter() | (newRow.newMvccTxState() << MVCC_HINTS_BIT_OFF)));
             }
             else if (newTxState != newRow.newMvccTxState() && newRow.newMvccTxState() != TxState.NA) {
-                assert newTxState == TxState.NA;
+                assert newTxState == TxState.NA : newTxState;
 
                 iox.rawNewMvccOperationCounter(pageAddr, off, newOpCntr | (newRow.newMvccTxState() << MVCC_HINTS_BIT_OFF));
 
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteRebalanceIterator.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteRebalanceIterator.java
index d2f29d5..0ccc9f7 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteRebalanceIterator.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteRebalanceIterator.java
@@ -47,4 +47,10 @@
      * @param partId Partition ID.
      */
     public void setPartitionMissing(int partId);
+
+    /**
+     * Return next element without moving iterator cursor to the next one.
+     * @return Next element or {@code Null} if there is no more elements.
+     */
+    public CacheDataRow peek();
 }
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtGetFuture.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtGetFuture.java
index 8c754f2..2a12fef 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtGetFuture.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtGetFuture.java
@@ -194,6 +194,8 @@
         // TODO get rid of force keys request https://issues.apache.org/jira/browse/IGNITE-10251
         GridDhtFuture<Object> fut = cctx.group().preloader().request(cctx, keys.keySet(), topVer);
 
+        assert !cctx.mvccEnabled() || fut == null; // Should not happen with MVCC enabled.
+
         if (fut != null) {
             if (!F.isEmpty(fut.invalidPartitions())) {
                 if (retries == null)
@@ -320,6 +322,18 @@
         try {
             int keyPart = cctx.affinity().partition(key);
 
+            if (cctx.mvccEnabled()) {
+                boolean noOwners = cctx.topology().owners(keyPart, topVer).isEmpty();
+
+                // Force key request is disabled for MVCC. So if there are no partition owners for the given key
+                // (we have a not strict partition loss policy if we've got here) we need to set flag forceKeys to true
+                // to avoid useless remapping to other non-owning partitions. For non-mvcc caches the force key request
+                // is also useless in the such situations, so the same flow is here: allegedly we've made a force key
+                // request with no results and therefore forceKeys flag may be set to true here.
+                if (noOwners)
+                    forceKeys = true;
+            }
+
             GridDhtLocalPartition part = topVer.topologyVersion() > 0 ?
                 cache().topology().localPartition(keyPart, topVer, true) :
                 cache().topology().localPartition(keyPart);
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtGetSingleFuture.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtGetSingleFuture.java
index fa15bd8..797fd66 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtGetSingleFuture.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtGetSingleFuture.java
@@ -215,6 +215,8 @@
     private void map() {
         // TODO Get rid of force keys request https://issues.apache.org/jira/browse/IGNITE-10251.
         if (cctx.group().preloader().needForceKeys()) {
+            assert !cctx.mvccEnabled();
+
             GridDhtFuture<Object> fut = cctx.group().preloader().request(
                 cctx,
                 Collections.singleton(key),
@@ -290,6 +292,18 @@
         try {
             int keyPart = cctx.affinity().partition(key);
 
+            if (cctx.mvccEnabled()) {
+                boolean noOwners = cctx.topology().owners(keyPart, topVer).isEmpty();
+
+                // Force key request is disabled for MVCC. So if there are no partition owners for the given key
+                // (we have a not strict partition loss policy if we've got here) we need to set flag forceKeys to true
+                // to avoid useless remapping to other non-owning partitions. For non-mvcc caches the force key request
+                // is also useless in the such situations, so the same flow is here: allegedly we've made a force key
+                // request with no results and therefore forceKeys flag may be set to true here.
+                if (noOwners)
+                    forceKeys = true;
+            }
+
             GridDhtLocalPartition part = topVer.topologyVersion() > 0 ?
                 cache().topology().localPartition(keyPart, topVer, true) :
                 cache().topology().localPartition(keyPart);
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 6f3153c..6b443cd 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
@@ -725,8 +725,7 @@
      * @return History entries.
      * @throws IgniteCheckedException, if failed.
      */
-    private CacheEntryInfoCollection fetchHistoryInfo(KeyCacheObject key, List<MvccLinkAwareSearchRow> hist)
-        throws IgniteCheckedException {
+    private CacheEntryInfoCollection fetchHistoryInfo(KeyCacheObject key, List<MvccLinkAwareSearchRow> hist) {
         List<GridCacheEntryInfo> res = new ArrayList<>();
 
         for (int i = 0; i < hist.size(); i++) {
@@ -736,7 +735,7 @@
                 row0.hash(),
                 row0.link(),
                 key.partition(),
-                CacheDataRowAdapter.RowData.NO_KEY,
+                CacheDataRowAdapter.RowData.NO_KEY_WITH_HINTS,
                 row0.mvccCoordinatorVersion(),
                 row0.mvccCounter(),
                 row0.mvccOperationCounter(),
@@ -745,22 +744,24 @@
 
             GridCacheMvccEntryInfo entry = new GridCacheMvccEntryInfo();
 
+            entry.cacheId(cctx.cacheId());
             entry.version(row.version());
-            entry.mvccVersion(row);
-            entry.newMvccVersion(row);
             entry.value(row.value());
             entry.expireTime(row.expireTime());
 
-            if (MvccUtils.compare(mvccSnapshot, row.mvccCoordinatorVersion(), row.mvccCounter()) != 0) {
-                entry.mvccTxState(row.mvccTxState() != TxState.NA ? row.mvccTxState() :
-                    MvccUtils.state(cctx, row.mvccCoordinatorVersion(), row.mvccCounter(), row.mvccOperationCounter()));
-            }
+            // Row should be retrieved with actual hints.
+            entry.mvccVersion(row);
+            entry.newMvccVersion(row);
 
-            if (MvccUtils.compare(mvccSnapshot, row.newMvccCoordinatorVersion(), row.newMvccCounter()) != 0) {
-                entry.newMvccTxState(row.newMvccTxState() != TxState.NA ? row.newMvccTxState() :
-                    MvccUtils.state(cctx, row.newMvccCoordinatorVersion(), row.newMvccCounter(),
-                    row.newMvccOperationCounter()));
-            }
+            if (MvccUtils.compare(mvccSnapshot, row.mvccCoordinatorVersion(), row.mvccCounter()) != 0)
+                entry.mvccTxState(row.mvccTxState());
+
+            if (row.newMvccCoordinatorVersion() != MvccUtils.MVCC_CRD_COUNTER_NA
+                && MvccUtils.compare(mvccSnapshot, row.newMvccCoordinatorVersion(), row.newMvccCounter()) != 0)
+                entry.newMvccTxState(row.newMvccTxState());
+
+
+            assert mvccSnapshot.coordinatorVersion() != MvccUtils.MVCC_CRD_COUNTER_NA;
 
             res.add(entry);
         }
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxQueryFirstEnlistRequest.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxQueryFirstEnlistRequest.java
index 53ceb05..1f96e63 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxQueryFirstEnlistRequest.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxQueryFirstEnlistRequest.java
@@ -103,6 +103,7 @@
         List<KeyCacheObject> keys,
         List<Message> vals) {
         super(cacheId, dhtFutId, lockVer, op, batchId, snapshot.operationCounter(), keys, vals);
+
         this.cacheId = cacheId;
         this.subjId = subjId;
         this.topVer = topVer;
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridPartitionedSingleGetFuture.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridPartitionedSingleGetFuture.java
index 99155dc..a82f5b5 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridPartitionedSingleGetFuture.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridPartitionedSingleGetFuture.java
@@ -228,17 +228,17 @@
      * Initialize future.
      */
     public void init() {
-        AffinityTopologyVersion mappingtopVermappingtopVer;
+        AffinityTopologyVersion mappingTopVer;
 
         if (topVer.topologyVersion() > 0)
-            mappingtopVermappingtopVer = topVer;
+            mappingTopVer = topVer;
         else {
-            mappingtopVermappingtopVer = canRemap ?
+            mappingTopVer = canRemap ?
                 cctx.affinity().affinityTopologyVersion() :
                 cctx.shared().exchange().readyAffinityVersion();
         }
 
-        map(mappingtopVermappingtopVer);
+        map(mappingTopVer);
     }
 
     /**
@@ -366,14 +366,14 @@
 
         List<ClusterNode> affNodes = cctx.affinity().nodesByPartition(part, topVer);
 
-        // Failed if none affinity node found by assigment.
+        // Failed if none affinity node found by assignment.
         if (affNodes.isEmpty()) {
             onDone(serverNotFoundError(part, topVer));
 
             return null;
         }
 
-        // Try to read key localy if we can.
+        // Try to read key locally if we can.
         if (tryLocalGet(key, part, topVer, affNodes))
             return null;
 
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtForceKeysFuture.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtForceKeysFuture.java
index 9d6c8fc..fba1d9d 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtForceKeysFuture.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtForceKeysFuture.java
@@ -235,6 +235,8 @@
         boolean ret = false;
 
         if (mappings != null) {
+            assert !cctx.mvccEnabled(); // Should not happen when MVCC enabled.
+
             ClusterNode loc = cctx.localNode();
 
             int curTopVer = topCntr.get();
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java
index 0d0b2e8..61f1e06 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java
@@ -47,6 +47,7 @@
 import org.apache.ignite.internal.processors.cache.GridCacheEntryEx;
 import org.apache.ignite.internal.processors.cache.GridCacheEntryInfo;
 import org.apache.ignite.internal.processors.cache.GridCacheEntryRemovedException;
+import org.apache.ignite.internal.processors.cache.GridCacheMvccEntryInfo;
 import org.apache.ignite.internal.processors.cache.GridCachePartitionExchangeManager;
 import org.apache.ignite.internal.processors.cache.GridCacheSharedContext;
 import org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridDhtInvalidPartitionException;
@@ -64,6 +65,7 @@
 import org.apache.ignite.internal.util.tostring.GridToStringExclude;
 import org.apache.ignite.internal.util.tostring.GridToStringInclude;
 import org.apache.ignite.internal.util.typedef.CI1;
+import org.apache.ignite.internal.util.typedef.internal.CU;
 import org.apache.ignite.internal.util.typedef.internal.LT;
 import org.apache.ignite.internal.util.typedef.internal.S;
 import org.apache.ignite.internal.util.typedef.internal.U;
@@ -766,35 +768,10 @@
                         try {
                             Iterator<GridCacheEntryInfo> infos = e.getValue().infos().iterator();
 
-                            // Loop through all received entries and try to preload them.
-                            while (infos.hasNext()) {
-                                ctx.database().checkpointReadLock();
-
-                                try {
-                                    for (int i = 0; i < 100; i++) {
-                                        if (!infos.hasNext())
-                                            break;
-
-                                        GridCacheEntryInfo entry = infos.next();
-
-                                        if (!preloadEntry(node, p, entry, topVer)) {
-                                            if (log.isTraceEnabled())
-                                                log.trace("Got entries for invalid partition during " +
-                                                    "preloading (will skip) [p=" + p + ", entry=" + entry + ']');
-
-                                            break;
-                                        }
-
-                                        for (GridCacheContext cctx : grp.caches()) {
-                                            if (cctx.statisticsEnabled())
-                                                cctx.cache().metrics0().onRebalanceKeyReceived();
-                                        }
-                                    }
-                                }
-                                finally {
-                                    ctx.database().checkpointReadUnlock();
-                                }
-                            }
+                            if (grp.mvccEnabled())
+                                mvccPreloadEntries(topVer, node, p, infos);
+                            else
+                                preloadEntries(topVer, node, p, infos);
 
                             // If message was last for this partition,
                             // then we take ownership.
@@ -875,12 +852,153 @@
     }
 
     /**
+     * Adds mvcc entries with theirs history to partition p.
+     *
+     * @param node Node which sent entry.
+     * @param p Partition id.
+     * @param infos Entries info for preload.
+     * @param topVer Topology version.
+     * @throws IgniteInterruptedCheckedException If interrupted.
+     */
+    private void mvccPreloadEntries(AffinityTopologyVersion topVer, ClusterNode node, int p,
+        Iterator<GridCacheEntryInfo> infos) throws IgniteCheckedException {
+        if (!infos.hasNext())
+            return;
+
+        List<GridCacheMvccEntryInfo> entryHist = new ArrayList<>();
+
+        GridCacheContext cctx = grp.sharedGroup() ? null : grp.singleCacheContext();
+
+        // Loop through all received entries and try to preload them.
+        while (infos.hasNext() || !entryHist.isEmpty()) {
+            ctx.database().checkpointReadLock();
+
+            try {
+                for (int i = 0; i < 100; i++) {
+                    boolean hasMore = infos.hasNext();
+
+                    assert hasMore || !entryHist.isEmpty();
+
+                    GridCacheMvccEntryInfo entry = null;
+
+                    boolean flushHistory;
+
+                    if (hasMore) {
+                        entry = (GridCacheMvccEntryInfo)infos.next();
+
+                        GridCacheMvccEntryInfo prev = entryHist.isEmpty() ? null : entryHist.get(0);
+
+                        flushHistory = prev != null && ((grp.sharedGroup() && prev.cacheId() != entry.cacheId())
+                            || !prev.key().equals(entry.key()));
+                    }
+                    else
+                        flushHistory = true;
+
+                    if (flushHistory) {
+                        assert !entryHist.isEmpty();
+
+                        int cacheId = entryHist.get(0).cacheId();
+
+                        if (grp.sharedGroup() && (cctx == null || cacheId != cctx.cacheId())) {
+                            assert cacheId != CU.UNDEFINED_CACHE_ID;
+
+                            cctx = grp.shared().cacheContext(cacheId);
+                        }
+
+                        if (cctx != null) {
+                            if (!mvccPreloadEntry(cctx, node, entryHist, topVer, p)) {
+                                if (log.isTraceEnabled())
+                                    log.trace("Got entries for invalid partition during " +
+                                        "preloading (will skip) [p=" + p +
+                                        ", entry=" + entryHist.get(entryHist.size() - 1) + ']');
+
+                                return; // Skip current partition.
+                            }
+
+                            //TODO: IGNITE-11330: Update metrics for touched cache only.
+                            for (GridCacheContext ctx : grp.caches()) {
+                                if (ctx.statisticsEnabled())
+                                    ctx.cache().metrics0().onRebalanceKeyReceived();
+                            }
+                        }
+
+                        if (!hasMore)
+                            return;
+
+                        entryHist.clear();
+                    }
+
+                    entryHist.add(entry);
+                }
+            }
+            finally {
+                ctx.database().checkpointReadUnlock();
+            }
+        }
+    }
+
+    /**
+     * Adds entries with theirs history to partition p.
+     *
+     * @param node Node which sent entry.
+     * @param p Partition id.
+     * @param infos Entries info for preload.
+     * @param topVer Topology version.
+     * @throws IgniteInterruptedCheckedException If interrupted.
+     */
+    private void preloadEntries(AffinityTopologyVersion topVer, ClusterNode node, int p,
+        Iterator<GridCacheEntryInfo> infos) throws IgniteCheckedException {
+        GridCacheContext cctx = null;
+
+        // Loop through all received entries and try to preload them.
+        while (infos.hasNext()) {
+            ctx.database().checkpointReadLock();
+
+            try {
+                for (int i = 0; i < 100; i++) {
+                    if (!infos.hasNext())
+                        break;
+
+                    GridCacheEntryInfo entry = infos.next();
+
+                    if (cctx == null || (grp.sharedGroup() && entry.cacheId() != cctx.cacheId())) {
+                        cctx = grp.sharedGroup() ? grp.shared().cacheContext(entry.cacheId()) : grp.singleCacheContext();
+
+                        if (cctx == null)
+                            continue;
+                        else if (cctx.isNear())
+                            cctx = cctx.dhtCache().context();
+                    }
+
+                    if (!preloadEntry(node, p, entry, topVer, cctx)) {
+                        if (log.isTraceEnabled())
+                            log.trace("Got entries for invalid partition during " +
+                                "preloading (will skip) [p=" + p + ", entry=" + entry + ']');
+
+                        return;
+                    }
+
+                    //TODO: IGNITE-11330: Update metrics for touched cache only.
+                    for (GridCacheContext ctx : grp.caches()) {
+                        if (ctx.statisticsEnabled())
+                            ctx.cache().metrics0().onRebalanceKeyReceived();
+                    }
+                }
+            }
+            finally {
+                ctx.database().checkpointReadUnlock();
+            }
+        }
+    }
+
+    /**
      * Adds {@code entry} to partition {@code p}.
      *
      * @param from Node which sent entry.
      * @param p Partition id.
      * @param entry Preloaded entry.
      * @param topVer Topology version.
+     * @param cctx Cache context.
      * @return {@code False} if partition has become invalid during preloading.
      * @throws IgniteInterruptedCheckedException If interrupted.
      */
@@ -888,7 +1006,8 @@
         ClusterNode from,
         int p,
         GridCacheEntryInfo entry,
-        AffinityTopologyVersion topVer
+        AffinityTopologyVersion topVer,
+        GridCacheContext cctx
     ) throws IgniteCheckedException {
         assert ctx.database().checkpointLockIsHeldByThread();
 
@@ -896,15 +1015,7 @@
             GridCacheEntryEx cached = null;
 
             try {
-                GridCacheContext cctx = grp.sharedGroup() ? ctx.cacheContext(entry.cacheId()) : grp.singleCacheContext();
-
-                if (cctx == null)
-                    return true;
-
-                if (cctx.isNear())
-                    cctx = cctx.dhtCache().context();
-
-                cached = cctx.cache().entryEx(entry.key());
+                cached = cctx.cache().entryEx(entry.key(), topVer);
 
                 if (log.isTraceEnabled())
                     log.trace("Rebalancing key [key=" + entry.key() + ", part=" + p + ", node=" + from.id() + ']');
@@ -966,6 +1077,79 @@
     }
 
     /**
+     * Adds mvcc {@code entry} with it's history to partition {@code p}.
+     *
+     * @param cctx Cache context.
+     * @param from Node which sent entry.
+     * @param history Mvcc entry history.
+     * @param topVer Topology version.
+     * @param p Partition id.
+     * @return {@code False} if partition has become invalid during preloading.
+     * @throws IgniteInterruptedCheckedException If interrupted.
+     */
+    private boolean mvccPreloadEntry(
+        GridCacheContext cctx,
+        ClusterNode from,
+        List<GridCacheMvccEntryInfo> history,
+        AffinityTopologyVersion topVer,
+        int p
+    ) throws IgniteCheckedException {
+        assert ctx.database().checkpointLockIsHeldByThread();
+        assert !history.isEmpty();
+
+        GridCacheMvccEntryInfo info = history.get(0);
+
+        assert info.key() != null;
+
+        try {
+            GridCacheEntryEx cached = null;
+
+            try {
+                cached = cctx.cache().entryEx(info.key(), topVer);
+
+                if (log.isTraceEnabled())
+                    log.trace("Rebalancing key [key=" + info.key() + ", part=" + p + ", node=" + from.id() + ']');
+
+                if (cached.mvccPreloadEntry(history)) {
+                    cached.touch(); // Start tracking.
+
+                    if (cctx.events().isRecordable(EVT_CACHE_REBALANCE_OBJECT_LOADED) && !cached.isInternal())
+                        cctx.events().addEvent(cached.partition(), cached.key(), cctx.localNodeId(), null,
+                            null, null, EVT_CACHE_REBALANCE_OBJECT_LOADED, null, true, null,
+                            false, null, null, null, true);
+                }
+                else {
+                    cached.touch(); // Start tracking.
+
+                    if (log.isTraceEnabled())
+                        log.trace("Rebalancing entry is already in cache (will ignore) [key=" + cached.key() +
+                            ", part=" + p + ']');
+                }
+            }
+            catch (GridCacheEntryRemovedException ignored) {
+                if (log.isTraceEnabled())
+                    log.trace("Entry has been concurrently removed while rebalancing (will ignore) [key=" +
+                        cached.key() + ", part=" + p + ']');
+            }
+            catch (GridDhtInvalidPartitionException ignored) {
+                if (log.isDebugEnabled())
+                    log.debug("Partition became invalid during rebalancing (will ignore): " + p);
+
+                return false;
+            }
+        }
+        catch (IgniteInterruptedCheckedException | ClusterTopologyCheckedException e) {
+            throw e;
+        }
+        catch (IgniteCheckedException e) {
+            throw new IgniteCheckedException("Failed to cache rebalanced entry (will stop rebalancing) [local=" +
+                ctx.localNode() + ", node=" + from.id() + ", key=" + info.key() + ", part=" + p + ']', e);
+        }
+
+        return true;
+    }
+
+    /**
      * String representation of demand routine.
      *
      * @param topicId Topic id.
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionSupplier.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionSupplier.java
index c6bcc80..514f8fd 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionSupplier.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionSupplier.java
@@ -316,8 +316,17 @@
 
             long batchesCnt = 0;
 
+            CacheDataRow prevRow = null;
+
             while (iter.hasNext()) {
-                if (supplyMsg.messageSize() >= msgMaxSize) {
+                CacheDataRow row = iter.peek();
+
+                // Prevent mvcc entry history splitting into separate batches.
+                boolean canFlushHistory = !grp.mvccEnabled() ||
+                    prevRow != null && ((grp.sharedGroup() && row.cacheId() != prevRow.cacheId()) ||
+                        !row.key().equals(prevRow.key()));
+
+                if (canFlushHistory && supplyMsg.messageSize() >= msgMaxSize) {
                     if (++batchesCnt >= maxBatchesCnt) {
                         saveSupplyContext(contextId,
                             iter,
@@ -340,7 +349,9 @@
                     }
                 }
 
-                CacheDataRow row = iter.next();
+                row = iter.next();
+
+                prevRow = row;
 
                 int part = row.partition();
 
@@ -364,38 +375,10 @@
                 if (!remainingParts.contains(part))
                     continue;
 
-                GridCacheEntryInfo info = grp.mvccEnabled() ?
-                    new GridCacheMvccEntryInfo() : new GridCacheEntryInfo();
+                GridCacheEntryInfo info = extractEntryInfo(row);
 
-                info.key(row.key());
-                info.cacheId(row.cacheId());
-
-                if (grp.mvccEnabled()) {
-                    byte txState = row.mvccTxState() != TxState.NA ? row.mvccTxState() :
-                        MvccUtils.state(grp, row.mvccCoordinatorVersion(), row.mvccCounter(),
-                        row.mvccOperationCounter());
-
-                    if (txState != TxState.COMMITTED)
-                        continue;
-
-                    ((MvccVersionAware)info).mvccVersion(row);
-                    ((GridCacheMvccEntryInfo)info).mvccTxState(TxState.COMMITTED);
-
-                    byte newTxState = row.newMvccTxState() != TxState.NA ? row.newMvccTxState() :
-                        MvccUtils.state(grp, row.newMvccCoordinatorVersion(), row.newMvccCounter(),
-                        row.newMvccOperationCounter());
-
-                    if (newTxState != TxState.ABORTED) {
-                        ((MvccUpdateVersionAware)info).newMvccVersion(row);
-
-                        if (newTxState == TxState.COMMITTED)
-                            ((GridCacheMvccEntryInfo)info).newMvccTxState(TxState.COMMITTED);
-                    }
-                }
-
-                info.value(row.value());
-                info.version(row.version());
-                info.expireTime(row.expireTime());
+                if (info == null)
+                    continue;
 
                 if (preloadPred == null || preloadPred.apply(info))
                     supplyMsg.addEntry0(part, iter.historical(part), info, grp.shared(), grp.cacheObjectContext());
@@ -503,6 +486,42 @@
     }
 
     /**
+     * Extracts entry info from row.
+     * @param row Cache data row.
+     * @return Entry info.
+     */
+    private GridCacheEntryInfo extractEntryInfo(CacheDataRow row) {
+        GridCacheEntryInfo info = grp.mvccEnabled() ?
+            new GridCacheMvccEntryInfo() : new GridCacheEntryInfo();
+
+        info.key(row.key());
+        info.cacheId(row.cacheId());
+
+        if (grp.mvccEnabled()) {
+            assert row.mvccCoordinatorVersion() != MvccUtils.MVCC_CRD_COUNTER_NA;
+
+            // Rows from rebalance iterator have actual states already.
+            if (row.mvccTxState() != TxState.COMMITTED)
+                return null;
+
+            ((MvccVersionAware)info).mvccVersion(row);
+            ((GridCacheMvccEntryInfo)info).mvccTxState(TxState.COMMITTED);
+
+            if (row.newMvccCoordinatorVersion() != MvccUtils.MVCC_CRD_COUNTER_NA &&
+                row.newMvccTxState() == TxState.COMMITTED) {
+                ((MvccUpdateVersionAware)info).newMvccVersion(row);
+                ((GridCacheMvccEntryInfo)info).newMvccTxState(TxState.COMMITTED);
+            }
+        }
+
+        info.value(row.value());
+        info.version(row.version());
+        info.expireTime(row.expireTime());
+
+        return info;
+    }
+
+    /**
      * Sends supply message to demand node.
      *
      * @param demander Recipient of supply message.
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionsExchangeFuture.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionsExchangeFuture.java
index 57de875..3ebfc6e 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionsExchangeFuture.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionsExchangeFuture.java
@@ -890,9 +890,12 @@
                 exchLog.info("Finished exchange init [topVer=" + topVer + ", crd=" + crdNode + ']');
         }
         catch (IgniteInterruptedCheckedException e) {
-            assert cctx.kernalContext().isStopping();
+            assert cctx.kernalContext().isStopping() || cctx.kernalContext().clientDisconnected();
 
-            onDone(new IgniteCheckedException("Node stopped"));
+            if (cctx.kernalContext().clientDisconnected())
+                onDone(new IgniteCheckedException("Client disconnected"));
+            else
+                onDone(new IgniteCheckedException("Node stopped"));
 
             throw e;
         }
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPreloader.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPreloader.java
index e92a240..042e0ea 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPreloader.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPreloader.java
@@ -477,6 +477,10 @@
 
     /** {@inheritDoc} */
     @Override public boolean needForceKeys() {
+        // Do not use force key request with enabled MVCC.
+        if (grp.mvccEnabled())
+            return false;
+
         if (grp.rebalanceEnabled()) {
             IgniteInternalFuture<Boolean> rebalanceFut = rebalanceFuture();
 
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/IgniteRebalanceIteratorImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/IgniteRebalanceIteratorImpl.java
index 87ba3a9..75ae89a 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/IgniteRebalanceIteratorImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/IgniteRebalanceIteratorImpl.java
@@ -50,6 +50,9 @@
     /** Current full iterator. */
     private Map.Entry<Integer, GridCloseableIterator<CacheDataRow>> current;
 
+    /** Next value. */
+    private CacheDataRow cached;
+
     /** */
     private boolean reachedEnd;
 
@@ -103,6 +106,9 @@
         if (historical(partId))
             return historicalIterator.isDone(partId);
 
+        if (cached != null)
+            return cached.partition() > partId;
+
         return current == null || current.getKey() > partId;
     }
 
@@ -142,12 +148,26 @@
     }
 
     /** {@inheritDoc} */
+    @Override public synchronized CacheDataRow peek() {
+        if (cached == null) {
+            if (!hasNext())
+                return null;
+
+            cached = next();
+        }
+
+        return cached;
+    }
+
+    /** {@inheritDoc} */
     @Override public synchronized void removeX() throws IgniteCheckedException {
         throw new UnsupportedOperationException("remove");
     }
 
     /** {@inheritDoc} */
     @Override public synchronized void close() throws IgniteCheckedException {
+        cached = null;
+
         if (historicalIterator != null)
             historicalIterator.close();
 
@@ -172,6 +192,9 @@
     /** {@inheritDoc} */
     @Override public synchronized boolean hasNext() {
         try {
+            if (cached != null)
+                return true;
+
             return hasNextX();
         }
         catch (IgniteCheckedException e) {
@@ -182,6 +205,14 @@
     /** {@inheritDoc} */
     @Override public synchronized CacheDataRow next() {
         try {
+            if (cached != null) {
+                CacheDataRow res = cached;
+
+                cached = null;
+
+                return res;
+            }
+
             return nextX();
         }
         catch (IgniteCheckedException e) {
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearTxAbstractEnlistFuture.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearTxAbstractEnlistFuture.java
index e43b5e9..89e7761 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearTxAbstractEnlistFuture.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearTxAbstractEnlistFuture.java
@@ -41,6 +41,7 @@
 import org.apache.ignite.internal.processors.cache.mvcc.MvccSnapshot;
 import org.apache.ignite.internal.processors.cache.version.GridCacheVersion;
 import org.apache.ignite.internal.processors.timeout.GridTimeoutObjectAdapter;
+import org.apache.ignite.internal.transactions.IgniteTxRollbackCheckedException;
 import org.apache.ignite.internal.transactions.IgniteTxTimeoutCheckedException;
 import org.apache.ignite.internal.util.tostring.GridToStringExclude;
 import org.apache.ignite.internal.util.typedef.internal.S;
@@ -361,6 +362,11 @@
     }
 
     /** {@inheritDoc} */
+    @Override public boolean onCancelled() {
+        return onDone(null, asyncRollbackException(), false);
+    }
+
+    /** {@inheritDoc} */
     @Override public boolean onDone(@Nullable T res, @Nullable Throwable err, boolean cancelled) {
         if (!DONE_UPD.compareAndSet(this, 0, 1))
             return false;
@@ -451,6 +457,13 @@
     }
 
     /**
+     * @return Async rollback exception.
+     */
+    @NotNull private IgniteTxRollbackCheckedException asyncRollbackException() {
+        return new IgniteTxRollbackCheckedException("Transaction was asynchronously rolled back [tx=" + tx + ']');
+    }
+
+    /**
      * Start iterating the data rows and form batches.
      *
      * @param topLocked Whether topology was already locked.
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/mvcc/MvccProcessorImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/mvcc/MvccProcessorImpl.java
index dfe4f75..478d156 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/mvcc/MvccProcessorImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/mvcc/MvccProcessorImpl.java
@@ -2173,8 +2173,6 @@
             int curCacheId = CU.UNDEFINED_CACHE_ID;
 
             try {
-                GridCursor<? extends CacheDataRow> cursor = part.dataStore().cursor(KEY_ONLY);
-
                 KeyCacheObject prevKey = null;
 
                 Object rest = null;
@@ -2190,6 +2188,8 @@
                 if (!shared && (cctx = F.first(part.group().caches())) == null)
                     return metrics;
 
+                GridCursor<? extends CacheDataRow> cursor = part.dataStore().cursor(KEY_ONLY);
+
                 while (cursor.next()) {
                     if (isCancelled())
                         throw new IgniteInterruptedCheckedException("Operation has been cancelled.");
@@ -2199,14 +2199,14 @@
                     if (prevKey == null)
                         prevKey = row.key();
 
-                    if (cctx == null) {
+                    if (cctx == null) { // Shared group.
                         cctx = part.group().shared().cacheContext(curCacheId = row.cacheId());
 
                         if (cctx == null)
-                            return metrics;
+                            continue;
                     }
 
-                    if (!prevKey.equals(row.key()) || (shared && curCacheId != row.cacheId())) {
+                    if ((shared && curCacheId != row.cacheId()) || !prevKey.equals(row.key())) {
                         if (rest != null || !F.isEmpty(cleanupRows))
                             cleanup(part, prevKey, cleanupRows, rest, cctx, metrics);
 
@@ -2218,7 +2218,7 @@
                             cctx = part.group().shared().cacheContext(curCacheId = row.cacheId());
 
                             if (cctx == null)
-                                return metrics;
+                                continue;
                         }
 
                         prevKey = row.key();
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/mvcc/MvccUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/mvcc/MvccUtils.java
index cf7b62b..c81b2da 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/mvcc/MvccUtils.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/mvcc/MvccUtils.java
@@ -173,7 +173,7 @@
      * @return TxState
      * @see TxState
      */
-    private static byte state(MvccProcessor proc, long mvccCrd, long mvccCntr, int mvccOpCntr) {
+    public static byte state(MvccProcessor proc, long mvccCrd, long mvccCntr, int mvccOpCntr) {
         if (compare(INITIAL_VERSION, mvccCrd, mvccCntr, mvccOpCntr) == 0)
             return TxState.COMMITTED; // Initial version is always committed;
 
@@ -550,7 +550,7 @@
      * @return {@code True} if version is valid.
      */
     public static boolean mvccVersionIsValid(long crdVer, long cntr) {
-        return crdVer > MVCC_CRD_COUNTER_NA && cntr != MVCC_COUNTER_NA;
+        return crdVer > MVCC_CRD_COUNTER_NA && cntr > MVCC_COUNTER_NA;
     }
 
     /**
@@ -788,16 +788,17 @@
     /**
      * Initialises MVCC filter and returns MVCC query tracker if needed.
      * @param cctx Cache context.
-     * @param startTx Start transaction flag.
+     * @param autoStartTx Start transaction flag.
      * @return MVCC query tracker.
      * @throws IgniteCheckedException If failed.
      */
-    @NotNull public static MvccQueryTracker mvccTracker(GridCacheContext cctx, boolean startTx) throws IgniteCheckedException {
+    @NotNull public static MvccQueryTracker mvccTracker(GridCacheContext cctx, boolean autoStartTx)
+        throws IgniteCheckedException {
         assert cctx != null && cctx.mvccEnabled();
 
         GridNearTxLocal tx = tx(cctx.kernalContext());
 
-        if (tx == null && startTx)
+        if (tx == null && autoStartTx)
             tx = txStart(cctx, 0);
 
         return mvccTracker(cctx, tx);
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/mvcc/txlog/TxLog.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/mvcc/txlog/TxLog.java
index 528bbbc..2351d29 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/mvcc/txlog/TxLog.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/mvcc/txlog/TxLog.java
@@ -30,6 +30,7 @@
 import org.apache.ignite.internal.pagemem.PageMemory;
 import org.apache.ignite.internal.pagemem.wal.IgniteWriteAheadLogManager;
 import org.apache.ignite.internal.pagemem.wal.record.delta.MetaPageInitRecord;
+import org.apache.ignite.internal.processors.cache.mvcc.MvccUtils;
 import org.apache.ignite.internal.processors.cache.persistence.DbCheckpointListener;
 import org.apache.ignite.internal.processors.cache.persistence.GridCacheDatabaseSharedManager;
 import org.apache.ignite.internal.processors.cache.persistence.IgniteCacheDatabaseSharedManager;
@@ -48,8 +49,6 @@
 
 import static org.apache.ignite.internal.pagemem.PageIdAllocator.FLAG_IDX;
 import static org.apache.ignite.internal.pagemem.PageIdAllocator.INDEX_PARTITION;
-import static org.apache.ignite.internal.processors.cache.mvcc.MvccUtils.MVCC_COUNTER_NA;
-import static org.apache.ignite.internal.processors.cache.mvcc.MvccUtils.MVCC_CRD_COUNTER_NA;
 
 /**
  *
@@ -377,7 +376,6 @@
         /** {@inheritDoc} */
         @Override public boolean apply(BPlusTree<TxKey, TxRow> tree, BPlusIO<TxKey> io, long pageAddr,
                                        int idx) throws IgniteCheckedException {
-
             if (rows == null)
                 rows = new ArrayList<>();
 
@@ -431,7 +429,8 @@
          * @param primary Flag if this is primary node.
          */
         TxLogUpdateClosure(long major, long minor, byte newState, boolean primary) {
-            assert major > MVCC_CRD_COUNTER_NA && minor > MVCC_COUNTER_NA && newState != TxState.NA;
+            assert MvccUtils.mvccVersionIsValid(major, minor) && newState != TxState.NA;
+
             this.major = major;
             this.minor = minor;
             this.newState = newState;
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 c9d006f..3e3dc5c 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
@@ -319,7 +319,7 @@
             }
 
             // Assume that row header is always located entirely on the very first page.
-            hdrLen = readHeader(pageAddr, data.offset());
+            hdrLen = readHeader(sharedCtx, pageAddr, data.offset(), rowData);
 
             if (rowData == LINK_WITH_HEADER)
                 return null;
@@ -346,11 +346,13 @@
     /**
      * Reads row header (i.e. MVCC info) which should be located on the very first page od data.
      *
+     * @param sharedCtx Shared context.
      * @param addr Address.
      * @param off Offset
+     * @param rowData Required row data.
      * @return Number of bytes read.
      */
-    protected int readHeader(long addr, int off) {
+    protected int readHeader(GridCacheSharedContext<?, ?> sharedCtx, long addr, int off, RowData rowData) {
         // No-op.
         return 0;
     }
@@ -461,7 +463,7 @@
     ) throws IgniteCheckedException {
         int off = 0;
 
-        off += readHeader(addr, off);
+        off += readHeader(sharedCtx, addr, off, rowData);
 
         if (rowData == LINK_WITH_HEADER)
             return;
@@ -478,7 +480,7 @@
         int len = PageUtils.getInt(addr, off);
         off += 4;
 
-        if (rowData != RowData.NO_KEY) {
+        if (rowData != RowData.NO_KEY && rowData != RowData.NO_KEY_WITH_HINTS) {
             byte type = PageUtils.getByte(addr, off);
             off++;
 
@@ -856,7 +858,13 @@
         LINK_ONLY,
 
         /** */
-        LINK_WITH_HEADER
+        LINK_WITH_HEADER,
+
+        /** Force instant hints actualization for rebalance (to avoid races with vacuum). */
+        FULL_WITH_HINTS,
+
+        /** Force instant hints actualization for update operation with history (to avoid races with vacuum). */
+        NO_KEY_WITH_HINTS
     }
 
     /** {@inheritDoc} */
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheOffheapManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheOffheapManager.java
index 16e9840..2978f69 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheOffheapManager.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheOffheapManager.java
@@ -55,6 +55,7 @@
 import org.apache.ignite.internal.processors.cache.CacheObject;
 import org.apache.ignite.internal.processors.cache.GridCacheContext;
 import org.apache.ignite.internal.processors.cache.GridCacheEntryEx;
+import org.apache.ignite.internal.processors.cache.GridCacheMvccEntryInfo;
 import org.apache.ignite.internal.processors.cache.GridCacheTtlManager;
 import org.apache.ignite.internal.processors.cache.IgniteCacheOffheapManagerImpl;
 import org.apache.ignite.internal.processors.cache.KeyCacheObject;
@@ -1957,24 +1958,16 @@
 
             return delegate.mvccInitialValue(cctx, key, val, ver, expireTime, mvccVer, newMvccVer);
         }
-
+        
         /** {@inheritDoc} */
-        @Override public boolean mvccInitialValueIfAbsent(
+        @Override public boolean mvccApplyHistoryIfAbsent(
             GridCacheContext cctx,
             KeyCacheObject key,
-            @Nullable CacheObject val,
-            GridCacheVersion ver,
-            long expireTime,
-            MvccVersion mvccVer,
-            MvccVersion newMvccVer,
-            byte txState,
-            byte newTxState)
-            throws IgniteCheckedException
-        {
+            List<GridCacheMvccEntryInfo> hist)
+            throws IgniteCheckedException {
             CacheDataStore delegate = init0(false);
 
-            return delegate.mvccInitialValueIfAbsent(cctx, key, val, ver, expireTime, mvccVer, newMvccVer,
-                txState, newTxState);
+            return delegate.mvccApplyHistoryIfAbsent(cctx, key, hist);
         }
 
         /** {@inheritDoc} */
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FilePageStore.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FilePageStore.java
index 8e0196e..0968c49 100755
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FilePageStore.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FilePageStore.java
@@ -349,7 +349,7 @@
 
                 long delta = newSize - allocated.getAndSet(newSize);
 
-                assert delta % pageSize == 0;
+                assert delta % pageSize == 0 : delta;
 
                 allocatedTracker.updateTotalAllocatedPages(delta / pageSize);
             }
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/io/DataPageIO.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/io/DataPageIO.java
index 9ed7b72..f67c89e 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/io/DataPageIO.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/io/DataPageIO.java
@@ -246,44 +246,6 @@
     /**
      * @param pageAddr Page address.
      * @param dataOff Data offset.
-     * @param ver New version.
-     */
-    public void updateVersion(long pageAddr, int dataOff, MvccVersion ver) {
-        long addr = pageAddr + dataOff;
-
-        updateVersion(addr, ver.coordinatorVersion(), ver.counter(), ver.operationCounter());
-    }
-
-    /**
-     * @param pageAddr Page address.
-     * @param itemId Item ID.
-     * @param pageSize Page size.
-     * @param mvccCrd Mvcc coordinator.
-     * @param mvccCntr Mvcc counter.
-     * @param mvccOpCntr Operation counter.
-     */
-    public void updateVersion(long pageAddr, int itemId, int pageSize, long mvccCrd, long mvccCntr, int mvccOpCntr) {
-        int dataOff = getDataOffset(pageAddr, itemId, pageSize);
-
-        long addr = pageAddr + dataOff + (isFragmented(pageAddr, dataOff) ? 10 : 2);
-
-        updateVersion(addr, mvccCrd, mvccCntr, mvccOpCntr);
-    }
-
-    /**
-     * @param addr Address.
-     * @param mvccCrd Mvcc coordinator.
-     * @param mvccCntr Mvcc counter.
-     */
-    private void updateVersion(long addr, long mvccCrd, long mvccCntr, int mvccOpCntr) {
-        PageUtils.putLong(addr, 0, mvccCrd);
-        PageUtils.putLong(addr, 8, mvccCntr);
-        PageUtils.putInt(addr, 16, mvccOpCntr);
-    }
-
-    /**
-     * @param pageAddr Page address.
-     * @param dataOff Data offset.
      * @param mvccCrd Mvcc coordinator.
      * @param mvccCntr Mvcc counter.
      * @param mvccOpCntr Operation counter.
@@ -325,7 +287,7 @@
 
         int opCntr = rawMvccOperationCounter(addr, 0);
 
-        rawMvccOperationCounter(addr, 0, ((int)txState << MVCC_HINTS_BIT_OFF) | (opCntr & ~MVCC_HINTS_MASK));
+        rawMvccOperationCounter(addr, 0, (opCntr & ~MVCC_HINTS_MASK) | ((int)txState << MVCC_HINTS_BIT_OFF));
     }
 
     /**
@@ -341,7 +303,7 @@
 
         int opCntr = rawNewMvccOperationCounter(addr, 0);
 
-        rawNewMvccOperationCounter(addr, 0, ((int)txState << MVCC_HINTS_BIT_OFF) | (opCntr & ~MVCC_HINTS_MASK));
+        rawNewMvccOperationCounter(addr, 0, (opCntr & ~MVCC_HINTS_MASK) | ((int)txState << MVCC_HINTS_BIT_OFF));
     }
 
     /**
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/FileWriteAheadLogManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/FileWriteAheadLogManager.java
index 1cf9a10..180bd56 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/FileWriteAheadLogManager.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/FileWriteAheadLogManager.java
@@ -1192,7 +1192,16 @@
                 switchSegmentRecordOffset.set(idx, hnd.getSwitchSegmentRecordOffset());
             }
 
-            FileWriteHandle next = initNextWriteHandle(cur);
+            FileWriteHandle next;
+            try {
+                next = initNextWriteHandle(cur);
+            }
+            catch (IgniteCheckedException e) {
+                //Allow to avoid forever waiting in other threads.
+                cur.signalNextAvailable();
+
+                throw e;
+            }
 
             next.writeHeader();
 
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/continuous/CacheContinuousQueryHandler.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/continuous/CacheContinuousQueryHandler.java
index b87858e..7f9b918 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/continuous/CacheContinuousQueryHandler.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/continuous/CacheContinuousQueryHandler.java
@@ -445,20 +445,8 @@
                         log.debug("Filter invoked for event [evt=" + evt + ", primary=" + primary
                             + ", notify=" + notify + ']');
 
-                    if (primary || skipPrimaryCheck) {
-                        if (fut == null)
-                            onEntryUpdate(evt, notify, loc, recordIgniteEvt);
-                        else {
-                            fut.addContinuousQueryClosure(new CI1<Boolean>() {
-                                @Override public void apply(Boolean suc) {
-                                    if (!suc)
-                                        evt.entry().markFiltered();
-
-                                    onEntryUpdate(evt, notify, loc, recordIgniteEvt);
-                                }
-                            }, sync);
-                        }
-                    }
+                    if (primary || skipPrimaryCheck)
+                        onEntryUpdate(evt, notify, loc, recordIgniteEvt);
                     else
                         handleBackupEntry(cctx, evt.entry());
                 }
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxImplicitSingleStateImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxImplicitSingleStateImpl.java
index c5f736a..4978320 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxImplicitSingleStateImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxImplicitSingleStateImpl.java
@@ -30,6 +30,7 @@
 import org.apache.ignite.internal.processors.cache.CacheStoppedException;
 import org.apache.ignite.internal.processors.cache.GridCacheContext;
 import org.apache.ignite.internal.processors.cache.GridCacheSharedContext;
+import org.apache.ignite.internal.processors.cache.KeyCacheObject;
 import org.apache.ignite.internal.processors.cache.distributed.dht.GridDhtTopologyFuture;
 import org.apache.ignite.internal.processors.cache.store.CacheStoreManager;
 import org.apache.ignite.internal.util.GridIntList;
@@ -125,7 +126,14 @@
         if (cacheCtx == null)
             return null;
 
-        Throwable err = topFut.validateCache(cacheCtx, recovery, read, null, entry);
+        Throwable err = null;
+
+        if (entry != null) {
+            // An entry is a singleton list here, so a key is taken from a first element.
+            KeyCacheObject key = entry.get(0).key();
+
+            err = topFut.validateCache(cacheCtx, recovery, read, key, null);
+        }
 
         if (err != null) {
             return new IgniteCheckedException(
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 0c460ee..197a685 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
@@ -102,7 +102,7 @@
      * @return Search row.
      */
     MvccDataRow mvccRow(int cacheId, int hash, long link, CacheDataRowAdapter.RowData rowData, long crdVer, long mvccCntr, int opCntr) {
-        MvccDataRow dataRow = new MvccDataRow(
+        MvccDataRow row = new MvccDataRow(
             grp,
             hash,
             link,
@@ -114,7 +114,7 @@
             SKIP_VER.get()
         );
 
-        return initDataRow(dataRow, cacheId);
+        return initDataRow(row, 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 71c8a86..b3c1c69 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
@@ -330,7 +330,7 @@
     /** {@inheritDoc} */
     @Override protected int compare(BPlusIO<CacheSearchRow> iox, long pageAddr, int idx, CacheSearchRow row)
         throws IgniteCheckedException {
-        assert !grp.mvccEnabled() || row.mvccCoordinatorVersion() != 0
+        assert !grp.mvccEnabled() || row.mvccCoordinatorVersion() != MvccUtils.MVCC_CRD_COUNTER_NA
             || (row.getClass() == SearchRow.class && row.key() == null) : row;
 
         RowLinkIO io = (RowLinkIO)iox;
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 92f5aed..cd6866e 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
@@ -21,6 +21,7 @@
 import org.apache.ignite.internal.pagemem.PageUtils;
 import org.apache.ignite.internal.processors.cache.CacheGroupContext;
 import org.apache.ignite.internal.processors.cache.CacheObject;
+import org.apache.ignite.internal.processors.cache.GridCacheSharedContext;
 import org.apache.ignite.internal.processors.cache.KeyCacheObject;
 import org.apache.ignite.internal.processors.cache.mvcc.MvccUtils;
 import org.apache.ignite.internal.processors.cache.mvcc.MvccVersion;
@@ -37,6 +38,8 @@
 import static org.apache.ignite.internal.processors.cache.mvcc.MvccUtils.MVCC_KEY_ABSENT_BEFORE_MASK;
 import static org.apache.ignite.internal.processors.cache.mvcc.MvccUtils.MVCC_OP_COUNTER_MASK;
 import static org.apache.ignite.internal.processors.cache.mvcc.MvccUtils.MVCC_OP_COUNTER_NA;
+import static org.apache.ignite.internal.processors.cache.persistence.CacheDataRowAdapter.RowData.FULL_WITH_HINTS;
+import static org.apache.ignite.internal.processors.cache.persistence.CacheDataRowAdapter.RowData.NO_KEY_WITH_HINTS;
 import static org.apache.ignite.internal.processors.cache.persistence.tree.io.DataPageIO.MVCC_INFO_SIZE;
 
 /**
@@ -168,7 +171,9 @@
     }
 
     /** {@inheritDoc} */
-    @Override protected int readHeader(long addr, int off) {
+    @Override protected int readHeader(GridCacheSharedContext<?, ?> sharedCtx, long addr, int off, RowData rowData) {
+        boolean addHints = rowData == FULL_WITH_HINTS || rowData == NO_KEY_WITH_HINTS;
+
         // xid_min.
         mvccCrd = PageUtils.getLong(addr, off);
         mvccCntr = PageUtils.getLong(addr, off + 8);
@@ -178,6 +183,9 @@
         mvccOpCntr = withHint & MVCC_OP_COUNTER_MASK;
         mvccTxState = (byte)(withHint >>> MVCC_HINTS_BIT_OFF);
 
+        if (addHints && mvccTxState == TxState.NA)
+            mvccTxState = MvccUtils.state(sharedCtx.coordinators(), mvccCrd, mvccCntr, mvccOpCntr);
+
         assert MvccUtils.mvccVersionIsValid(mvccCrd, mvccCntr, mvccOpCntr);
 
         keyAbsentFlag = (withHint & MVCC_KEY_ABSENT_BEFORE_MASK) != 0;
@@ -193,9 +201,13 @@
 
         assert newMvccCrd == MVCC_CRD_COUNTER_NA || MvccUtils.mvccVersionIsValid(newMvccCrd, newMvccCntr, newMvccOpCntr);
 
-        if (newMvccCrd != MVCC_CRD_COUNTER_NA)
+        if (newMvccCrd != MVCC_CRD_COUNTER_NA) {
             keyAbsentFlag = (withHint & MVCC_KEY_ABSENT_BEFORE_MASK) != 0;
 
+            if (addHints && newMvccTxState == TxState.NA)
+                newMvccTxState = MvccUtils.state(sharedCtx.coordinators(), newMvccCrd, newMvccCntr, newMvccOpCntr);
+        }
+
         return MVCC_INFO_SIZE;
     }
 
@@ -233,6 +245,8 @@
 
     /** {@inheritDoc} */
     @Override public int newMvccOperationCounter() {
+        assert (newMvccOpCntr & ~MVCC_OP_COUNTER_MASK) == 0;
+
         return newMvccOpCntr;
     }
 
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/tree/mvcc/search/MvccSnapshotSearchRow.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/tree/mvcc/search/MvccSnapshotSearchRow.java
index 432593d..c0bc634f 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/tree/mvcc/search/MvccSnapshotSearchRow.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/tree/mvcc/search/MvccSnapshotSearchRow.java
@@ -59,7 +59,7 @@
      */
     public MvccSnapshotSearchRow(GridCacheContext cctx, KeyCacheObject key,
         MvccSnapshot snapshot) {
-        super(cctx.cacheId(), key, snapshot.coordinatorVersion(), snapshot.counter(), Integer.MAX_VALUE);
+        super(cctx.cacheId(), key, snapshot.coordinatorVersion(), snapshot.counter(), MvccUtils.MVCC_READ_OP_CNTR);
 
         this.cctx = cctx;
 
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cluster/BaselineConfigurationMXBeanImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cluster/BaselineConfigurationMXBeanImpl.java
new file mode 100644
index 0000000..9b55978
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cluster/BaselineConfigurationMXBeanImpl.java
@@ -0,0 +1,69 @@
+/*
+ * 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.cluster;
+
+import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.IgniteException;
+import org.apache.ignite.internal.GridKernalContext;
+import org.apache.ignite.internal.cluster.DistributedBaselineConfiguration;
+import org.apache.ignite.mxbean.BaselineConfigurationMXBean;
+
+/**
+ * {@link BaselineConfigurationMXBean} implementation.
+ */
+public class BaselineConfigurationMXBeanImpl implements BaselineConfigurationMXBean {
+    /** */
+    private final DistributedBaselineConfiguration baselineConfiguration;
+
+    /**
+     * @param ctx Context.
+     */
+    public BaselineConfigurationMXBeanImpl(GridKernalContext ctx) {
+        baselineConfiguration = ctx.cluster().get().baselineConfiguration();
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean isAutoAdjustmentEnabled() {
+        return baselineConfiguration.isBaselineAutoAdjustEnabled();
+    }
+
+    /** {@inheritDoc} */
+    @Override public long getAutoAdjustmentTimeout() {
+        return baselineConfiguration.getBaselineAutoAdjustTimeout();
+    }
+
+    /** {@inheritDoc} */
+    @Override public void setAutoAdjustmentEnabled(boolean enabled) {
+        try {
+            baselineConfiguration.updateBaselineAutoAdjustEnabledAsync(enabled).get();
+        }
+        catch (IgniteCheckedException e) {
+            throw new IgniteException(e);
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override public void setAutoAdjustmentTimeout(long timeout) {
+        try {
+            baselineConfiguration.updateBaselineAutoAdjustTimeoutAsync(timeout).get();
+        }
+        catch (IgniteCheckedException e) {
+            throw new IgniteException(e);
+        }
+    }
+}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cluster/ClusterProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cluster/ClusterProcessor.java
index f9e5efe..cd43e34 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cluster/ClusterProcessor.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cluster/ClusterProcessor.java
@@ -48,6 +48,7 @@
 import org.apache.ignite.internal.managers.eventstorage.GridLocalEventListener;
 import org.apache.ignite.internal.processors.GridProcessorAdapter;
 import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion;
+import org.apache.ignite.internal.processors.cluster.baseline.autoadjust.BaselineAutoAdjustStatistic;
 import org.apache.ignite.internal.processors.cluster.baseline.autoadjust.ChangeTopologyWatcher;
 import org.apache.ignite.internal.processors.timeout.GridTimeoutObject;
 import org.apache.ignite.internal.util.GridTimerTask;
@@ -126,6 +127,9 @@
     /** */
     private boolean sndMetrics;
 
+    /** Watcher of topology change for baseline auto-adjust. */
+    private ChangeTopologyWatcher changeTopologyWatcher;
+
     /**
      * @param ctx Kernal context.
      */
@@ -172,7 +176,10 @@
             }
         }, EVT_NODE_FAILED, EVT_NODE_LEFT);
 
-        ctx.event().addLocalEventListener(new ChangeTopologyWatcher(ctx), EVT_NODE_FAILED, EVT_NODE_LEFT, EVT_NODE_JOINED);
+        ctx.event().addLocalEventListener(
+            changeTopologyWatcher = new ChangeTopologyWatcher(ctx),
+            EVT_NODE_FAILED, EVT_NODE_LEFT, EVT_NODE_JOINED
+        );
 
         ctx.io().addMessageListener(TOPIC_INTERNAL_DIAGNOSTIC, new GridMessageListener() {
             @Override public void onMessage(UUID nodeId, Object msg, byte plc) {
@@ -640,6 +647,13 @@
     }
 
     /**
+     * @return Statistic of baseline auto-adjust.
+     */
+    public BaselineAutoAdjustStatistic baselineAutoAdjustStatistic(){
+        return changeTopologyWatcher.getStatistic();
+    }
+
+    /**
      * Update notifier timer task.
      */
     private static class UpdateNotifierTimerTask extends GridTimerTask {
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cluster/baseline/autoadjust/BaselineAutoAdjustData.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cluster/baseline/autoadjust/BaselineAutoAdjustData.java
index a913d09..bb393a3 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cluster/baseline/autoadjust/BaselineAutoAdjustData.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cluster/baseline/autoadjust/BaselineAutoAdjustData.java
@@ -17,30 +17,40 @@
 
 package org.apache.ignite.internal.processors.cluster.baseline.autoadjust;
 
-import org.apache.ignite.events.Event;
-
 /**
  * Container of required data for changing baseline.
  */
 class BaselineAutoAdjustData {
-    /** Event with which this data correspond to. For statistic only. */
-    private final Event reasonEvent;
+    /** Task represented NULL value is using when normal task can not be created. */
+    public static final BaselineAutoAdjustData NULL_BASELINE_DATA = nullValue();
     /** Topology version nodes of which should be set to baseline by this task. */
     private final long targetTopologyVersion;
 
     /** {@code true} If this data don't actual anymore and it setting should be skipped. */
     private volatile boolean invalidated = false;
+    /** {@code true} If this data was adjusted. */
+    private volatile boolean adjusted = false;
 
     /**
-     * @param evt Event with which this data correspond to. For statistic only.
      * @param targetTopologyVersion Topology version nodes of which should be set by this task.
      */
-    BaselineAutoAdjustData(Event evt, long targetTopologyVersion) {
-        reasonEvent = evt;
+    BaselineAutoAdjustData(long targetTopologyVersion) {
         this.targetTopologyVersion = targetTopologyVersion;
     }
 
     /**
+     * @return New null value.
+     */
+    private static BaselineAutoAdjustData nullValue() {
+        BaselineAutoAdjustData data = new BaselineAutoAdjustData(-1);
+
+        data.onInvalidate();
+        data.onAdjust();
+
+        return data;
+    }
+
+    /**
      * Mark that this data are invalid.
      */
     private void onInvalidate() {
@@ -48,6 +58,13 @@
     }
 
     /**
+     * Mark that this data was adjusted.
+     */
+    public void onAdjust() {
+        adjusted = true;
+    }
+
+    /**
      * @return Topology version nodes of which should be set to baseline by this task.
      */
     public long getTargetTopologyVersion() {
@@ -55,21 +72,27 @@
     }
 
     /**
-     * @return {@code true} If this data still actual and can be set.
+     * @return {@code true} If this data already invalidated and can not be set.
      */
     public boolean isInvalidated() {
         return invalidated;
     }
 
     /**
+     * @return {@code true} If this data already adjusted.
+     */
+    public boolean isAdjusted() {
+        return adjusted;
+    }
+
+    /**
      * Produce next set baseline data based on this data.
      *
-     * @param evt New triggired event.
      * @return New set baseline data.
      */
-    public BaselineAutoAdjustData next(Event evt, long targetTopologyVersion) {
+    public BaselineAutoAdjustData next(long targetTopologyVersion) {
         onInvalidate();
 
-        return new BaselineAutoAdjustData(evt, targetTopologyVersion);
+        return new BaselineAutoAdjustData(targetTopologyVersion);
     }
 }
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cluster/baseline/autoadjust/BaselineAutoAdjustExecutor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cluster/baseline/autoadjust/BaselineAutoAdjustExecutor.java
index b560932..b90df68 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cluster/baseline/autoadjust/BaselineAutoAdjustExecutor.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cluster/baseline/autoadjust/BaselineAutoAdjustExecutor.java
@@ -76,6 +76,8 @@
                     log.error("Error during baseline changing", e);
                 }
                 finally {
+                    data.onAdjust();
+
                     executionGuard.unlock();
                 }
             }
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cluster/baseline/autoadjust/BaselineAutoAdjustScheduler.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cluster/baseline/autoadjust/BaselineAutoAdjustScheduler.java
index d89ba85..f6e41db 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cluster/baseline/autoadjust/BaselineAutoAdjustScheduler.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cluster/baseline/autoadjust/BaselineAutoAdjustScheduler.java
@@ -30,14 +30,15 @@
     private final GridTimeoutProcessor timeoutProcessor;
     /** Executor of set baseline operation. */
     private final BaselineAutoAdjustExecutor baselineAutoAdjustExecutor;
-    /** Last set task for set new baseline. It needed for removing from queue. */
+    /** Last scheduled task for adjust new baseline. It needed for removing from queue. */
     private GridTimeoutObject baselineTimeoutObj;
 
     /**
      * @param timeoutProcessor Timeout processor.
      * @param baselineAutoAdjustExecutor Executor of set baseline operation.
      */
-    public BaselineAutoAdjustScheduler(GridTimeoutProcessor timeoutProcessor, BaselineAutoAdjustExecutor baselineAutoAdjustExecutor) {
+    public BaselineAutoAdjustScheduler(GridTimeoutProcessor timeoutProcessor,
+        BaselineAutoAdjustExecutor baselineAutoAdjustExecutor) {
         this.timeoutProcessor = timeoutProcessor;
         this.baselineAutoAdjustExecutor = baselineAutoAdjustExecutor;
     }
@@ -60,4 +61,16 @@
             }
         );
     }
+
+    /**
+     * @return Time of last scheduled task or -1 if it doesn't exist.
+     */
+    public long lastScheduledTaskTime() {
+        if (baselineTimeoutObj == null)
+            return -1;
+
+        long lastScheduledTaskTime = baselineTimeoutObj.endTime() - System.currentTimeMillis();
+
+        return lastScheduledTaskTime < 0 ? -1 : lastScheduledTaskTime;
+    }
 }
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cluster/baseline/autoadjust/BaselineAutoAdjustStatistic.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cluster/baseline/autoadjust/BaselineAutoAdjustStatistic.java
new file mode 100644
index 0000000..3847bae
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cluster/baseline/autoadjust/BaselineAutoAdjustStatistic.java
@@ -0,0 +1,90 @@
+/*
+ * 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.cluster.baseline.autoadjust;
+
+/**
+ * Statistic of baseline auto-adjust.
+ */
+public class BaselineAutoAdjustStatistic {
+    /** Timeout of task of baseline adjust. */
+    private final long baselineAdjustTimeout;
+    /** State of baseline adjust task. */
+    private final TaskState taskState;
+
+    /**
+     * @param timeout Timeout of baseline adjust.
+     */
+    private BaselineAutoAdjustStatistic(TaskState state, long timeout) {
+        baselineAdjustTimeout = timeout;
+        taskState = state;
+    }
+
+    /**
+     * @param timeout Timeout of task of baseline adjust.
+     * @return Created statistic object.
+     */
+    public static BaselineAutoAdjustStatistic scheduled(long timeout) {
+        return new BaselineAutoAdjustStatistic(TaskState.SCHEDULED, timeout);
+    }
+
+    /**
+     * @return Created statistic object with 'in progress' status.
+     */
+    public static BaselineAutoAdjustStatistic inProgress() {
+        return new BaselineAutoAdjustStatistic(TaskState.IN_PROGRESS, -1);
+    }
+
+    /**
+     * @return Created statistic object with 'not scheduled' status.
+     */
+    public static BaselineAutoAdjustStatistic notScheduled() {
+        return new BaselineAutoAdjustStatistic(TaskState.NOT_SCHEDULED, -1);
+    }
+
+    /**
+     * @return Timeout of task of baseline adjust.
+     */
+    public long getBaselineAdjustTimeout() {
+        return baselineAdjustTimeout;
+    }
+
+    /**
+     * @return State of baseline adjust task.
+     */
+    public TaskState getTaskState() {
+        return taskState;
+    }
+
+    /**
+     *
+     */
+    public enum TaskState {
+        /**
+         * Baseline is changing now.
+         */
+        IN_PROGRESS,
+        /**
+         * Task to baseline adjust was scheduled.
+         */
+        SCHEDULED,
+        /**
+         * Task to baseline adjust was not scheduled.
+         */
+        NOT_SCHEDULED;
+    }
+}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cluster/baseline/autoadjust/ChangeTopologyWatcher.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cluster/baseline/autoadjust/ChangeTopologyWatcher.java
index ad63d13..2448810 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cluster/baseline/autoadjust/ChangeTopologyWatcher.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cluster/baseline/autoadjust/ChangeTopologyWatcher.java
@@ -17,7 +17,6 @@
 
 package org.apache.ignite.internal.processors.cluster.baseline.autoadjust;
 
-import org.apache.ignite.IgniteCheckedException;
 import org.apache.ignite.IgniteLogger;
 import org.apache.ignite.events.DiscoveryEvent;
 import org.apache.ignite.events.Event;
@@ -32,14 +31,15 @@
 import org.apache.ignite.internal.processors.cluster.GridClusterStateProcessor;
 import org.apache.ignite.lang.IgniteInClosure;
 
+import static org.apache.ignite.internal.processors.cluster.baseline.autoadjust.BaselineAutoAdjustData.NULL_BASELINE_DATA;
+import static org.apache.ignite.internal.processors.cluster.baseline.autoadjust.BaselineAutoAdjustStatistic.TaskState.IN_PROGRESS;
+import static org.apache.ignite.internal.processors.cluster.baseline.autoadjust.BaselineAutoAdjustStatistic.TaskState.NOT_SCHEDULED;
 import static org.apache.ignite.internal.util.IgniteUtils.isLocalNodeCoordinator;
 
 /**
  * Watcher of topology changes. It initiate to set new baseline after some timeout.
  */
 public class ChangeTopologyWatcher implements GridLocalEventListener {
-    /** Task represented NULL value is using when normal task can not be created. */
-    private static final BaselineAutoAdjustData NULL_BASELINE_DATA = new BaselineAutoAdjustData(null, -1);
     /** */
     private final IgniteLogger log;
     /** */
@@ -92,7 +92,7 @@
             return;
 
         synchronized (this) {
-            lastBaselineData = lastBaselineData.next(evt, discoEvt.topologyVersion());
+            lastBaselineData = lastBaselineData.next(discoEvt.topologyVersion());
 
             if (isLocalNodeCoordinator(discoveryMgr)) {
                 exchangeManager.affinityReadyFuture(new AffinityTopologyVersion(discoEvt.topologyVersion()))
@@ -123,4 +123,21 @@
     private boolean isBaselineAutoAdjustEnabled() {
         return stateProcessor.clusterState().active() && baselineConfiguration.isBaselineAutoAdjustEnabled();
     }
+
+    /**
+     * @return Statistic of baseline auto-adjust.
+     */
+    public BaselineAutoAdjustStatistic getStatistic() {
+        synchronized (this) {
+            if (lastBaselineData.isAdjusted())
+                return BaselineAutoAdjustStatistic.notScheduled();
+
+            long timeToLastTask = baselineAutoAdjustScheduler.lastScheduledTaskTime();
+
+            if (timeToLastTask <= 0)
+                return BaselineAutoAdjustStatistic.inProgress();
+
+            return BaselineAutoAdjustStatistic.scheduled(timeToLastTask);
+        }
+    }
 }
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcBatchExecuteRequest.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcBatchExecuteRequest.java
index 42b1936..b09f968 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcBatchExecuteRequest.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcBatchExecuteRequest.java
@@ -183,6 +183,6 @@
 
     /** {@inheritDoc} */
     @Override public String toString() {
-        return S.toString(JdbcBatchExecuteRequest.class, this);
+        return S.toString(JdbcBatchExecuteRequest.class, this, super.toString());
     }
 }
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcBatchExecuteResult.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcBatchExecuteResult.java
index 0d93244e..b40674a 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcBatchExecuteResult.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcBatchExecuteResult.java
@@ -120,6 +120,6 @@
 
     /** {@inheritDoc} */
     @Override public String toString() {
-        return S.toString(JdbcBatchExecuteResult.class, this);
+        return S.toString(JdbcBatchExecuteResult.class, this, super.toString());
     }
 }
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcOrderedBatchExecuteRequest.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcOrderedBatchExecuteRequest.java
index 743978d..44ff9ef 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcOrderedBatchExecuteRequest.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcOrderedBatchExecuteRequest.java
@@ -77,7 +77,7 @@
 
     /** {@inheritDoc} */
     @Override public String toString() {
-        return S.toString(JdbcOrderedBatchExecuteRequest.class, this);
+        return S.toString(JdbcOrderedBatchExecuteRequest.class, this, super.toString());
     }
 
     /** {@inheritDoc} */
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcOrderedBatchExecuteResult.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcOrderedBatchExecuteResult.java
index 76f665f..6f4ea04 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcOrderedBatchExecuteResult.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcOrderedBatchExecuteResult.java
@@ -73,6 +73,6 @@
 
     /** {@inheritDoc} */
     @Override public String toString() {
-        return S.toString(JdbcOrderedBatchExecuteResult.class, this);
+        return S.toString(JdbcOrderedBatchExecuteResult.class, this, super.toString());
     }
 }
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcQueryExecuteRequest.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcQueryExecuteRequest.java
index 9b92323..b2f4aea 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcQueryExecuteRequest.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcQueryExecuteRequest.java
@@ -192,6 +192,6 @@
 
     /** {@inheritDoc} */
     @Override public String toString() {
-        return S.toString(JdbcQueryExecuteRequest.class, this);
+        return S.toString(JdbcQueryExecuteRequest.class, this, super.toString());
     }
 }
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcQueryExecuteResult.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcQueryExecuteResult.java
index 0b91555..7fbef44 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcQueryExecuteResult.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcQueryExecuteResult.java
@@ -154,6 +154,6 @@
 
     /** {@inheritDoc} */
     @Override public String toString() {
-        return S.toString(JdbcQueryExecuteResult.class, this);
+        return S.toString(JdbcQueryExecuteResult.class, this, super.toString());
     }
 }
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcRequest.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcRequest.java
index f611c8c..04d0166 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcRequest.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcRequest.java
@@ -26,6 +26,7 @@
 import org.apache.ignite.internal.binary.streams.BinaryInputStream;
 import org.apache.ignite.internal.processors.odbc.ClientListenerProtocolVersion;
 import org.apache.ignite.internal.processors.odbc.ClientListenerRequestNoId;
+import org.apache.ignite.internal.util.typedef.internal.S;
 
 import static org.apache.ignite.internal.processors.odbc.jdbc.JdbcConnectionContext.VER_2_8_0;
 
@@ -237,4 +238,9 @@
 
         return stream.readLong();
     }
+
+    /** {@inheritDoc} */
+    @Override public String toString() {
+        return S.toString(JdbcRequest.class, this);
+    }
 }
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcRequestHandler.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcRequestHandler.java
index e968574..d0febd0 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcRequestHandler.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcRequestHandler.java
@@ -251,8 +251,7 @@
         assert reqId != 0;
 
         synchronized (reqMux) {
-            if (isCancellationSupported() && (cmdType == QRY_EXEC || cmdType == BATCH_EXEC ||
-                cmdType == BATCH_EXEC_ORDERED))
+            if (isCancellationSupported() && (cmdType == QRY_EXEC || cmdType == BATCH_EXEC))
                 reqRegister.put(reqId, new JdbcQueryDescriptor());
         }
     }
@@ -348,16 +347,17 @@
      * @return Response.
      */
     private ClientListenerResponse dispatchBatchOrdered(JdbcOrderedBatchExecuteRequest req) {
-        synchronized (orderedBatchesMux) {
-            orderedBatchesQueue.add(req);
-
-            orderedBatchesMux.notify();
-        }
-
         if (!cliCtx.isStreamOrdered())
             executeBatchOrdered(req);
+        else {
+            synchronized (orderedBatchesMux) {
+                orderedBatchesQueue.add(req);
 
-        return null;
+                orderedBatchesMux.notifyAll();
+            }
+        }
+
+       return null;
     }
 
     /**
@@ -383,10 +383,6 @@
             sender.send(new JdbcResponse(IgniteQueryErrorCode.UNKNOWN, "Server error: " + e));
         }
 
-        synchronized (orderedBatchesMux) {
-            orderedBatchesQueue.poll();
-        }
-
         cliCtx.orderedRequestProcessed();
 
         return null;
@@ -835,7 +831,10 @@
     private ClientListenerResponse executeBatch(JdbcBatchExecuteRequest req) {
         GridQueryCancel cancel = null;
 
-        if (isCancellationSupported()) {
+        // Skip request register check for ORDERED batches (JDBC streams)
+        // because ordered batch requests are processed asynchronously at the
+        // separate thread.
+        if (isCancellationSupported() && req.type() == BATCH_EXEC) {
             synchronized (reqMux) {
                 JdbcQueryDescriptor desc = reqRegister.get(req.requestId());
 
@@ -1184,6 +1183,8 @@
 
                         continue;
                     }
+                    else
+                        orderedBatchesQueue.poll();
                 }
 
                 executeBatchOrdered(req);
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcResult.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcResult.java
index 3a0d7bb..5463d7e 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcResult.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcResult.java
@@ -22,6 +22,7 @@
 import org.apache.ignite.internal.binary.BinaryReaderExImpl;
 import org.apache.ignite.internal.binary.BinaryWriterExImpl;
 import org.apache.ignite.internal.processors.odbc.ClientListenerProtocolVersion;
+import org.apache.ignite.internal.util.typedef.internal.S;
 
 /**
  * JDBC response result.
@@ -199,4 +200,9 @@
 
         return res;
     }
+
+    /** {@inheritDoc} */
+    @Override public String toString() {
+        return S.toString(JdbcResult.class, this);
+    }
 }
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/odbc/OdbcRequestHandler.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/odbc/OdbcRequestHandler.java
index 4723742..d1ebaa9 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/odbc/OdbcRequestHandler.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/odbc/OdbcRequestHandler.java
@@ -474,14 +474,15 @@
      * @return Response.
      */
     private ClientListenerResponse dispatchBatchOrdered(OdbcStreamingBatchRequest req) {
-        synchronized (orderedBatchesMux) {
-            orderedBatchesQueue.add(req);
-
-            orderedBatchesMux.notify();
-        }
-
         if (!cliCtx.isStreamOrdered())
             processStreamingBatchOrdered(req);
+        else {
+            synchronized (orderedBatchesMux) {
+                orderedBatchesQueue.add(req);
+
+                orderedBatchesMux.notifyAll();
+            }
+        }
 
         return null;
     }
@@ -501,10 +502,6 @@
             sender.send(new OdbcResponse(IgniteQueryErrorCode.UNKNOWN, "Server error: " + e));
         }
 
-        synchronized (orderedBatchesMux) {
-            orderedBatchesQueue.poll();
-        }
-
         cliCtx.orderedRequestProcessed();
     }
 
@@ -1022,6 +1019,8 @@
 
                         continue;
                     }
+                    else
+                        orderedBatchesQueue.poll();
                 }
 
                 processStreamingBatchOrdered(req);
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryIndexing.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryIndexing.java
index f6215b7..557e3ec 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryIndexing.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryIndexing.java
@@ -31,7 +31,6 @@
 import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion;
 import org.apache.ignite.internal.processors.cache.GridCacheContext;
 import org.apache.ignite.internal.processors.cache.GridCacheContextInfo;
-import org.apache.ignite.internal.processors.cache.mvcc.MvccQueryTracker;
 import org.apache.ignite.internal.processors.cache.mvcc.MvccSnapshot;
 import org.apache.ignite.internal.processors.cache.persistence.CacheDataRow;
 import org.apache.ignite.internal.processors.query.schema.SchemaIndexCacheVisitor;
@@ -85,14 +84,16 @@
      * @param cliCtx Client context.
      * @param keepBinary Keep binary flag.
      * @param failOnMultipleStmts Whether an exception should be thrown for multiple statements query.
-     * @param tracker Query tracker.
-     * @param registerAsNewQry {@code true} In case it's new query which should be registered as running query,
-     * {@code false} otherwise.
      * @return Cursor.
      */
-    public List<FieldsQueryCursor<List<?>>> querySqlFields(String schemaName, SqlFieldsQuery qry,
-        SqlClientContext cliCtx, boolean keepBinary, boolean failOnMultipleStmts, MvccQueryTracker tracker,
-        GridQueryCancel cancel, boolean registerAsNewQry);
+    public List<FieldsQueryCursor<List<?>>> querySqlFields(
+        String schemaName,
+        SqlFieldsQuery qry,
+        SqlClientContext cliCtx,
+        boolean keepBinary,
+        boolean failOnMultipleStmts,
+        GridQueryCancel cancel
+    );
 
     /**
      * Execute an INSERT statement using data streamer as receiver.
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java
index b6af8ca..bac148d 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java
@@ -1501,7 +1501,7 @@
     /**
      * Create cache and table from given query entity.
      *
-     * @param schemaName Schema name to create table in.
+     * @param schemaName Schema name to create table in. Case sensitive, must not be \"quoted\".
      * @param entity Entity to create table from.
      * @param templateName Template name.
      * @param cacheName Cache name.
@@ -1579,7 +1579,7 @@
             ccfg.setQueryParallelism(qryParallelism);
 
         ccfg.setEncryptionEnabled(encrypted);
-        ccfg.setSqlSchema(schemaName);
+        ccfg.setSqlSchema("\"" + schemaName + "\"");
         ccfg.setSqlEscapeAll(true);
         ccfg.setQueryEntities(Collections.singleton(entity));
 
@@ -2231,6 +2231,8 @@
             throw new CacheException("Execution of local SqlFieldsQuery on client node disallowed.");
 
         return executeQuerySafe(cctx, () -> {
+            assert idx != null;
+
             final String schemaName = qry.getSchema() != null ? qry.getSchema()
                 : (cctx != null ? idx.schema(cctx.name()) : QueryUtils.DFLT_SCHEMA);
 
@@ -2239,16 +2241,13 @@
                     @Override public List<FieldsQueryCursor<List<?>>> applyx() {
                         GridQueryCancel cancel0 = cancel != null ? cancel : new GridQueryCancel();
 
-                        List<FieldsQueryCursor<List<?>>> res =
-                            idx.querySqlFields(
+                        List<FieldsQueryCursor<List<?>>> res = idx.querySqlFields(
                                 schemaName,
                                 qry,
                                 cliCtx,
                                 keepBinary,
                                 failOnMultipleStmts,
-                                null,
-                                cancel0,
-                                true
+                                cancel0
                             );
 
                         if (cctx != null)
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/QueryHistoryMetrics.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/QueryHistoryMetrics.java
index 0f8a07d..1d494ac 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/QueryHistoryMetrics.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/QueryHistoryMetrics.java
@@ -44,17 +44,16 @@
      * @param qry Textual query representation.
      * @param schema Schema name.
      * @param loc {@code true} for local query.
-     * @param startTime Duration of queue execution.
-     * @param duration Duration of queue execution.
+     * @param startTime Start time of query execution.
+     * @param duration Duration of query execution.
      * @param failed {@code True} query executed unsuccessfully {@code false} otherwise.
      */
     public QueryHistoryMetrics(String qry, String schema, boolean loc, long startTime, long duration, boolean failed) {
         key = new QueryHistoryMetricsKey(qry, schema, loc);
 
-        if (failed)
-            val = new QueryHistoryMetricsValue(1, 1, 0, 0, startTime);
-        else
-            val = new QueryHistoryMetricsValue(1, 0, duration, duration, startTime);
+        long failures = failed ? 1 : 0;
+
+        val = new QueryHistoryMetricsValue(1, failures, duration, duration, startTime);
 
         linkRef = new AtomicReference<>();
     }
@@ -109,7 +108,7 @@
      *
      * @return Number of executions.
      */
-    public int executions() {
+    public long executions() {
         return val.execs();
     }
 
@@ -118,7 +117,7 @@
      *
      * @return Number of times a query execution failed.
      */
-    public int failures() {
+    public long failures() {
         return val.failures();
     }
 
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/QueryHistoryMetricsValue.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/QueryHistoryMetricsValue.java
index c37e141..babac6d 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/QueryHistoryMetricsValue.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/QueryHistoryMetricsValue.java
@@ -23,10 +23,10 @@
  */
 class QueryHistoryMetricsValue {
     /** Number of executions. */
-    private final int execs;
+    private final long execs;
 
     /** Number of failures. */
-    private final int failures;
+    private final long failures;
 
     /** Minimum time of execution. */
     private final long minTime;
@@ -44,7 +44,7 @@
      * @param maxTime Max time of execution.
      * @param lastStartTime Last start time of execution.
      */
-    public QueryHistoryMetricsValue(int execs, int failures, long minTime, long maxTime, long lastStartTime) {
+    public QueryHistoryMetricsValue(long execs, long failures, long minTime, long maxTime, long lastStartTime) {
         this.execs = execs;
         this.failures = failures;
         this.minTime = minTime;
@@ -57,7 +57,7 @@
      *
      * @return Number of executions.
      */
-    public int execs() {
+    public long execs() {
         return execs;
     }
 
@@ -66,7 +66,7 @@
      *
      * @return Number of times a query execution failed.
      */
-    public int failures() {
+    public long failures() {
         return failures;
     }
 
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/SqlClientContext.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/SqlClientContext.java
index f51fdb4..4296704 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/SqlClientContext.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/SqlClientContext.java
@@ -61,8 +61,8 @@
     /** Data page scan support for query execution. */
     private final @Nullable Boolean dataPageScanEnabled;
 
-    /** Monitor. */
-    private final Object mux = new Object();
+    /** Monitor for stream operations. */
+    private final Object muxStreamer = new Object();
 
     /** Allow overwrites for duplicate keys on streamed {@code INSERT}s. */
     private boolean streamAllowOverwrite;
@@ -133,7 +133,7 @@
      */
     public void enableStreaming(boolean allowOverwrite, long flushFreq, int perNodeBufSize,
         int perNodeParOps, boolean ordered) {
-        synchronized (mux) {
+        synchronized (muxStreamer) {
             if (isStream())
                 return;
 
@@ -144,6 +144,7 @@
             this.streamNodeBufSize = perNodeBufSize;
             this.streamNodeParOps = perNodeParOps;
             this.streamOrdered = ordered;
+            this.totalProcessedOrderedReqs = 0;
 
             if (ordered) {
                 orderedBatchThread = new IgniteThread(orderedBatchWorkerFactory.create());
@@ -157,7 +158,7 @@
      * Turn off streaming on this client context - with closing all open streamers, if any.
      */
     public void disableStreaming() {
-        synchronized (mux) {
+        synchronized (muxStreamer) {
             if (!isStream())
                 return;
 
@@ -172,8 +173,8 @@
             }
 
             streamers = null;
-
             orderedBatchThread = null;
+            totalProcessedOrderedReqs = 0;
         }
     }
 
@@ -230,7 +231,7 @@
      * @return Streaming state flag (on or off).
      */
     public boolean isStream() {
-        synchronized (mux) {
+        synchronized (muxStreamer) {
             return streamers != null;
         }
     }
@@ -239,7 +240,7 @@
      * @return Stream ordered flag.
      */
     public boolean isStreamOrdered() {
-        synchronized (mux) {
+        synchronized (muxStreamer) {
             return streamOrdered;
         }
     }
@@ -249,7 +250,7 @@
      * @return Streamer for given cache.
      */
     public IgniteDataStreamer<?, ?> streamerForCache(String cacheName) {
-        synchronized (mux) {
+        synchronized (muxStreamer) {
             if (streamers == null)
                 return null;
 
@@ -281,10 +282,10 @@
      * @param total Expected total processed request.
      */
     public void waitTotalProcessedOrderedRequests(long total) {
-        synchronized (mux) {
+        synchronized (muxStreamer) {
             while (totalProcessedOrderedReqs < total) {
                 try {
-                    mux.wait();
+                    muxStreamer.wait();
                 }
                 catch (InterruptedException e) {
                     throw new IgniteException("Waiting for end of processing the last batch is interrupted", e);
@@ -297,10 +298,10 @@
      *
      */
     public void orderedRequestProcessed() {
-        synchronized (mux) {
+        synchronized (muxStreamer) {
             totalProcessedOrderedReqs++;
 
-            mux.notify();
+            muxStreamer.notifyAll();
         }
     }
 
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/service/IgniteServiceProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/service/IgniteServiceProcessor.java
index d993803..1e4f22b 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/service/IgniteServiceProcessor.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/service/IgniteServiceProcessor.java
@@ -52,6 +52,7 @@
 import org.apache.ignite.internal.IgniteInternalFuture;
 import org.apache.ignite.internal.IgniteInterruptedCheckedException;
 import org.apache.ignite.internal.SkipDaemon;
+import org.apache.ignite.internal.managers.deployment.GridDeployment;
 import org.apache.ignite.internal.managers.discovery.CustomEventListener;
 import org.apache.ignite.internal.managers.discovery.DiscoCache;
 import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion;
@@ -1239,9 +1240,14 @@
      */
     private Service copyAndInject(ServiceConfiguration cfg) throws IgniteCheckedException {
         if (cfg instanceof LazyServiceConfiguration) {
+            LazyServiceConfiguration srvcCfg = (LazyServiceConfiguration)cfg;
+
+            GridDeployment srvcDep = ctx.deploy().getDeployment(srvcCfg.serviceClassName());
+
             byte[] bytes = ((LazyServiceConfiguration)cfg).serviceBytes();
 
-            Service srvc = U.unmarshal(marsh, bytes, U.resolveClassLoader(null, ctx.config()));
+            Service srvc = U.unmarshal(marsh, bytes,
+                U.resolveClassLoader(srvcDep != null ? srvcDep.classLoader() : null, ctx.config()));
 
             ctx.resource().inject(srvc);
 
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/util/future/GridFutureAdapter.java b/modules/core/src/main/java/org/apache/ignite/internal/util/future/GridFutureAdapter.java
index cddb19c..ea670dc 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/util/future/GridFutureAdapter.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/util/future/GridFutureAdapter.java
@@ -251,10 +251,10 @@
      * @throws IgniteCheckedException If resolved to exception.
      */
     private R resolve() throws IgniteCheckedException {
-        if(state == CANCELLED)
+        if (state == CANCELLED)
             throw new IgniteFutureCancelledCheckedException("Future was cancelled: " + this);
 
-        if(state == null || state.getClass() != ErrorWrapper.class)
+        if (state == null || state.getClass() != ErrorWrapper.class)
             return (R)state;
 
         throw U.cast(((ErrorWrapper)state).error);
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/visor/baseline/VisorBaselineAutoAdjustSettings.java b/modules/core/src/main/java/org/apache/ignite/internal/visor/baseline/VisorBaselineAutoAdjustSettings.java
index c8f8727..d2f16d4 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/visor/baseline/VisorBaselineAutoAdjustSettings.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/visor/baseline/VisorBaselineAutoAdjustSettings.java
@@ -28,45 +28,55 @@
     private static final long serialVersionUID = 0L;
 
     /** "Enable" flag. */
-    private boolean enabled;
+    public Boolean enabled;
 
     /** Soft timeout. */
-    private long softTimeout;
+    public Long softTimeout;
 
     /** Default constructor. */
     public VisorBaselineAutoAdjustSettings() {
     }
 
     /** Constructor. */
-    public VisorBaselineAutoAdjustSettings(boolean enabled, long softTimeout) {
-        this.enabled= enabled;
+    public VisorBaselineAutoAdjustSettings(Boolean enabled, Long softTimeout) {
+        this.enabled = enabled;
         this.softTimeout = softTimeout;
     }
 
     /**
      * @return "Enable" flag.
      */
-    public boolean isEnabled() {
+    public Boolean getEnabled() {
         return enabled;
     }
 
     /**
      * Soft timeout.
      */
-    public long getSoftTimeout() {
+    public Long getSoftTimeout() {
         return softTimeout;
     }
 
     /** {@inheritDoc} */
     @Override protected void writeExternalData(ObjectOutput out) throws IOException {
-        out.writeBoolean(enabled);
-        out.writeLong(softTimeout);
+        out.writeBoolean(enabled != null);
+
+        if (enabled != null)
+            out.writeBoolean(enabled);
+
+        out.writeBoolean(softTimeout != null);
+
+        if (softTimeout != null)
+            out.writeLong(softTimeout);
     }
 
     /** {@inheritDoc} */
     @Override
     protected void readExternalData(byte protoVer, ObjectInput in) throws IOException, ClassNotFoundException {
-        enabled = in.readBoolean();
-        softTimeout = in.readLong();
+        if (in.readBoolean())
+            enabled = in.readBoolean();
+
+        if (in.readBoolean())
+            softTimeout = in.readLong();
     }
 }
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/visor/baseline/VisorBaselineTask.java b/modules/core/src/main/java/org/apache/ignite/internal/visor/baseline/VisorBaselineTask.java
index 6a074ae..aa74ea9 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/visor/baseline/VisorBaselineTask.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/visor/baseline/VisorBaselineTask.java
@@ -30,6 +30,7 @@
 import org.apache.ignite.internal.cluster.DistributedBaselineConfiguration;
 import org.apache.ignite.internal.cluster.DetachedClusterNode;
 import org.apache.ignite.internal.cluster.IgniteClusterEx;
+import org.apache.ignite.internal.processors.cluster.baseline.autoadjust.BaselineAutoAdjustStatistic;
 import org.apache.ignite.internal.processors.task.GridInternal;
 import org.apache.ignite.internal.processors.task.GridVisorManagementTask;
 import org.apache.ignite.internal.util.typedef.F;
@@ -81,12 +82,21 @@
             Collection<? extends BaselineNode> srvrs = cluster.forServers().nodes();
 
             VisorBaselineAutoAdjustSettings autoAdjustSettings = new VisorBaselineAutoAdjustSettings(
-                cluster.baselineConfiguration().isBaselineAutoAdjustEnabled(),
-                cluster.baselineConfiguration().getBaselineAutoAdjustTimeout()
+                cluster.isBaselineAutoAdjustEnabled(),
+                cluster.baselineAutoAdjustTimeout()
             );
 
-            return new VisorBaselineTaskResult(ignite.cluster().active(), cluster.topologyVersion(),
-                F.isEmpty(baseline) ? null : baseline, srvrs, autoAdjustSettings);
+            BaselineAutoAdjustStatistic adjustStatistic = ignite.context().cluster().baselineAutoAdjustStatistic();
+
+            return new VisorBaselineTaskResult(
+                ignite.cluster().active(),
+                cluster.topologyVersion(),
+                F.isEmpty(baseline) ? null : baseline,
+                srvrs,
+                autoAdjustSettings,
+                adjustStatistic.getBaselineAdjustTimeout(),
+                adjustStatistic.getTaskState() == BaselineAutoAdjustStatistic.TaskState.IN_PROGRESS
+            );
         }
 
         /**
@@ -220,17 +230,11 @@
          * @return New baseline.
          */
         private VisorBaselineTaskResult updateAutoAdjustmentSettings(VisorBaselineAutoAdjustSettings settings) {
-            DistributedBaselineConfiguration baselineConfiguration = ignite.cluster().baselineConfiguration();
+            if (settings.getSoftTimeout() != null)
+                ignite.cluster().baselineAutoAdjustTimeout(settings.getSoftTimeout());
 
-            try {
-                if (settings.isEnabled())
-                    baselineConfiguration.updateBaselineAutoAdjustTimeoutAsync(settings.getSoftTimeout()).get();
-
-                baselineConfiguration.updateBaselineAutoAdjustEnabledAsync(settings.isEnabled()).get();
-            }
-            catch (IgniteCheckedException e) {
-                throw U.convertException(e);
-            }
+            if (settings.getEnabled() != null)
+                ignite.cluster().baselineAutoAdjustEnabled(settings.getEnabled());
 
             return collect();
         }
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/visor/baseline/VisorBaselineTaskResult.java b/modules/core/src/main/java/org/apache/ignite/internal/visor/baseline/VisorBaselineTaskResult.java
index 1af1740..7691008 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/visor/baseline/VisorBaselineTaskResult.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/visor/baseline/VisorBaselineTaskResult.java
@@ -51,6 +51,12 @@
     /** Baseline autoadjustment settings. */
     private VisorBaselineAutoAdjustSettings autoAdjustSettings;
 
+    /** Time to next baseline adjust. */
+    private long remainingTimeToBaselineAdjust = -1;
+
+    /** Is baseline adjust in progress? */
+    private boolean baselineAdjustInProgress = false;
+
     /**
      * Default constructor.
      */
@@ -84,19 +90,24 @@
      * @param topVer Current topology version.
      * @param baseline Current baseline nodes.
      * @param servers Current server nodes.
+     * @param remainingTimeToBaselineAdjust Time to next baseline adjust.
+     * @param baselineAdjustInProgress {@code true} If baseline adjust is in progress.
      */
     public VisorBaselineTaskResult(
         boolean active,
         long topVer,
         Collection<? extends BaselineNode> baseline,
         Collection<? extends BaselineNode> servers,
-        VisorBaselineAutoAdjustSettings autoAdjustSettings
-    ) {
+        VisorBaselineAutoAdjustSettings autoAdjustSettings,
+        long remainingTimeToBaselineAdjust,
+        boolean baselineAdjustInProgress) {
         this.active = active;
         this.topVer = topVer;
         this.baseline = toMap(baseline);
         this.servers = toMap(servers);
         this.autoAdjustSettings = autoAdjustSettings;
+        this.remainingTimeToBaselineAdjust = remainingTimeToBaselineAdjust;
+        this.baselineAdjustInProgress = baselineAdjustInProgress;
     }
 
     /**
@@ -139,6 +150,20 @@
         return autoAdjustSettings;
     }
 
+    /**
+     * @return Time to next baseline adjust.
+     */
+    public long getRemainingTimeToBaselineAdjust() {
+        return remainingTimeToBaselineAdjust;
+    }
+
+    /**
+     * @return {@code true} If baseline adjust is in progress.
+     */
+    public boolean isBaselineAdjustInProgress() {
+        return baselineAdjustInProgress;
+    }
+
     /** {@inheritDoc} */
     @Override protected void writeExternalData(ObjectOutput out) throws IOException {
         out.writeBoolean(active);
@@ -146,17 +171,23 @@
         U.writeMap(out, baseline);
         U.writeMap(out, servers);
         out.writeObject(autoAdjustSettings);
+        out.writeLong(remainingTimeToBaselineAdjust);
+        out.writeBoolean(baselineAdjustInProgress);
     }
 
     /** {@inheritDoc} */
-    @Override protected void readExternalData(byte protoVer, ObjectInput in) throws IOException, ClassNotFoundException {
+    @Override protected void readExternalData(byte protoVer,
+        ObjectInput in) throws IOException, ClassNotFoundException {
         active = in.readBoolean();
         topVer = in.readLong();
         baseline = U.readTreeMap(in);
         servers = U.readTreeMap(in);
 
-        if (protoVer > V1)
+        if (protoVer > V1) {
             autoAdjustSettings = (VisorBaselineAutoAdjustSettings)in.readObject();
+            remainingTimeToBaselineAdjust = in.readLong();
+            baselineAdjustInProgress = in.readBoolean();
+        }
     }
 
     /** {@inheritDoc} */
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/visor/baseline/VisorBaselineViewTask.java b/modules/core/src/main/java/org/apache/ignite/internal/visor/baseline/VisorBaselineViewTask.java
index b62ec90..7e9a3b3 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/visor/baseline/VisorBaselineViewTask.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/visor/baseline/VisorBaselineViewTask.java
@@ -19,6 +19,7 @@
 
 import org.apache.ignite.IgniteException;
 import org.apache.ignite.internal.cluster.IgniteClusterEx;
+import org.apache.ignite.internal.processors.cluster.baseline.autoadjust.BaselineAutoAdjustStatistic;
 import org.apache.ignite.internal.processors.task.GridInternal;
 import org.apache.ignite.internal.util.typedef.internal.S;
 import org.apache.ignite.internal.visor.VisorJob;
@@ -58,16 +59,20 @@
             IgniteClusterEx cluster = ignite.cluster();
 
             VisorBaselineAutoAdjustSettings autoAdjustSettings = new VisorBaselineAutoAdjustSettings(
-                cluster.baselineConfiguration().isBaselineAutoAdjustEnabled(),
-                cluster.baselineConfiguration().getBaselineAutoAdjustTimeout()
+                cluster.isBaselineAutoAdjustEnabled(),
+                cluster.baselineAutoAdjustTimeout()
             );
 
+            BaselineAutoAdjustStatistic adjustStatistic = ignite.context().cluster().baselineAutoAdjustStatistic();
+
             return new VisorBaselineTaskResult(
                 ignite.cluster().active(),
                 cluster.topologyVersion(),
                 cluster.currentBaselineTopology(),
                 cluster.forServers().nodes(),
-                autoAdjustSettings
+                autoAdjustSettings,
+                adjustStatistic.getBaselineAdjustTimeout(),
+                adjustStatistic.getTaskState() == BaselineAutoAdjustStatistic.TaskState.IN_PROGRESS
             );
         }
 
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/visor/query/VisorQueryPingTask.java b/modules/core/src/main/java/org/apache/ignite/internal/visor/query/VisorQueryPingTask.java
new file mode 100644
index 0000000..b7d4200
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/visor/query/VisorQueryPingTask.java
@@ -0,0 +1,88 @@
+/*
+ * 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.visor.query;
+
+import org.apache.ignite.internal.processors.task.GridInternal;
+import org.apache.ignite.internal.util.typedef.internal.S;
+import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.internal.visor.VisorEither;
+import org.apache.ignite.internal.visor.VisorJob;
+import org.apache.ignite.internal.visor.VisorOneNodeTask;
+import org.apache.ignite.internal.visor.util.VisorExceptionWrapper;
+
+import static org.apache.ignite.internal.visor.query.VisorQueryUtils.getQueryHolder;
+import static org.apache.ignite.internal.visor.util.VisorTaskUtils.log;
+
+/**
+ * Task for inform a node about awaiting of query result from Web console.
+ */
+@GridInternal
+public class VisorQueryPingTask extends VisorOneNodeTask<VisorQueryNextPageTaskArg, VisorEither<VisorQueryPingTaskResult>> {
+    /** */
+    private static final long serialVersionUID = 0L;
+
+    /** {@inheritDoc} */
+    @Override protected VisorQueryFetchFirstPageJob job(VisorQueryNextPageTaskArg arg) {
+        return new VisorQueryFetchFirstPageJob(arg, debug);
+    }
+
+    /**
+     * Job for inform a node about awaiting of query result from Web console.
+     */
+    private static class VisorQueryFetchFirstPageJob extends VisorJob<VisorQueryNextPageTaskArg, VisorEither<VisorQueryPingTaskResult>> {
+        /** */
+        private static final long serialVersionUID = 0L;
+
+        /**
+         * Create job with specified argument.
+         *
+         * @param arg Job argument.
+         * @param debug Debug flag.
+         */
+        private VisorQueryFetchFirstPageJob(VisorQueryNextPageTaskArg arg, boolean debug) {
+            super(arg, debug);
+        }
+
+        /** {@inheritDoc} */
+        @Override protected VisorEither<VisorQueryPingTaskResult> run(VisorQueryNextPageTaskArg arg) {
+            String qryId = arg.getQueryId();
+
+            long start = U.currentTimeMillis();
+
+            if (debug)
+                start = log(ignite.log(), "Ping of query started: " + qryId, getClass(), start);
+
+            VisorQueryHolder holder = getQueryHolder(ignite, qryId);
+
+            if (holder.getErr() != null)
+                return new VisorEither<>(new VisorExceptionWrapper(holder.getErr()));
+
+            holder.setAccessed(true);
+
+            if (debug)
+                log(ignite.log(), "Ping of query finished: " + qryId, getClass(), start);
+
+            return new VisorEither<>(new VisorQueryPingTaskResult());
+        }
+
+        /** {@inheritDoc} */
+        @Override public String toString() {
+            return S.toString(VisorQueryFetchFirstPageJob.class, this);
+        }
+    }
+}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/visor/query/VisorQueryPingTaskResult.java b/modules/core/src/main/java/org/apache/ignite/internal/visor/query/VisorQueryPingTaskResult.java
new file mode 100644
index 0000000..540dd14
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/visor/query/VisorQueryPingTaskResult.java
@@ -0,0 +1,50 @@
+/*
+ * 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.visor.query;
+
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import org.apache.ignite.internal.util.typedef.internal.S;
+import org.apache.ignite.internal.visor.VisorDataTransferObject;
+
+/**
+ * Result for cache query ping tasks.
+ */
+public class VisorQueryPingTaskResult extends VisorDataTransferObject {
+    /** */
+    private static final long serialVersionUID = 0L;
+
+    /**
+     * Default constructor.
+     */
+    public VisorQueryPingTaskResult() {
+        // No-op.
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void writeExternalData(ObjectOutput out) throws IOException {}
+
+    /** {@inheritDoc} */
+    @Override protected void readExternalData(byte protoVer, ObjectInput in) throws IOException, ClassNotFoundException {}
+
+    /** {@inheritDoc} */
+    @Override public String toString() {
+        return S.toString(VisorQueryPingTaskResult.class, this);
+    }
+}
diff --git a/modules/core/src/main/java/org/apache/ignite/mxbean/BaselineConfigurationMXBean.java b/modules/core/src/main/java/org/apache/ignite/mxbean/BaselineConfigurationMXBean.java
new file mode 100644
index 0000000..172980b
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/mxbean/BaselineConfigurationMXBean.java
@@ -0,0 +1,45 @@
+/*
+ * 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.mxbean;
+
+import org.apache.ignite.internal.cluster.DistributedBaselineConfiguration;
+
+/**
+ * This interface defines JMX view on {@link DistributedBaselineConfiguration}.
+ */
+public interface BaselineConfigurationMXBean {
+    /** */
+    @MXBeanDescription("Whether baseline autoadjustment is enabled ot not.")
+    boolean isAutoAdjustmentEnabled();
+
+    /** */
+    @MXBeanDescription("Baseline autoadjustment timeout value.")
+    long getAutoAdjustmentTimeout();
+
+    /** */
+    @MXBeanDescription("Enable/disable baseline autoadjustment feature.")
+    @MXBeanParametersNames("enabled")
+    @MXBeanParametersDescriptions("Enable/disable flag.")
+    public void setAutoAdjustmentEnabled(boolean enabled);
+
+    /** */
+    @MXBeanDescription("Set baseline autoadjustment timeout value.")
+    @MXBeanParametersNames("timeout")
+    @MXBeanParametersDescriptions("Timeout value.")
+    public void setAutoAdjustmentTimeout(long timeout);
+}
diff --git a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ServerImpl.java b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ServerImpl.java
index 5c777ab..6016e42 100644
--- a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ServerImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ServerImpl.java
@@ -2132,6 +2132,23 @@
     }
 
     /**
+     * Sweeps failedNodes collection in msg and fills it with failed nodes observed by local node.
+     *
+     * @param msg {@link TcpDiscoveryAbstractMessage} to sweep failed nodes from.
+     */
+    private void sweepMessageFailedNodes(TcpDiscoveryAbstractMessage msg) {
+        msg.failedNodes(null);
+
+        synchronized (mux) {
+            for (TcpDiscoveryNode n : failedNodes.keySet())
+                msg.addFailedNode(n.id());
+        }
+
+        if (log.isDebugEnabled())
+            log.debug("Message failed nodes were replaced with failed nodes observed by local node: " + msg.failedNodes());
+    }
+
+    /**
      * Adds failed nodes specified in the received message to the local failed nodes list.
      *
      * @param msg Message.
@@ -2149,6 +2166,8 @@
                             ", failedNodes=" + msgFailedNodes + ']');
                     }
 
+                    sweepMessageFailedNodes(msg);
+
                     return;
                 }
 
@@ -2160,6 +2179,8 @@
                                     ", failedNodes=" + msgFailedNodes + ']');
                             }
 
+                            sweepMessageFailedNodes(msg);
+
                             return;
                         }
                     }
@@ -5803,8 +5824,8 @@
                     notifyDiscoveryListener(msg, waitForNotification);
                 }
 
-                if (msg.verified())
-                    msg.message(null, msg.messageBytes());
+                // Clear msg field to prevent possible memory leak.
+                msg.message(null, msg.messageBytes());
 
                 if (sendMessageToRemotes(msg))
                     sendMessageAcrossRing(msg);
diff --git a/modules/core/src/main/java/org/apache/ignite/spi/encryption/keystore/KeystoreEncryptionSpi.java b/modules/core/src/main/java/org/apache/ignite/spi/encryption/keystore/KeystoreEncryptionSpi.java
index beba015..f6b8e17 100644
--- a/modules/core/src/main/java/org/apache/ignite/spi/encryption/keystore/KeystoreEncryptionSpi.java
+++ b/modules/core/src/main/java/org/apache/ignite/spi/encryption/keystore/KeystoreEncryptionSpi.java
@@ -132,7 +132,7 @@
     protected Ignite ignite;
 
     /** */
-    private ThreadLocal<Cipher> aesWithPadding = ThreadLocal.withInitial(() -> {
+    private static final ThreadLocal<Cipher> aesWithPadding = ThreadLocal.withInitial(() -> {
         try {
             return Cipher.getInstance(AES_WITH_PADDING);
         }
@@ -142,7 +142,7 @@
     });
 
     /** */
-    private ThreadLocal<Cipher> aesWithoutPadding = ThreadLocal.withInitial(() -> {
+    private static final ThreadLocal<Cipher> aesWithoutPadding = ThreadLocal.withInitial(() -> {
         try {
             return Cipher.getInstance(AES_WITHOUT_PADDING);
         }
diff --git a/modules/core/src/test/java/org/apache/ignite/cache/ResetLostPartitionTest.java b/modules/core/src/test/java/org/apache/ignite/cache/ResetLostPartitionTest.java
index a32eb67..bef69a2 100644
--- a/modules/core/src/test/java/org/apache/ignite/cache/ResetLostPartitionTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/cache/ResetLostPartitionTest.java
@@ -53,8 +53,6 @@
 
     /** {@inheritDoc} */
     @Override protected void beforeTest() throws Exception {
-        Assume.assumeFalse("https://issues.apache.org/jira/browse/IGNITE-10560", MvccFeatureChecker.forcedMvcc());
-
         super.beforeTest();
 
         stopAllGrids();
diff --git a/modules/core/src/test/java/org/apache/ignite/cache/affinity/AffinityDistributionLoggingTest.java b/modules/core/src/test/java/org/apache/ignite/cache/affinity/AffinityDistributionLoggingTest.java
index 0a8e7c2..7706d94e 100644
--- a/modules/core/src/test/java/org/apache/ignite/cache/affinity/AffinityDistributionLoggingTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/cache/affinity/AffinityDistributionLoggingTest.java
@@ -34,6 +34,7 @@
 import org.apache.ignite.internal.util.typedef.internal.CU;
 import org.apache.ignite.testframework.GridStringLogger;
 import org.apache.ignite.testframework.GridTestUtils;
+import org.apache.ignite.testframework.junits.WithSystemProperty;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
 import org.junit.Test;
 
@@ -60,28 +61,10 @@
     /** Backups number. */
     private int backups = 0;
 
-    /** For storing original value of system property. */
-    private String tempProp;
-
-    /** {@inheritDoc} */
-    @Override protected void beforeTestsStarted() throws Exception {
-        super.beforeTestsStarted();
-
-        tempProp = System.getProperty(IGNITE_PART_DISTRIBUTION_WARN_THRESHOLD);
-    }
-
-    /** {@inheritDoc} */
-    @Override protected void afterTestsStopped() throws Exception {
-        if (tempProp != null)
-            System.setProperty(IGNITE_PART_DISTRIBUTION_WARN_THRESHOLD, tempProp);
-    }
-
     /** {@inheritDoc} */
     @Override protected void afterTest() throws Exception {
         super.afterTest();
 
-        System.clearProperty(IGNITE_PART_DISTRIBUTION_WARN_THRESHOLD);
-
         stopAllGrids();
     }
 
@@ -104,9 +87,8 @@
      * @throws Exception In case of an error.
      */
     @Test
+    @WithSystemProperty(key = IGNITE_PART_DISTRIBUTION_WARN_THRESHOLD, value = "0")
     public void test2PartitionsIdealDistributionIsNotLogged() throws Exception {
-        System.setProperty(IGNITE_PART_DISTRIBUTION_WARN_THRESHOLD, "0");
-
         nodes = 2;
         parts = 2;
         backups = 1;
@@ -120,9 +102,8 @@
      * @throws Exception In case of an error.
      */
     @Test
+    @WithSystemProperty(key = IGNITE_PART_DISTRIBUTION_WARN_THRESHOLD, value = "0.0")
     public void test120PartitionsIdeadDistributionIsNotLogged() throws Exception {
-        System.setProperty(IGNITE_PART_DISTRIBUTION_WARN_THRESHOLD, "0.0");
-
         nodes = 3;
         parts = 120;
         backups = 2;
@@ -136,9 +117,8 @@
      * @throws Exception In case of an error.
      */
     @Test
+    @WithSystemProperty(key = IGNITE_PART_DISTRIBUTION_WARN_THRESHOLD, value = "50.0")
     public void test5PartitionsNotIdealDistributionIsLogged() throws Exception {
-        System.setProperty(IGNITE_PART_DISTRIBUTION_WARN_THRESHOLD, "50.0");
-
         nodes = 4;
         parts = 5;
         backups = 3;
@@ -152,9 +132,8 @@
      * @throws Exception In case of an error.
      */
     @Test
+    @WithSystemProperty(key = IGNITE_PART_DISTRIBUTION_WARN_THRESHOLD, value = "0.0")
     public void test5PartitionsNotIdealDistributionSuppressedLoggingOnClientNode() throws Exception {
-        System.setProperty(IGNITE_PART_DISTRIBUTION_WARN_THRESHOLD, "0.0");
-
         nodes = 4;
         parts = 5;
         backups = 3;
@@ -168,9 +147,8 @@
      * @throws Exception In case of an error.
      */
     @Test
+    @WithSystemProperty(key = IGNITE_PART_DISTRIBUTION_WARN_THRESHOLD, value = "50.0")
     public void test7PartitionsNotIdealDistributionSuppressedLogging() throws Exception {
-        System.setProperty(IGNITE_PART_DISTRIBUTION_WARN_THRESHOLD, "50.0");
-
         nodes = 3;
         parts = 7;
         backups = 0;
@@ -184,9 +162,8 @@
      * @throws Exception In case of an error.
      */
     @Test
+    @WithSystemProperty(key = IGNITE_PART_DISTRIBUTION_WARN_THRESHOLD, value = "65")
     public void test5PartitionsNotIdealDistributionSuppressedLogging() throws Exception {
-        System.setProperty(IGNITE_PART_DISTRIBUTION_WARN_THRESHOLD, "65");
-
         nodes = 4;
         parts = 5;
         backups = 3;
diff --git a/modules/core/src/test/java/org/apache/ignite/cache/affinity/AffinityHistoryCleanupTest.java b/modules/core/src/test/java/org/apache/ignite/cache/affinity/AffinityHistoryCleanupTest.java
index 697caa9..6de9228 100644
--- a/modules/core/src/test/java/org/apache/ignite/cache/affinity/AffinityHistoryCleanupTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/cache/affinity/AffinityHistoryCleanupTest.java
@@ -32,9 +32,12 @@
 import org.apache.ignite.internal.processors.cache.GridCacheProcessor;
 import org.apache.ignite.internal.util.typedef.F;
 import org.apache.ignite.testframework.GridTestUtils;
+import org.apache.ignite.testframework.junits.WithSystemProperty;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
 import org.junit.Test;
 
+import static org.apache.ignite.IgniteSystemProperties.IGNITE_AFFINITY_HISTORY_SIZE;
+
 /**
  *
  */
@@ -75,100 +78,89 @@
      * @throws Exception If failed.
      */
     @Test
+    @WithSystemProperty(key = IGNITE_AFFINITY_HISTORY_SIZE, value = "5")
     public void testAffinityHistoryCleanup() throws Exception {
-        String histProp = System.getProperty(IgniteSystemProperties.IGNITE_AFFINITY_HISTORY_SIZE);
+        Ignite ignite = startGrid(0);
 
-        try {
-            System.setProperty(IgniteSystemProperties.IGNITE_AFFINITY_HISTORY_SIZE, "5");
+        checkHistory(ignite, F.asList(topVer(1, 0)), 1); //fullHistSize = 1
 
-            Ignite ignite = startGrid(0);
+        startGrid(1);
 
-            checkHistory(ignite, F.asList(topVer(1, 0)), 1); //fullHistSize = 1
+        checkHistory(ignite, F.asList(
+            topVer(1, 0), // FullHistSize = 1.
+            topVer(2, 0), // FullHistSize = 2.
+            topVer(2, 1)), // FullHistSize = 3.
+            3);
 
-            startGrid(1);
+        startGrid(2);
 
-            checkHistory(ignite, F.asList(
-                topVer(1, 0), // FullHistSize = 1.
-                topVer(2, 0), // FullHistSize = 2.
-                topVer(2, 1)), // FullHistSize = 3.
-                3);
+        checkHistory(ignite, F.asList(
+            topVer(1, 0), // FullHistSize = 1.
+            topVer(2, 0), // FullHistSize = 2.
+            topVer(2, 1), // FullHistSize = 3.
+            topVer(3, 0), // FullHistSize = 4.
+            topVer(3, 1)), // FullHistSize = 5.
+            5);
 
-            startGrid(2);
+        startGrid(3);
 
-            checkHistory(ignite, F.asList(
-                topVer(1, 0), // FullHistSize = 1.
-                topVer(2, 0), // FullHistSize = 2.
-                topVer(2, 1), // FullHistSize = 3.
-                topVer(3, 0), // FullHistSize = 4.
-                topVer(3, 1)), // FullHistSize = 5.
-                5);
+        checkHistory(ignite, F.asList(
+            topVer(2, 1), // FullHistSize = 3.
+            topVer(3, 0), // FullHistSize = 4.
+            topVer(3, 1), // FullHistSize = 5.
+            topVer(4, 0), // FullHistSize = (6 - IGNITE_AFFINITY_HISTORY_SIZE(5)/2) = 4.
+            topVer(4, 1)), // FullHistSize = 5.
+            5);
 
-            startGrid(3);
+        client = true;
 
-            checkHistory(ignite, F.asList(
-                topVer(2, 1), // FullHistSize = 3.
-                topVer(3, 0), // FullHistSize = 4.
-                topVer(3, 1), // FullHistSize = 5.
-                topVer(4, 0), // FullHistSize = (6 - IGNITE_AFFINITY_HISTORY_SIZE(5)/2) = 4.
-                topVer(4, 1)), // FullHistSize = 5.
-                5);
+        startGrid(4);
 
-            client = true;
+        stopGrid(4);
 
-            startGrid(4);
+        checkHistory(ignite, F.asList(
+            topVer(3, 1), // FullHistSize = 5.
+            topVer(4, 0), // FullHistSize = (6 - IGNITE_AFFINITY_HISTORY_SIZE(5)/2) = 4.
+            topVer(4, 1), // FullHistSize = 5.
+            topVer(5, 0), // FullHistSize = (6 - IGNITE_AFFINITY_HISTORY_SIZE(5)/2) = 4.
+            topVer(6, 0)), // FullHistSize = 5.
+            5);
 
-            stopGrid(4);
+        startGrid(4);
 
-            checkHistory(ignite, F.asList(
-                topVer(3, 1), // FullHistSize = 5.
-                topVer(4, 0), // FullHistSize = (6 - IGNITE_AFFINITY_HISTORY_SIZE(5)/2) = 4.
-                topVer(4, 1), // FullHistSize = 5.
-                topVer(5, 0), // FullHistSize = (6 - IGNITE_AFFINITY_HISTORY_SIZE(5)/2) = 4.
-                topVer(6, 0)), // FullHistSize = 5.
-                5);
+        stopGrid(4);
 
-            startGrid(4);
+        checkHistory(ignite, F.asList(
+            topVer(4, 1), // FullHistSize = 5.
+            topVer(5, 0), // FullHistSize = (6 - IGNITE_AFFINITY_HISTORY_SIZE(5)/2) = 4.
+            topVer(6, 0), // FullHistSize = 5.
+            topVer(7, 0), // FullHistSize = (6 - IGNITE_AFFINITY_HISTORY_SIZE(5)/2) = 4.
+            topVer(8, 0)), // FullHistSize = 5.
+            5);
 
-            stopGrid(4);
+        startGrid(4);
 
-            checkHistory(ignite, F.asList(
-                topVer(4, 1), // FullHistSize = 5.
-                topVer(5, 0), // FullHistSize = (6 - IGNITE_AFFINITY_HISTORY_SIZE(5)/2) = 4.
-                topVer(6, 0), // FullHistSize = 5.
-                topVer(7, 0), // FullHistSize = (6 - IGNITE_AFFINITY_HISTORY_SIZE(5)/2) = 4.
-                topVer(8, 0)), // FullHistSize = 5.
-                5);
+        stopGrid(4);
 
-            startGrid(4);
+        checkHistory(ignite, F.asList(
+            topVer(6, 0), // FullHistSize = 5.
+            topVer(7, 0), // FullHistSize = (6 - IGNITE_AFFINITY_HISTORY_SIZE(5)/2) = 4.
+            topVer(8, 0), // FullHistSize = 5.
+            topVer(9, 0), // FullHistSize = (6 - IGNITE_AFFINITY_HISTORY_SIZE(5)/2) = 4.
+            topVer(10, 0)), // FullHistSize = 5.
+            5);
 
-            stopGrid(4);
+        client = false;
 
-            checkHistory(ignite, F.asList(
-                topVer(6, 0), // FullHistSize = 5.
-                topVer(7, 0), // FullHistSize = (6 - IGNITE_AFFINITY_HISTORY_SIZE(5)/2) = 4.
-                topVer(8, 0), // FullHistSize = 5.
-                topVer(9, 0), // FullHistSize = (6 - IGNITE_AFFINITY_HISTORY_SIZE(5)/2) = 4.
-                topVer(10, 0)), // FullHistSize = 5.
-                5);
+        startGrid(4);
 
-            client = false;
-
-            startGrid(4);
-
-            checkHistory(ignite, F.asList(
-                topVer(8, 0), // FullHistSize = 5.
-                topVer(9, 0), // FullHistSize = (6 - IGNITE_AFFINITY_HISTORY_SIZE(5)/2) = 4.
-                topVer(10, 0), // FullHistSize = 5.
-                topVer(11, 0), // FullHistSize = (6 - IGNITE_AFFINITY_HISTORY_SIZE(5)/2) = 4.
-                topVer(11, 1)), // FullHistSize = 5.
-                5);
-        }
-        finally {
-            if (histProp != null)
-                System.setProperty(IgniteSystemProperties.IGNITE_AFFINITY_HISTORY_SIZE, histProp);
-            else
-                System.clearProperty(IgniteSystemProperties.IGNITE_AFFINITY_HISTORY_SIZE);
-        }
+        checkHistory(ignite, F.asList(
+            topVer(8, 0), // FullHistSize = 5.
+            topVer(9, 0), // FullHistSize = (6 - IGNITE_AFFINITY_HISTORY_SIZE(5)/2) = 4.
+            topVer(10, 0), // FullHistSize = 5.
+            topVer(11, 0), // FullHistSize = (6 - IGNITE_AFFINITY_HISTORY_SIZE(5)/2) = 4.
+            topVer(11, 1)), // FullHistSize = 5.
+            5);
     }
 
     /**
diff --git a/modules/core/src/test/java/org/apache/ignite/failure/FailureHandlingConfigurationTest.java b/modules/core/src/test/java/org/apache/ignite/failure/FailureHandlingConfigurationTest.java
index 324854f..ca4391d 100644
--- a/modules/core/src/test/java/org/apache/ignite/failure/FailureHandlingConfigurationTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/failure/FailureHandlingConfigurationTest.java
@@ -32,6 +32,7 @@
 import org.apache.ignite.internal.worker.FailureHandlingMxBeanImpl;
 import org.apache.ignite.internal.worker.WorkersRegistry;
 import org.apache.ignite.mxbean.FailureHandlingMxBean;
+import org.apache.ignite.testframework.junits.WithSystemProperty;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
 import org.junit.Test;
 
@@ -183,51 +184,34 @@
      * @throws Exception If failed.
      */
     @Test
+    @WithSystemProperty(key = IGNITE_SYSTEM_WORKER_BLOCKED_TIMEOUT, value = "80000")
+    @WithSystemProperty(key = IGNITE_CHECKPOINT_READ_LOCK_TIMEOUT, value = "90000")
     public void testOverridingBySysProps() throws Exception {
-        String prevWorkerProp = System.getProperty(IGNITE_SYSTEM_WORKER_BLOCKED_TIMEOUT);
-        String prevCheckpointProp = System.getProperty(IGNITE_CHECKPOINT_READ_LOCK_TIMEOUT);
+        sysWorkerBlockedTimeout = 1L;
+        checkpointReadLockTimeout = 2L;
 
-        long workerPropVal = 80_000;
-        long checkpointPropVal = 90_000;
+        IgniteEx ignite = startGrid(0);
 
-        System.setProperty(IGNITE_SYSTEM_WORKER_BLOCKED_TIMEOUT, String.valueOf(workerPropVal));
-        System.setProperty(IGNITE_CHECKPOINT_READ_LOCK_TIMEOUT, String.valueOf(checkpointPropVal));
+        ignite.cluster().active(true);
 
-        try {
-            sysWorkerBlockedTimeout = 1L;
-            checkpointReadLockTimeout = 2L;
+        WorkersRegistry reg = ignite.context().workersRegistry();
 
-            IgniteEx ignite = startGrid(0);
+        IgniteCacheDatabaseSharedManager dbMgr = ignite.context().cache().context().database();
 
-            ignite.cluster().active(true);
+        FailureHandlingMxBean mBean = getMBean();
 
-            WorkersRegistry reg = ignite.context().workersRegistry();
+        assertEquals(sysWorkerBlockedTimeout, ignite.configuration().getSystemWorkerBlockedTimeout());
+        assertEquals(checkpointReadLockTimeout,
+            ignite.configuration().getDataStorageConfiguration().getCheckpointReadLockTimeout());
 
-            IgniteCacheDatabaseSharedManager dbMgr = ignite.context().cache().context().database();
+        long workerPropVal = Long.getLong(IGNITE_SYSTEM_WORKER_BLOCKED_TIMEOUT);
+        long checkpointPropVal = Long.getLong(IGNITE_CHECKPOINT_READ_LOCK_TIMEOUT);
 
-            FailureHandlingMxBean mBean = getMBean();
+        assertEquals(workerPropVal, reg.getSystemWorkerBlockedTimeout());
+        assertEquals(checkpointPropVal, dbMgr.checkpointReadLockTimeout());
 
-            assertEquals(sysWorkerBlockedTimeout, ignite.configuration().getSystemWorkerBlockedTimeout());
-            assertEquals(checkpointReadLockTimeout,
-                ignite.configuration().getDataStorageConfiguration().getCheckpointReadLockTimeout());
-
-            assertEquals(workerPropVal, reg.getSystemWorkerBlockedTimeout());
-            assertEquals(checkpointPropVal, dbMgr.checkpointReadLockTimeout());
-
-            assertEquals(workerPropVal, mBean.getSystemWorkerBlockedTimeout());
-            assertEquals(checkpointPropVal, mBean.getCheckpointReadLockTimeout());
-        }
-        finally {
-            if (prevWorkerProp != null)
-                System.setProperty(IGNITE_SYSTEM_WORKER_BLOCKED_TIMEOUT, prevWorkerProp);
-            else
-                System.clearProperty(IGNITE_SYSTEM_WORKER_BLOCKED_TIMEOUT);
-
-            if (prevCheckpointProp != null)
-                System.setProperty(IGNITE_CHECKPOINT_READ_LOCK_TIMEOUT, prevCheckpointProp);
-            else
-                System.clearProperty(IGNITE_CHECKPOINT_READ_LOCK_TIMEOUT);
-        }
+        assertEquals(workerPropVal, mBean.getSystemWorkerBlockedTimeout());
+        assertEquals(checkpointPropVal, mBean.getCheckpointReadLockTimeout());
     }
 
     /**
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/ConsistentIdImplicitlyExplicitlyTest.java b/modules/core/src/test/java/org/apache/ignite/internal/ConsistentIdImplicitlyExplicitlyTest.java
index c88888f..60c8f4e 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/ConsistentIdImplicitlyExplicitlyTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/ConsistentIdImplicitlyExplicitlyTest.java
@@ -20,13 +20,15 @@
 import java.io.Serializable;
 import java.util.regex.Pattern;
 import org.apache.ignite.Ignite;
-import org.apache.ignite.IgniteSystemProperties;
 import org.apache.ignite.configuration.DataRegionConfiguration;
 import org.apache.ignite.configuration.DataStorageConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.testframework.junits.WithSystemProperty;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
 import org.junit.Test;
 
+import static org.apache.ignite.IgniteSystemProperties.IGNITE_OVERRIDE_CONSISTENT_ID;
+
 /**
  * Checks consistent id in various cases.
  */
@@ -70,8 +72,6 @@
 
         defConsistentId = null;
         persistenceEnabled = false;
-
-        System.clearProperty(IgniteSystemProperties.IGNITE_OVERRIDE_CONSISTENT_ID);
     }
 
     /** {@inheritDoc} */
@@ -85,8 +85,6 @@
 
             persistenceEnabled = false;
         }
-
-        System.clearProperty(IgniteSystemProperties.IGNITE_OVERRIDE_CONSISTENT_ID);
     }
 
     /**
@@ -130,10 +128,9 @@
      * @throws Exception if failed.
      */
     @Test
+    @WithSystemProperty(key = IGNITE_OVERRIDE_CONSISTENT_ID, value = "JvmProp consistent id")
     public void testConsistentIdConfiguredInJvmProp() throws Exception {
-        String specificConsistentId = "JvmProp consistent id";
-
-        System.setProperty(IgniteSystemProperties.IGNITE_OVERRIDE_CONSISTENT_ID, specificConsistentId);
+        String specificConsistentId = System.getProperty(IGNITE_OVERRIDE_CONSISTENT_ID);
 
         Ignite ignite = startGrid(0);
 
@@ -168,12 +165,11 @@
      * @throws Exception if failed.
      */
     @Test
+    @WithSystemProperty(key = IGNITE_OVERRIDE_CONSISTENT_ID, value = "JvmProp consistent id")
     public void testConsistentIdConfiguredInIgniteCfgAndJvmProp() throws Exception {
         defConsistentId = "IgniteCfg consistent id";
 
-        String specificConsistentId = "JvmProp consistent id";
-
-        System.setProperty(IgniteSystemProperties.IGNITE_OVERRIDE_CONSISTENT_ID, specificConsistentId);
+        String specificConsistentId = System.getProperty(IGNITE_OVERRIDE_CONSISTENT_ID);;
 
         Ignite ignite = startGrid(0);
 
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/GridCachePartitionExchangeManagerHistSizeTest.java b/modules/core/src/test/java/org/apache/ignite/internal/GridCachePartitionExchangeManagerHistSizeTest.java
index 842eb8e..70e3a77 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/GridCachePartitionExchangeManagerHistSizeTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/GridCachePartitionExchangeManagerHistSizeTest.java
@@ -19,6 +19,7 @@
 
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.testframework.junits.WithSystemProperty;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
 import org.junit.Test;
 
@@ -28,9 +29,6 @@
  * Test exchange history size parameter effect.
  */
 public class GridCachePartitionExchangeManagerHistSizeTest extends GridCommonAbstractTest {
-    /** */
-    private String oldHistVal;
-
     /** {@inheritDoc} */
     @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception {
         IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName);
@@ -40,29 +38,12 @@
         return cfg;
     }
 
-    /** {@inheritDoc} */
-    @Override protected void beforeTestsStarted() throws Exception {
-        super.beforeTestsStarted();
-
-        oldHistVal = System.getProperty(IGNITE_EXCHANGE_HISTORY_SIZE);
-    }
-
-    /** {@inheritDoc} */
-    @Override protected void afterTestsStopped() throws Exception {
-        if (oldHistVal != null)
-            System.setProperty(IGNITE_EXCHANGE_HISTORY_SIZE, oldHistVal);
-        else
-            System.clearProperty(IGNITE_EXCHANGE_HISTORY_SIZE);
-    }
-
-
     /**
      * @throws Exception If failed.
      */
     @Test
+    @WithSystemProperty(key = IGNITE_EXCHANGE_HISTORY_SIZE, value = "1")
     public void testSingleExchangeHistSize() throws Exception {
-        System.setProperty(IGNITE_EXCHANGE_HISTORY_SIZE, "1");
-
         startGridsMultiThreaded(10);
     }
 }
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/GridVersionSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/GridVersionSelfTest.java
index 5314d87..02b3258 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/GridVersionSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/GridVersionSelfTest.java
@@ -20,6 +20,7 @@
 import org.apache.ignite.internal.util.lang.GridAbsPredicate;
 import org.apache.ignite.lang.IgniteProductVersion;
 import org.apache.ignite.testframework.GridTestUtils;
+import org.apache.ignite.testframework.junits.WithSystemProperty;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
 import org.junit.Test;
 
@@ -33,11 +34,8 @@
      * @throws Exception If failed.
      */
     @Test
+    @WithSystemProperty(key = IGNITE_UPDATE_NOTIFIER, value = "true")
     public void testVersions() throws Exception {
-        String propVal = System.getProperty(IGNITE_UPDATE_NOTIFIER);
-
-        System.setProperty(IGNITE_UPDATE_NOTIFIER, "true");
-
         try {
             final IgniteEx ignite = (IgniteEx)startGrid();
 
@@ -58,11 +56,6 @@
         }
         finally {
             stopGrid();
-
-            if (propVal != null)
-                System.setProperty(IGNITE_UPDATE_NOTIFIER, propVal);
-            else
-                System.clearProperty(IGNITE_UPDATE_NOTIFIER);
         }
     }
 }
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/IgniteClientRejoinTest.java b/modules/core/src/test/java/org/apache/ignite/internal/IgniteClientRejoinTest.java
index 8fe6dd2..e3b0dd2 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/IgniteClientRejoinTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/IgniteClientRejoinTest.java
@@ -48,12 +48,16 @@
 import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
 import org.apache.ignite.spi.discovery.tcp.messages.TcpDiscoveryAbstractMessage;
 import org.apache.ignite.testframework.GridTestUtils;
+import org.apache.ignite.testframework.junits.WithSystemProperty;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
 import org.junit.Test;
 
+import static org.apache.ignite.IgniteSystemProperties.IGNITE_SKIP_CONFIGURATION_CONSISTENCY_CHECK;
+
 /**
  * Tests client to be able restore connection to cluster if coordination is not available.
  */
+@WithSystemProperty(key = IGNITE_SKIP_CONFIGURATION_CONSISTENCY_CHECK, value = "true")
 public class IgniteClientRejoinTest extends GridCommonAbstractTest {
     /** Block. */
     private volatile boolean block;
@@ -68,16 +72,6 @@
     private boolean clientReconnectDisabled;
 
     /** {@inheritDoc} */
-    @Override protected void beforeTestsStarted() throws Exception {
-        System.setProperty("IGNITE_SKIP_CONFIGURATION_CONSISTENCY_CHECK", "true");
-    }
-
-    /** {@inheritDoc} */
-    @Override protected void afterTestsStopped() throws Exception {
-        System.clearProperty("IGNITE_SKIP_CONFIGURATION_CONSISTENCY_CHECK");
-    }
-
-    /** {@inheritDoc} */
     @Override protected void afterTest() throws Exception {
         stopAllGrids();
     }
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/IgniteDiscoveryMassiveNodeFailTest.java b/modules/core/src/test/java/org/apache/ignite/internal/IgniteDiscoveryMassiveNodeFailTest.java
index 3413f73..cbd060d 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/IgniteDiscoveryMassiveNodeFailTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/IgniteDiscoveryMassiveNodeFailTest.java
@@ -28,7 +28,6 @@
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 import org.apache.ignite.IgniteCheckedException;
-import org.apache.ignite.IgniteSystemProperties;
 import org.apache.ignite.cluster.ClusterNode;
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.events.DiscoveryEvent;
@@ -37,14 +36,18 @@
 import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
 import org.apache.ignite.spi.discovery.tcp.internal.TcpDiscoveryNode;
 import org.apache.ignite.spi.discovery.tcp.messages.TcpDiscoveryAbstractMessage;
+import org.apache.ignite.testframework.junits.WithSystemProperty;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
 import org.junit.Test;
 
+import static org.apache.ignite.IgniteSystemProperties.IGNITE_DUMP_THREADS_ON_FAILURE;
+
 /**
  * Tests checks case when one node is unable to connect to next in a ring,
  * but those nodes are not experiencing any connectivity troubles between
  * each other.
  */
+@WithSystemProperty(key = IGNITE_DUMP_THREADS_ON_FAILURE, value = "false")
 public class IgniteDiscoveryMassiveNodeFailTest extends GridCommonAbstractTest {
     /** */
     private static final int FAILURE_DETECTION_TIMEOUT = 5_000;
@@ -85,20 +88,6 @@
     }
 
     /** {@inheritDoc} */
-    @Override protected void beforeTestsStarted() throws Exception {
-        super.beforeTestsStarted();
-
-        System.setProperty(IgniteSystemProperties.IGNITE_DUMP_THREADS_ON_FAILURE, "false");
-    }
-
-    /** {@inheritDoc} */
-    @Override protected void afterTestsStopped() throws Exception {
-        super.afterTestsStopped();
-
-        System.setProperty(IgniteSystemProperties.IGNITE_DUMP_THREADS_ON_FAILURE, "true");
-    }
-
-    /** {@inheritDoc} */
     @Override protected void afterTest() throws Exception {
         super.afterTest();
 
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/IgniteUpdateNotifierPerClusterSettingSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/IgniteUpdateNotifierPerClusterSettingSelfTest.java
index 1127a9e..aa933f9 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/IgniteUpdateNotifierPerClusterSettingSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/IgniteUpdateNotifierPerClusterSettingSelfTest.java
@@ -18,31 +18,23 @@
 package org.apache.ignite.internal;
 
 import org.apache.ignite.Ignite;
-import org.apache.ignite.IgniteSystemProperties;
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.internal.processors.cluster.ClusterProcessor;
 import org.apache.ignite.testframework.GridTestUtils;
+import org.apache.ignite.testframework.junits.WithSystemProperty;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
 import org.junit.Test;
 
+import static org.apache.ignite.IgniteSystemProperties.IGNITE_UPDATE_NOTIFIER;
+
 /**
  */
 public class IgniteUpdateNotifierPerClusterSettingSelfTest extends GridCommonAbstractTest {
     /** */
-    private String backup;
-
-    /** */
     private boolean client;
 
     /** {@inheritDoc} */
-    @Override protected void beforeTest() throws Exception {
-        backup = System.getProperty(IgniteSystemProperties.IGNITE_UPDATE_NOTIFIER);
-    }
-
-    /** {@inheritDoc} */
     @Override protected void afterTest() throws Exception {
-        System.setProperty(IgniteSystemProperties.IGNITE_UPDATE_NOTIFIER, backup);
-
         stopAllGrids();
     }
 
@@ -59,6 +51,7 @@
      * @throws Exception If failed.
      */
     @Test
+    @WithSystemProperty(key = IGNITE_UPDATE_NOTIFIER, value = "true")
     public void testNotifierEnabledForCluster() throws Exception {
         checkNotifierStatusForCluster(true);
     }
@@ -67,6 +60,7 @@
      * @throws Exception If failed.
      */
     @Test
+    @WithSystemProperty(key = IGNITE_UPDATE_NOTIFIER, value = "false")
     public void testNotifierDisabledForCluster() throws Exception {
         checkNotifierStatusForCluster(false);
     }
@@ -76,13 +70,11 @@
      * @throws Exception If failed.
      */
     private void checkNotifierStatusForCluster(boolean enabled) throws Exception {
-        System.setProperty(IgniteSystemProperties.IGNITE_UPDATE_NOTIFIER, String.valueOf(enabled));
-
         IgniteEx grid1 = startGrid(0);
 
         checkNotifier(grid1, enabled);
 
-        System.setProperty(IgniteSystemProperties.IGNITE_UPDATE_NOTIFIER, String.valueOf(!enabled));
+        System.setProperty(IGNITE_UPDATE_NOTIFIER, String.valueOf(!enabled));
 
         IgniteEx grid2 = startGrid(1);
 
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/binary/BinaryConfigurationConsistencySelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/binary/BinaryConfigurationConsistencySelfTest.java
index 2524e2e..9b47ffc 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/binary/BinaryConfigurationConsistencySelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/binary/BinaryConfigurationConsistencySelfTest.java
@@ -29,6 +29,7 @@
 import org.apache.ignite.configuration.BinaryConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.testframework.GridTestUtils;
+import org.apache.ignite.testframework.junits.WithSystemProperty;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
 import org.junit.Test;
 
@@ -68,30 +69,21 @@
      * @throws Exception If failed.
      */
     @Test
+    @WithSystemProperty(key = IGNITE_SKIP_CONFIGURATION_CONSISTENCY_CHECK, value = "true")
     public void testSkipCheckConsistencyFlagEnabled() throws Exception {
-        String backup = System.setProperty(IGNITE_SKIP_CONFIGURATION_CONSISTENCY_CHECK, "true");
+        // Wrong usage of Ignite (done only in test purposes).
+        binaryCfg = null;
 
-        try {
-            // Wrong usage of Ignite (done only in test purposes).
-            binaryCfg = null;
+        startGrid(0);
 
-            startGrid(0);
+        binaryCfg = new BinaryConfiguration();
 
-            binaryCfg = new BinaryConfiguration();
+        startGrid(1);
 
-            startGrid(1);
+        isClient = true;
+        binaryCfg = customConfig(true);
 
-            isClient = true;
-            binaryCfg = customConfig(true);
-
-            startGrid(2);
-        }
-        finally {
-            if (backup != null)
-                System.setProperty(IGNITE_SKIP_CONFIGURATION_CONSISTENCY_CHECK, backup);
-            else
-                System.clearProperty(IGNITE_SKIP_CONFIGURATION_CONSISTENCY_CHECK);
-        }
+        startGrid(2);
     }
 
     /**
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/binary/BinarySimpleNameTestPropertySelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/binary/BinarySimpleNameTestPropertySelfTest.java
index ce98e33..7e1709e 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/binary/BinarySimpleNameTestPropertySelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/binary/BinarySimpleNameTestPropertySelfTest.java
@@ -27,7 +27,6 @@
 import org.junit.Test;
 
 import static org.apache.ignite.testframework.config.GridTestProperties.BINARY_MARSHALLER_USE_SIMPLE_NAME_MAPPER;
-import static org.apache.ignite.testframework.config.GridTestProperties.MARSH_CLASS_NAME;
 
 /**
  * Tests testing framewrok, epecially BINARY_MARSHALLER_USE_SIMPLE_NAME_MAPPER test property.
@@ -94,22 +93,12 @@
      * @throws Exception If failed.
      */
     private void checkProperty(String expTypeName) throws Exception {
-        String marshBackup = GridTestProperties.getProperty(MARSH_CLASS_NAME);
+        IgniteBinary binary = startGrid().binary();
 
-        try {
-            GridTestProperties.setProperty(MARSH_CLASS_NAME, BinaryMarshaller.class.getName());
+        BinaryObjectBuilder builder = binary.builder("org.ignite.test.TestClass");
 
-            IgniteBinary binary = startGrid().binary();
+        BinaryObject bObj = builder.build();
 
-            BinaryObjectBuilder builder = binary.builder("org.ignite.test.TestClass");
-
-            BinaryObject bObj = builder.build();
-
-            assertEquals(expTypeName, bObj.type().typeName());
-        }
-        finally {
-            if (marshBackup != null)
-                GridTestProperties.setProperty(MARSH_CLASS_NAME, marshBackup);
-        }
+        assertEquals(expTypeName, bObj.type().typeName());
     }
 }
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/commandline/CommandHandlerParsingTest.java b/modules/core/src/test/java/org/apache/ignite/internal/commandline/CommandHandlerParsingTest.java
index f261292..3239171 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/commandline/CommandHandlerParsingTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/commandline/CommandHandlerParsingTest.java
@@ -327,8 +327,8 @@
                         assertEquals(cmd, args.command());
                         assertEquals(DFLT_HOST, args.host());
                         assertEquals(DFLT_PORT, args.port());
-                        assertEquals(baselineAct, args.baselineAction());
-                        assertEquals("c_id1,c_id2", args.baselineArguments());
+                        assertEquals(baselineAct, args.baselineArguments().getCmd().text());
+                        assertEquals(Arrays.asList("c_id1","c_id2"), args.baselineArguments().getConsistentIds());
                         assertEquals(true, args.autoConfirmation());
                     }
 
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheMixedPartitionExchangeSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheMixedPartitionExchangeSelfTest.java
index 7ee0ebe..4e3f988 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheMixedPartitionExchangeSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheMixedPartitionExchangeSelfTest.java
@@ -34,7 +34,6 @@
 import org.apache.ignite.testframework.MvccFeatureChecker;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
 import org.apache.ignite.transactions.Transaction;
-import org.junit.Assume;
 import org.junit.Test;
 
 import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL;
@@ -52,13 +51,6 @@
     private boolean cache;
 
     /** {@inheritDoc} */
-    @Override protected void beforeTestsStarted() throws Exception {
-        Assume.assumeFalse("https://issues.apache.org/jira/browse/IGNITE-9470", MvccFeatureChecker.forcedMvcc());
-
-        super.beforeTestsStarted();
-    }
-
-    /** {@inheritDoc} */
     @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception {
         IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName);
 
@@ -126,7 +118,7 @@
                         }
                         catch (Exception e) {
                             if (!X.hasCause(e, ClusterTopologyCheckedException.class))
-                                throw e;
+                                MvccFeatureChecker.assertMvccWriteConflict(e);
                         }
                     }
 
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheMvccMultiThreadedUpdateSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheMvccMultiThreadedUpdateSelfTest.java
index 4e8f3d5..f48300d 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheMvccMultiThreadedUpdateSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheMvccMultiThreadedUpdateSelfTest.java
@@ -18,13 +18,15 @@
 package org.apache.ignite.internal.processors.cache;
 
 import java.util.concurrent.Callable;
+import java.util.function.Supplier;
+import javax.cache.CacheException;
 import org.apache.ignite.IgniteCache;
 import org.apache.ignite.IgniteTransactions;
 import org.apache.ignite.cache.CacheAtomicityMode;
 import org.apache.ignite.testframework.GridTestUtils;
 import org.apache.ignite.testframework.MvccFeatureChecker;
 import org.apache.ignite.transactions.Transaction;
-import org.junit.Assume;
+import org.junit.Test;
 
 import static org.apache.ignite.transactions.TransactionConcurrency.PESSIMISTIC;
 import static org.apache.ignite.transactions.TransactionIsolation.REPEATABLE_READ;
@@ -46,16 +48,10 @@
         return CacheAtomicityMode.TRANSACTIONAL_SNAPSHOT;
     }
 
-    /** {@inheritDoc} */
-    @Override protected void beforeTestsStarted() throws Exception {
-        Assume.assumeFalse("https://issues.apache.org/jira/browse/IGNITE-9470", MvccFeatureChecker.forcedMvcc());
-
-        super.beforeTestsStarted();
-    }
-
     /**
      * @throws Exception If failed.
      */
+    @Test
     public void testTransformTx() throws Exception {
         testTransformTx(keyForNode(0));
 
@@ -82,11 +78,13 @@
                     if (i % 500 == 0)
                         log.info("Iteration " + i);
 
-                    try (Transaction tx = txs.txStart(PESSIMISTIC, REPEATABLE_READ)) {
-                        cache.invoke(key, new IncProcessor());
+                    doOperation(() -> {
+                        try (Transaction tx = txs.txStart(PESSIMISTIC, REPEATABLE_READ)) {
+                            cache.invoke(key, new IncProcessor());
 
-                        tx.commit();
-                    }
+                            tx.commit();
+                        }
+                    });
                 }
 
                 return null;
@@ -110,6 +108,7 @@
     /**
      * @throws Exception If failed.
      */
+    @Test
     public void testPutTxPessimistic() throws Exception {
         testPutTx(keyForNode(0));
 
@@ -134,13 +133,16 @@
                     if (i % 500 == 0)
                         log.info("Iteration " + i);
 
-                    try (Transaction tx = grid(0).transactions().txStart(PESSIMISTIC, REPEATABLE_READ)) {
-                        Integer val = cache.getAndPut(key, i);
+                    int val0 = i;
+                    doOperation(() -> {
+                        try (Transaction tx = grid(0).transactions().txStart(PESSIMISTIC, REPEATABLE_READ)) {
+                            Integer val = cache.getAndPut(key, val0);
 
-                        assertNotNull(val);
+                            assertNotNull(val);
 
-                        tx.commit();
-                    }
+                            tx.commit();
+                        }
+                    });
                 }
 
                 return null;
@@ -157,6 +159,7 @@
     /**
      * @throws Exception If failed.
      */
+    @Test
     public void testPutxIfAbsentTxPessimistic() throws Exception {
         testPutxIfAbsentTx(keyForNode(0));
 
@@ -200,4 +203,16 @@
 
         assertFalse(failed);
     }
+
+    /** {@inheritDoc} */
+    @Override protected <T> T doOperation(Supplier<T> op) {
+        while (true) {
+            try {
+                return super.doOperation(op);
+            }
+            catch (CacheException e) {
+                MvccFeatureChecker.assertMvccWriteConflict(e);
+            }
+        }
+    }
 }
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheOffHeapMultiThreadedUpdateAbstractSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheOffHeapMultiThreadedUpdateAbstractSelfTest.java
index f39e495..6ece9ec 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheOffHeapMultiThreadedUpdateAbstractSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheOffHeapMultiThreadedUpdateAbstractSelfTest.java
@@ -20,6 +20,7 @@
 import java.io.Serializable;
 import java.util.concurrent.Callable;
 import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.function.Supplier;
 import javax.cache.Cache;
 import javax.cache.processor.EntryProcessor;
 import javax.cache.processor.MutableEntry;
@@ -98,7 +99,7 @@
                     if (i % 500 == 0)
                         log.info("Iteration " + i);
 
-                    cache.invoke(key, new IncProcessor());
+                    doOperation(() -> cache.invoke(key, new IncProcessor()));
                 }
 
                 return null;
@@ -143,7 +144,8 @@
                     if (i % 500 == 0)
                         log.info("Iteration " + i);
 
-                    Integer val = cache.getAndPut(key, i);
+                    int val0 = i;
+                    Integer val = doOperation(() -> cache.getAndPut(key, val0));
 
                     assertNotNull(val);
                 }
@@ -235,7 +237,8 @@
                     if (i % 1000 == 0)
                         log.info("Put iteration " + i);
 
-                    cache.put(key, i);
+                    int val = i;
+                    doOperation(() -> cache.put(key, val));
                 }
 
                 return null;
@@ -304,6 +307,20 @@
         return 1_000;
     }
 
+    /** */
+    protected <T> T doOperation(Supplier<T> op) {
+        return op.get();
+    }
+
+    /** */
+    protected void doOperation(Runnable op) {
+        doOperation(() -> {
+            op.run();
+
+            return null;
+        });
+    }
+
     /**
      *
      */
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheTestEntryEx.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheTestEntryEx.java
index 9624bd8..d6e59af 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheTestEntryEx.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheTestEntryEx.java
@@ -84,6 +84,22 @@
     }
 
     /** {@inheritDoc} */
+    @Override public boolean initialValue(CacheObject val, GridCacheVersion ver, long ttl, long expireTime,
+        boolean preload, AffinityTopologyVersion topVer, GridDrType drType, boolean fromStore) {
+        assert false;
+
+        return false;
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean mvccPreloadEntry(
+        List<GridCacheMvccEntryInfo> entries) {
+        assert false;
+
+        return false;
+    }
+
+    /** {@inheritDoc} */
     @Override public boolean isInternal() {
         return key instanceof GridCacheInternal;
     }
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteClientCacheInitializationFailTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteClientCacheInitializationFailTest.java
index 5313c09..9e3af5a 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteClientCacheInitializationFailTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteClientCacheInitializationFailTest.java
@@ -42,7 +42,6 @@
 import org.apache.ignite.internal.IgniteInternalFuture;
 import org.apache.ignite.internal.IgniteKernal;
 import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion;
-import org.apache.ignite.internal.processors.cache.mvcc.MvccQueryTracker;
 import org.apache.ignite.internal.processors.cache.mvcc.MvccSnapshot;
 import org.apache.ignite.internal.processors.cache.persistence.CacheDataRow;
 import org.apache.ignite.internal.processors.query.GridQueryCancel;
@@ -285,9 +284,14 @@
         }
 
         /** {@inheritDoc} */
-        @Override public List<FieldsQueryCursor<List<?>>> querySqlFields(String schemaName, SqlFieldsQuery qry,
-            SqlClientContext cliCtx, boolean keepBinary, boolean failOnMultipleStmts, MvccQueryTracker tracker,
-            GridQueryCancel cancel, boolean registerAsNewQry) {
+        @Override public List<FieldsQueryCursor<List<?>>> querySqlFields(
+            String schemaName,
+            SqlFieldsQuery qry,
+            SqlClientContext cliCtx,
+            boolean keepBinary,
+            boolean failOnMultipleStmts,
+            GridQueryCancel cancel
+        ) {
             return null;
         }
 
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteClientCacheStartFailoverTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteClientCacheStartFailoverTest.java
index 26d94db..28daffe 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteClientCacheStartFailoverTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteClientCacheStartFailoverTest.java
@@ -572,8 +572,7 @@
             cache.putAll(map);
         }
 
-        //TODO: uncomment TRANSACTIONAL_SNAPSHOT cache creation when IGNITE-9470 will be fixed.
-       /* for (int i = 0; i < 3; i++) {
+       for (int i = 0; i < 3; i++) {
             CacheConfiguration<Object, Object> ccfg = cacheConfiguration("mvcc-" + i, TRANSACTIONAL_SNAPSHOT, i);
 
             IgniteCache<Object, Object> cache = node.createCache(ccfg);
@@ -581,7 +580,7 @@
             cacheNames.add(ccfg.getName());
 
             cache.putAll(map);
-        }*/
+        }
 
 
         return cacheNames;
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteMvccTxMultiThreadedAbstractTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteMvccTxMultiThreadedAbstractTest.java
index a6c0b57..9007050 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteMvccTxMultiThreadedAbstractTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteMvccTxMultiThreadedAbstractTest.java
@@ -25,7 +25,6 @@
 import org.apache.ignite.transactions.TransactionConcurrency;
 import org.apache.ignite.transactions.TransactionIsolation;
 import org.jetbrains.annotations.Nullable;
-import org.junit.Ignore;
 import org.junit.Test;
 
 import static org.apache.ignite.transactions.TransactionConcurrency.PESSIMISTIC;
@@ -34,13 +33,7 @@
 /**
  * Tests for local transactions.
  */
-@Ignore("https://issues.apache.org/jira/browse/IGNITE-9470")
 public abstract class IgniteMvccTxMultiThreadedAbstractTest extends IgniteTxAbstractTest {
-    /** {@inheritDoc} */
-    @Override protected void beforeTest() throws Exception {
-        // No-op.
-    }
-
     /**
      * @return Thread count.
      */
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteMvccTxSingleThreadedAbstractTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteMvccTxSingleThreadedAbstractTest.java
index 89d92ff..48533f4 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteMvccTxSingleThreadedAbstractTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteMvccTxSingleThreadedAbstractTest.java
@@ -18,7 +18,6 @@
 package org.apache.ignite.internal.processors.cache;
 
 import org.apache.ignite.IgniteCheckedException;
-import org.junit.Ignore;
 import org.junit.Test;
 
 import static org.apache.ignite.transactions.TransactionConcurrency.PESSIMISTIC;
@@ -31,7 +30,6 @@
     /**
      * @throws IgniteCheckedException If test failed.
      */
-    @Ignore("https://issues.apache.org/jira/browse/IGNITE-10261")
     @Test
     public void testPessimisticRepeatableReadCommit() throws Exception {
         checkCommit(PESSIMISTIC, REPEATABLE_READ);
@@ -42,7 +40,6 @@
     /**
      * @throws IgniteCheckedException If test failed.
      */
-    @Ignore("https://issues.apache.org/jira/browse/IGNITE-10261")
     @Test
     public void testPessimisticRepeatableReadRollback() throws Exception {
         checkRollback(PESSIMISTIC, REPEATABLE_READ);
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgnitePdsDataRegionMetricsTxTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgnitePdsDataRegionMetricsTxTest.java
index 49b734b..f31a2a6 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgnitePdsDataRegionMetricsTxTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgnitePdsDataRegionMetricsTxTest.java
@@ -21,8 +21,6 @@
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.internal.processors.cache.persistence.db.IgnitePdsDataRegionMetricsTest;
-import org.apache.ignite.testframework.MvccFeatureChecker;
-import org.junit.Assume;
 import org.junit.Ignore;
 import org.junit.Test;
 
@@ -45,8 +43,6 @@
     @Ignore("https://issues.apache.org/jira/browse/IGNITE-10662")
     @Test
     @Override public void testMemoryUsageMultipleNodes() throws Exception {
-        Assume.assumeFalse("https://issues.apache.org/jira/browse/IGNITE-10583", MvccFeatureChecker.forcedMvcc());
-
         super.testMemoryUsageMultipleNodes();
     }
 }
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteTxAbstractTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteTxAbstractTest.java
index a6ca1b7..585b201 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteTxAbstractTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteTxAbstractTest.java
@@ -24,6 +24,7 @@
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.atomic.AtomicInteger;
+import javax.cache.CacheException;
 import org.apache.ignite.Ignite;
 import org.apache.ignite.IgniteCache;
 import org.apache.ignite.IgniteCheckedException;
@@ -32,11 +33,13 @@
 import org.apache.ignite.internal.IgniteKernal;
 import org.apache.ignite.internal.util.typedef.F;
 import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.testframework.MvccFeatureChecker;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
 import org.apache.ignite.transactions.Transaction;
 import org.apache.ignite.transactions.TransactionConcurrency;
 import org.apache.ignite.transactions.TransactionIsolation;
 import org.apache.ignite.transactions.TransactionOptimisticException;
+import org.apache.ignite.transactions.TransactionSerializationException;
 
 import static org.apache.ignite.transactions.TransactionConcurrency.OPTIMISTIC;
 import static org.apache.ignite.transactions.TransactionIsolation.SERIALIZABLE;
@@ -44,7 +47,7 @@
 /**
  * Tests for local transactions.
  */
-@SuppressWarnings( {"BusyWait"})
+@SuppressWarnings({"BusyWait"})
 abstract class IgniteTxAbstractTest extends GridCommonAbstractTest {
     /** Random number generator. */
     private static final Random RAND = new Random();
@@ -209,6 +212,9 @@
                     throw e;
                 }
             }
+            catch (CacheException e) {
+                MvccFeatureChecker.assertMvccWriteConflict(e);
+            }
             catch (Throwable e) {
                 log.error("Unexpected error: " + e, e);
 
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteTxExceptionAbstractSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteTxExceptionAbstractSelfTest.java
index 3e48da2..8833f95 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteTxExceptionAbstractSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteTxExceptionAbstractSelfTest.java
@@ -36,6 +36,7 @@
 import org.apache.ignite.internal.processors.cache.distributed.near.GridNearCacheAdapter;
 import org.apache.ignite.internal.transactions.IgniteTxHeuristicCheckedException;
 import org.apache.ignite.internal.util.typedef.PA;
+import org.apache.ignite.internal.util.typedef.X;
 import org.apache.ignite.spi.IgniteSpiAdapter;
 import org.apache.ignite.spi.IgniteSpiException;
 import org.apache.ignite.spi.indexing.IndexingQueryFilter;
@@ -46,7 +47,6 @@
 import org.apache.ignite.transactions.TransactionConcurrency;
 import org.apache.ignite.transactions.TransactionHeuristicException;
 import org.apache.ignite.transactions.TransactionIsolation;
-import org.apache.ignite.transactions.TransactionRollbackException;
 import org.jetbrains.annotations.Nullable;
 import org.junit.Assume;
 import org.junit.Test;
@@ -100,6 +100,8 @@
 
     /** {@inheritDoc} */
     @Override protected void beforeTestsStarted() throws Exception {
+        Assume.assumeFalse("https://issues.apache.org/jira/browse/IGNITE-10871", MvccFeatureChecker.forcedMvcc());
+
         super.beforeTestsStarted();
 
         lastKey = 0;
@@ -327,8 +329,6 @@
      */
     private void checkPutTx(boolean putBefore, TransactionConcurrency concurrency,
         TransactionIsolation isolation, final Integer... keys) throws Exception {
-        Assume.assumeFalse("https://issues.apache.org/jira/browse/IGNITE-10871", MvccFeatureChecker.forcedMvcc());
-
         if (MvccFeatureChecker.forcedMvcc() &&
             !MvccFeatureChecker.isSupported(concurrency, isolation))
             return;
@@ -382,11 +382,9 @@
 
             fail("Transaction should fail.");
         }
-        catch (CacheException e){
-            if (!MvccFeatureChecker.forcedMvcc() || !(e.getCause() instanceof TransactionRollbackException))
-                throw e;
-        }
-        catch (TransactionHeuristicException e) {
+        catch (Exception e) {
+            assertTrue("Unexptected exception " + X.getFullStackTrace(e), e instanceof TransactionHeuristicException);
+
             log.info("Expected exception: " + e);
         }
 
@@ -491,12 +489,7 @@
 
                 return null;
             }
-        }, CacheException.class, null);
-
-        if (MvccFeatureChecker.forcedMvcc())
-            assertTrue(err.toString(), err.getCause() instanceof TransactionRollbackException); // Put operation fails.
-        else
-            assertTrue(err.toString(), err.getCause() instanceof TransactionHeuristicException); // Implicit tx commit fails.
+        }, TransactionHeuristicException.class, null);
 
         checkUnlocked(key);
     }
@@ -507,8 +500,6 @@
      * @throws Exception If failed.
      */
     private void checkTransform(boolean putBefore, final Integer key) throws Exception {
-        Assume.assumeFalse("https://issues.apache.org/jira/browse/IGNITE-9470", MvccFeatureChecker.forcedMvcc());
-
         if (putBefore) {
             TestIndexingSpi.forceFail(false);
 
@@ -586,12 +577,7 @@
 
                 return null;
             }
-        }, CacheException.class, null);
-
-        if (MvccFeatureChecker.forcedMvcc())
-            assertTrue(err.toString(), err.getCause() instanceof TransactionRollbackException); // Put operation fails.
-        else
-            assertTrue(err.toString(), err.getCause() instanceof TransactionHeuristicException); // Implicit tx commit fails.
+        }, TransactionHeuristicException.class, null);
 
         for (Integer key : m.keySet())
             checkUnlocked(key);
@@ -603,8 +589,6 @@
      * @throws Exception If failed.
      */
     private void checkRemove(boolean putBefore, final Integer key) throws Exception {
-        Assume.assumeFalse("https://issues.apache.org/jira/browse/IGNITE-9470", MvccFeatureChecker.forcedMvcc());
-
         if (putBefore) {
             TestIndexingSpi.forceFail(false);
 
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CacheLateAffinityAssignmentTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CacheLateAffinityAssignmentTest.java
index 294e8c8..6fc749d 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CacheLateAffinityAssignmentTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CacheLateAffinityAssignmentTest.java
@@ -90,13 +90,11 @@
 import org.apache.ignite.services.ServiceContext;
 import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
 import org.apache.ignite.testframework.GridTestUtils;
-import org.apache.ignite.testframework.MvccFeatureChecker;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
 import org.apache.ignite.transactions.Transaction;
 import org.apache.ignite.transactions.TransactionConcurrency;
 import org.apache.ignite.transactions.TransactionIsolation;
 import org.jetbrains.annotations.Nullable;
-import org.junit.Assume;
 import org.junit.Test;
 
 import static org.apache.ignite.cache.CacheAtomicityMode.ATOMIC;
@@ -1767,8 +1765,6 @@
      */
     @Test
     public void testRandomOperations() throws Exception {
-        Assume.assumeFalse("https://issues.apache.org/jira/browse/IGNITE-10261", MvccFeatureChecker.forcedMvcc());
-
         forceSrvMode = true;
 
         final int MAX_SRVS = 10;
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/GridCachePreloadRestartAbstractSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/GridCachePreloadRestartAbstractSelfTest.java
index f53910e..62350ad 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/GridCachePreloadRestartAbstractSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/GridCachePreloadRestartAbstractSelfTest.java
@@ -195,7 +195,7 @@
      */
     @Test
     public void testDisabledPreloadRestart() throws Exception {
-        Assume.assumeFalse("https://issues.apache.org/jira/browse/IGNITE-10261", MvccFeatureChecker.forcedMvcc());
+        Assume.assumeFalse("https://issues.apache.org/jira/browse/IGNITE-11417", MvccFeatureChecker.forcedMvcc());
 
         preloadMode = NONE;
 
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteCachePartitionLossPolicySelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteCachePartitionLossPolicySelfTest.java
index e3930f6..158bdd1 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteCachePartitionLossPolicySelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteCachePartitionLossPolicySelfTest.java
@@ -32,6 +32,7 @@
 import org.apache.ignite.Ignite;
 import org.apache.ignite.IgniteCache;
 import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.cache.CacheAtomicityMode;
 import org.apache.ignite.cache.PartitionLossPolicy;
 import org.apache.ignite.cache.affinity.Affinity;
 import org.apache.ignite.cache.affinity.rendezvous.RendezvousAffinityFunction;
@@ -56,20 +57,40 @@
 import org.apache.ignite.internal.util.typedef.internal.CU;
 import org.apache.ignite.plugin.extensions.communication.Message;
 import org.apache.ignite.testframework.GridTestUtils;
+import org.apache.ignite.testframework.MvccFeatureChecker;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
 import org.junit.Ignore;
 import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
 
 import static java.util.Arrays.asList;
 import static java.util.Collections.singletonList;
+import static org.apache.ignite.cache.CacheAtomicityMode.ATOMIC;
+import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL;
 import static org.apache.ignite.cache.CacheMode.PARTITIONED;
 import static org.apache.ignite.cache.CacheWriteSynchronizationMode.FULL_SYNC;
+import static org.junit.Assume.assumeFalse;
 
 /**
  *
  */
+@RunWith(Parameterized.class)
 public class IgniteCachePartitionLossPolicySelfTest extends GridCommonAbstractTest {
     /** */
+    @Parameterized.Parameters(name = "{0}")
+    public static List<Object[]> parameters() {
+        ArrayList<Object[]> params = new ArrayList<>();
+
+        params.add(new Object[]{TRANSACTIONAL});
+
+        if (!MvccFeatureChecker.forcedMvcc())
+            params.add(new Object[]{ATOMIC});
+
+        return params;
+    }
+
+    /** */
     private static boolean client;
 
     /** */
@@ -88,6 +109,10 @@
     /** */
     private static boolean isPersistenceEnabled;
 
+    /** */
+    @Parameterized.Parameter
+    public CacheAtomicityMode atomicity;
+
     /** {@inheritDoc} */
     @Override protected IgniteConfiguration getConfiguration(String gridName) throws Exception {
         IgniteConfiguration cfg = super.getConfiguration(gridName);
@@ -128,6 +153,7 @@
         cacheCfg.setWriteSynchronizationMode(FULL_SYNC);
         cacheCfg.setPartitionLossPolicy(partLossPlc);
         cacheCfg.setAffinity(new RendezvousAffinityFunction(false, 32));
+        cacheCfg.setAtomicityMode(atomicity);
 
         return cacheCfg;
     }
@@ -159,6 +185,8 @@
      */
     @Test
     public void testReadOnlySafe() throws Exception {
+        assumeFalse("https://issues.apache.org/jira/browse/IGNITE-11107", MvccFeatureChecker.forcedMvcc());
+
         partLossPlc = PartitionLossPolicy.READ_ONLY_SAFE;
 
         checkLostPartition(false, true, killSingleNode);
@@ -181,6 +209,8 @@
      */
     @Test
     public void testReadOnlyAll() throws Exception {
+        assumeFalse("https://issues.apache.org/jira/browse/IGNITE-11107", MvccFeatureChecker.forcedMvcc());
+
         partLossPlc = PartitionLossPolicy.READ_ONLY_ALL;
 
         checkLostPartition(false, false, killSingleNode);
@@ -204,6 +234,8 @@
      */
     @Test
     public void testReadWriteSafe() throws Exception {
+        assumeFalse("https://issues.apache.org/jira/browse/IGNITE-11107", MvccFeatureChecker.forcedMvcc());
+
         partLossPlc = PartitionLossPolicy.READ_WRITE_SAFE;
 
         checkLostPartition(true, true, killSingleNode);
@@ -226,6 +258,8 @@
      */
     @Test
     public void testReadWriteAll() throws Exception {
+        assumeFalse("https://issues.apache.org/jira/browse/IGNITE-11107", MvccFeatureChecker.forcedMvcc());
+
         partLossPlc = PartitionLossPolicy.READ_WRITE_ALL;
 
         checkLostPartition(true, false, killSingleNode);
@@ -249,6 +283,8 @@
      */
     @Test
     public void testReadWriteSafeAfterKillTwoNodes() throws Exception {
+        assumeFalse("https://issues.apache.org/jira/browse/IGNITE-11107", MvccFeatureChecker.forcedMvcc());
+
         partLossPlc = PartitionLossPolicy.READ_WRITE_SAFE;
 
         checkLostPartition(true, true, new TopologyChanger(false, asList(3, 2), asList(0, 1, 4), 0));
@@ -271,6 +307,8 @@
      */
     @Test
     public void testReadWriteSafeAfterKillTwoNodesWithDelay() throws Exception {
+        assumeFalse("https://issues.apache.org/jira/browse/IGNITE-11107", MvccFeatureChecker.forcedMvcc());
+
         partLossPlc = PartitionLossPolicy.READ_WRITE_SAFE;
 
         checkLostPartition(true, true, new TopologyChanger(false, asList(3, 2), asList(0, 1, 4), 20));
@@ -293,6 +331,8 @@
      */
     @Test
     public void testReadWriteSafeWithBackupsAfterKillThreeNodes() throws Exception {
+        assumeFalse("https://issues.apache.org/jira/browse/IGNITE-11107", MvccFeatureChecker.forcedMvcc());
+
         partLossPlc = PartitionLossPolicy.READ_WRITE_SAFE;
 
         backups = 1;
@@ -319,6 +359,8 @@
      */
     @Test
     public void testReadWriteSafeAfterKillCrd() throws Exception {
+        assumeFalse("https://issues.apache.org/jira/browse/IGNITE-11107", MvccFeatureChecker.forcedMvcc());
+
         partLossPlc = PartitionLossPolicy.READ_WRITE_SAFE;
 
         checkLostPartition(true, true, new TopologyChanger(true, asList(3, 0), asList(1, 2, 4), 0));
@@ -341,6 +383,8 @@
      */
     @Test
     public void testReadWriteSafeWithBackups() throws Exception {
+        assumeFalse("https://issues.apache.org/jira/browse/IGNITE-11107", MvccFeatureChecker.forcedMvcc());
+
         partLossPlc = PartitionLossPolicy.READ_WRITE_SAFE;
 
         backups = 1;
@@ -367,6 +411,8 @@
      */
     @Test
     public void testReadWriteSafeWithBackupsAfterKillCrd() throws Exception {
+        assumeFalse("https://issues.apache.org/jira/browse/IGNITE-11107", MvccFeatureChecker.forcedMvcc());
+
         partLossPlc = PartitionLossPolicy.READ_WRITE_SAFE;
 
         backups = 1;
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteTxCacheWriteSynchronizationModesMultithreadedTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteTxCacheWriteSynchronizationModesMultithreadedTest.java
index 829d9dc..ecec29a 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteTxCacheWriteSynchronizationModesMultithreadedTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteTxCacheWriteSynchronizationModesMultithreadedTest.java
@@ -32,7 +32,6 @@
 import org.apache.ignite.Ignite;
 import org.apache.ignite.IgniteCache;
 import org.apache.ignite.IgniteException;
-import org.apache.ignite.IgniteSystemProperties;
 import org.apache.ignite.cache.CacheWriteSynchronizationMode;
 import org.apache.ignite.cache.store.CacheStore;
 import org.apache.ignite.cache.store.CacheStoreAdapter;
@@ -51,7 +50,6 @@
 import org.apache.ignite.transactions.Transaction;
 import org.apache.ignite.transactions.TransactionOptimisticException;
 import org.jetbrains.annotations.NotNull;
-import org.junit.Assume;
 import org.junit.Test;
 
 import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL;
@@ -112,11 +110,6 @@
             assertTrue(grid(SRVS + i).configuration().isClientMode());
     }
 
-    /** {@inheritDoc} */
-    @Override protected void beforeTest() throws Exception {
-        Assume.assumeFalse("https://issues.apache.org/jira/browse/IGNITE-9470", MvccFeatureChecker.forcedMvcc());
-    }
-
     /**
      * @throws Exception If failed.
      */
@@ -231,7 +224,16 @@
 
                     Integer key = rnd.nextInt(MULTITHREADED_TEST_KEYS);
 
-                    cache.put(key, rnd.nextInt());
+                    while (true) {
+                        try {
+                            cache.put(key, rnd.nextInt());
+
+                            break;
+                        }
+                        catch (CacheException e) {
+                            MvccFeatureChecker.assertMvccWriteConflict(e);
+                        }
+                    }
                 }
             });
 
@@ -247,7 +249,16 @@
                         map.put(key, rnd.nextInt());
                     }
 
-                    cache.putAll(map);
+                    while (true) {
+                        try {
+                            cache.putAll(map);
+
+                            break;
+                        }
+                        catch (CacheException e) {
+                            MvccFeatureChecker.assertMvccWriteConflict(e);
+                        }
+                    }
                 }
             });
 
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteTxConcurrentRemoveObjectsTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteTxConcurrentRemoveObjectsTest.java
index 5a65e21..b04c580 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteTxConcurrentRemoveObjectsTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteTxConcurrentRemoveObjectsTest.java
@@ -20,7 +20,6 @@
 import java.util.UUID;
 import org.apache.ignite.IgniteCache;
 import org.apache.ignite.IgniteDataStreamer;
-import org.apache.ignite.IgniteSystemProperties;
 import org.apache.ignite.cache.CacheAtomicityMode;
 import org.apache.ignite.cache.affinity.rendezvous.RendezvousAffinityFunction;
 import org.apache.ignite.configuration.CacheConfiguration;
@@ -30,11 +29,12 @@
 import org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridDhtLocalPartition;
 import org.apache.ignite.internal.processors.cache.version.GridCacheVersion;
 import org.apache.ignite.testframework.GridTestUtils;
+import org.apache.ignite.testframework.junits.WithSystemProperty;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
 import org.apache.ignite.transactions.Transaction;
-import org.junit.Test;
 import org.apache.ignite.transactions.TransactionConcurrency;
 import org.apache.ignite.transactions.TransactionIsolation;
+import org.junit.Test;
 
 import static org.apache.ignite.IgniteSystemProperties.IGNITE_CACHE_REMOVED_ENTRIES_TTL;
 import static org.apache.ignite.transactions.TransactionIsolation.REPEATABLE_READ;
@@ -43,6 +43,7 @@
 /**
  *
  */
+@WithSystemProperty(key = IGNITE_CACHE_REMOVED_ENTRIES_TTL, value = "50")
 public class IgniteTxConcurrentRemoveObjectsTest extends GridCommonAbstractTest {
     /** Cache partitions. */
     private static final int CACHE_PARTITIONS = 16;
@@ -50,31 +51,14 @@
     /** Cache entries count. */
     private static final int CACHE_ENTRIES_COUNT = 512 * CACHE_PARTITIONS;
 
-    /** New value for {@link IgniteSystemProperties#IGNITE_CACHE_REMOVED_ENTRIES_TTL} property. */
-    private static final long newIgniteCacheRemovedEntriesTtl = 50L;
-
-    /** Old value of {@link IgniteSystemProperties#IGNITE_CACHE_REMOVED_ENTRIES_TTL} property. */
-    private static long oldIgniteCacheRmvEntriesTtl;
-
     /** {@inheritDoc} */
     @Override protected void beforeTestsStarted() throws Exception {
         super.beforeTestsStarted();
 
-        oldIgniteCacheRmvEntriesTtl = Long.getLong(IGNITE_CACHE_REMOVED_ENTRIES_TTL, 10_000);
-
-        System.setProperty(IGNITE_CACHE_REMOVED_ENTRIES_TTL, Long.toString(newIgniteCacheRemovedEntriesTtl));
-
         startGrid(0);
     }
 
     /** {@inheritDoc} */
-    @Override protected void afterTestsStopped() throws Exception {
-        System.setProperty(IGNITE_CACHE_REMOVED_ENTRIES_TTL, Long.toString(oldIgniteCacheRmvEntriesTtl));
-
-        super.afterTestsStopped();
-    }
-
-    /** {@inheritDoc} */
     @Override protected void afterTest() throws Exception {
         grid(0).destroyCache(DEFAULT_CACHE_NAME);
 
@@ -167,7 +151,7 @@
                 .flatMap(cgctx -> cgctx.topology().localPartitions().stream())
                 .mapToInt(GridDhtLocalPartition::internalSize)
                 .max().orElse(-1) == 0,
-            newIgniteCacheRemovedEntriesTtl * 10
+            500L
         );
     }
 }
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridCacheColocatedMvccTxSingleThreadedSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridCacheColocatedMvccTxSingleThreadedSelfTest.java
index 717d771..c8c117a 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridCacheColocatedMvccTxSingleThreadedSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridCacheColocatedMvccTxSingleThreadedSelfTest.java
@@ -24,7 +24,6 @@
 
 import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL_SNAPSHOT;
 import static org.apache.ignite.cache.CacheMode.PARTITIONED;
-import static org.apache.ignite.cache.CacheRebalanceMode.NONE;
 
 /**
  * Test Mvcc txs in single-threaded mode for colocated cache.
@@ -45,8 +44,6 @@
 
         ccfg.setWriteSynchronizationMode(CacheWriteSynchronizationMode.FULL_ASYNC);
 
-        ccfg.setRebalanceMode(NONE);
-
         cfg.setCacheConfiguration(ccfg);
 
         return cfg;
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridCacheColocatedTxExceptionSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridCacheColocatedTxExceptionSelfTest.java
index 89d1060..eb3d037 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridCacheColocatedTxExceptionSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridCacheColocatedTxExceptionSelfTest.java
@@ -20,8 +20,6 @@
 import org.apache.ignite.cache.CacheMode;
 import org.apache.ignite.configuration.NearCacheConfiguration;
 import org.apache.ignite.internal.processors.cache.IgniteTxExceptionAbstractSelfTest;
-import org.junit.Ignore;
-import org.junit.Test;
 
 import static org.apache.ignite.cache.CacheMode.PARTITIONED;
 
@@ -38,60 +36,4 @@
     @Override protected NearCacheConfiguration nearConfiguration() {
         return null;
     }
-
-    /** */
-    @Ignore("https://issues.apache.org/jira/browse/IGNITE-10377")
-    @Test
-    @Override public void testPutAll() throws Exception {
-        super.testPutAll();
-    }
-
-    /** */
-    @Ignore("https://issues.apache.org/jira/browse/IGNITE-10377")
-    @Test
-    @Override public void testPutBackup() throws Exception {
-        super.testPutBackup();
-    }
-
-    /** */
-    @Ignore("https://issues.apache.org/jira/browse/IGNITE-10377")
-    @Test
-    @Override public void testPutBackupTx() throws Exception {
-        super.testPutBackupTx();
-    }
-
-    /** */
-    @Ignore("https://issues.apache.org/jira/browse/IGNITE-10377")
-    @Test
-    @Override public void testPutMultipleKeysTx() throws Exception {
-        super.testPutMultipleKeysTx();
-    }
-
-    /** */
-    @Ignore("https://issues.apache.org/jira/browse/IGNITE-10377")
-    @Test
-    @Override public void testPutNear() throws Exception {
-        super.testPutNear();
-    }
-
-    /** */
-    @Ignore("https://issues.apache.org/jira/browse/IGNITE-10377")
-    @Test
-    @Override public void testPutNearTx() throws Exception {
-        super.testPutNearTx();
-    }
-
-    /** */
-    @Ignore("https://issues.apache.org/jira/browse/IGNITE-10377")
-    @Test
-    @Override public void testPutPrimary() throws Exception {
-        super.testPutPrimary();
-    }
-
-    /** */
-    @Ignore("https://issues.apache.org/jira/browse/IGNITE-10377")
-    @Test
-    @Override public void testPutPrimaryTx() throws Exception {
-        super.testPutPrimaryTx();
-    }
 }
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridCacheDhtPreloadPutGetSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridCacheDhtPreloadPutGetSelfTest.java
index a2070f5..b417dcd 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridCacheDhtPreloadPutGetSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridCacheDhtPreloadPutGetSelfTest.java
@@ -17,6 +17,8 @@
 
 package org.apache.ignite.internal.processors.cache.distributed.dht;
 
+import java.util.Arrays;
+import java.util.Map;
 import java.util.concurrent.Callable;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
@@ -152,6 +154,8 @@
      */
     @Test
     public void testPutGetNone0() throws Exception {
+        Assume.assumeFalse("https://issues.apache.org/jira/browse/IGNITE-11417", MvccFeatureChecker.forcedMvcc());
+
         preloadMode = NONE;
         backups = 0;
 
@@ -163,7 +167,7 @@
      */
     @Test
     public void testPutGetNone1() throws Exception {
-        Assume.assumeFalse("https://issues.apache.org/jira/browse/IGNITE-10261", MvccFeatureChecker.forcedMvcc());
+        Assume.assumeFalse("https://issues.apache.org/jira/browse/IGNITE-11417", MvccFeatureChecker.forcedMvcc());
 
         preloadMode = NONE;
         backups = 1;
@@ -176,7 +180,7 @@
      */
     @Test
     public void testPutGetNone2() throws Exception {
-        Assume.assumeFalse("https://issues.apache.org/jira/browse/IGNITE-10261", MvccFeatureChecker.forcedMvcc());
+        Assume.assumeFalse("https://issues.apache.org/jira/browse/IGNITE-11417", MvccFeatureChecker.forcedMvcc());
 
         preloadMode = NONE;
         backups = 2;
@@ -247,10 +251,16 @@
                             done.set(true);
 
                             for (int j = 0; j < KEY_CNT; j++) {
+                                // Check SingleGetFuture.
                                 Integer val = internalCache(cache).get(j);
 
                                 assert val != null;
 
+                                // Check GetFuture.
+                                Map<Integer, Integer> vals = internalCache(cache).getAll(Arrays.asList(j, j + 1));
+
+                                assert val.equals(vals.get(j));
+
                                 if (j % FREQUENCY == 0)
                                     info("Read entry: " + j + " -> " + val);
 
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/near/GridCachePartitionedMvccTxMultiThreadedSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/near/GridCachePartitionedMvccTxMultiThreadedSelfTest.java
index afe3e1c..b126720 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/near/GridCachePartitionedMvccTxMultiThreadedSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/near/GridCachePartitionedMvccTxMultiThreadedSelfTest.java
@@ -22,7 +22,9 @@
 import org.apache.ignite.configuration.NearCacheConfiguration;
 import org.apache.ignite.internal.processors.cache.IgniteMvccTxMultiThreadedAbstractTest;
 import org.apache.ignite.testframework.MvccFeatureChecker;
+import org.junit.Assume;
 
+import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL_SNAPSHOT;
 import static org.apache.ignite.cache.CacheMode.PARTITIONED;
 import static org.apache.ignite.cache.CacheWriteSynchronizationMode.FULL_SYNC;
 
@@ -31,20 +33,20 @@
  */
 public class GridCachePartitionedMvccTxMultiThreadedSelfTest extends IgniteMvccTxMultiThreadedAbstractTest {
     /** {@inheritDoc} */
-    @Override protected void beforeTest() throws Exception {
+    @Override protected void beforeTestsStarted() throws Exception {
         if (nearEnabled())
-            MvccFeatureChecker.skipIfNotSupported(MvccFeatureChecker.Feature.NEAR_CACHE);
+            Assume.assumeTrue(MvccFeatureChecker.isSupported(MvccFeatureChecker.Feature.NEAR_CACHE));
+
+        super.beforeTestsStarted();
     }
 
     /** {@inheritDoc} */
     @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception {
-        if (nearEnabled())
-            MvccFeatureChecker.skipIfNotSupported(MvccFeatureChecker.Feature.NEAR_CACHE);
-
         IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName);
 
         CacheConfiguration<?, ?> ccfg = defaultCacheConfiguration();
 
+        ccfg.setAtomicityMode(TRANSACTIONAL_SNAPSHOT);
         ccfg.setCacheMode(PARTITIONED);
         ccfg.setBackups(1);
 
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/near/GridCachePartitionedMvccTxSingleThreadedSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/near/GridCachePartitionedMvccTxSingleThreadedSelfTest.java
index 1404839..c282a76 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/near/GridCachePartitionedMvccTxSingleThreadedSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/near/GridCachePartitionedMvccTxSingleThreadedSelfTest.java
@@ -24,7 +24,6 @@
 
 import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL_SNAPSHOT;
 import static org.apache.ignite.cache.CacheMode.PARTITIONED;
-import static org.apache.ignite.cache.CacheRebalanceMode.NONE;
 
 /**
  * Tests for partitioned cache transactions.
@@ -45,8 +44,6 @@
 
         ccfg.setWriteSynchronizationMode(CacheWriteSynchronizationMode.FULL_ASYNC);
 
-        ccfg.setRebalanceMode(NONE);
-
         cfg.setCacheConfiguration(ccfg);
 
         return cfg;
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/rebalancing/GridCacheRebalancingSyncSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/rebalancing/GridCacheRebalancingSyncSelfTest.java
index 3bd4a25..8d7ba7c 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/rebalancing/GridCacheRebalancingSyncSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/rebalancing/GridCacheRebalancingSyncSelfTest.java
@@ -30,9 +30,12 @@
 import org.apache.ignite.cache.CacheAtomicityMode;
 import org.apache.ignite.cache.CacheMode;
 import org.apache.ignite.cache.CacheRebalanceMode;
+import org.apache.ignite.cache.affinity.rendezvous.RendezvousAffinityFunction;
 import org.apache.ignite.cache.query.ScanQuery;
 import org.apache.ignite.cluster.ClusterNode;
 import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.configuration.DataRegionConfiguration;
+import org.apache.ignite.configuration.DataStorageConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.internal.IgniteEx;
 import org.apache.ignite.internal.IgniteKernal;
@@ -55,12 +58,10 @@
 import org.apache.ignite.resources.LoggerResource;
 import org.apache.ignite.spi.IgniteSpiException;
 import org.apache.ignite.spi.communication.tcp.TcpCommunicationSpi;
-import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
 import org.apache.ignite.testframework.GridTestUtils;
 import org.apache.ignite.testframework.GridTestUtils.SF;
 import org.apache.ignite.testframework.MvccFeatureChecker;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
-import org.junit.Assume;
 import org.junit.Test;
 
 import static org.apache.ignite.cache.CacheMode.LOCAL;
@@ -107,18 +108,18 @@
     @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception {
         IgniteConfiguration iCfg = super.getConfiguration(igniteInstanceName);
 
-        ((TcpDiscoverySpi)iCfg.getDiscoverySpi()).setForceServerMode(true);
+        if (MvccFeatureChecker.forcedMvcc()) {
+            iCfg.setDataStorageConfiguration(new DataStorageConfiguration()
+                .setDefaultDataRegionConfiguration(
+                    new DataRegionConfiguration().setMaxSize(400L * 1024 * 1024)
+                ));
+        }
 
         TcpCommunicationSpi commSpi = new CollectingCommunicationSpi();
-
-        commSpi.setLocalPort(GridTestUtils.getNextCommPort(getClass()));
         commSpi.setTcpNoDelay(true);
 
         iCfg.setCommunicationSpi(commSpi);
 
-        if (getTestIgniteInstanceName(10).equals(igniteInstanceName))
-            iCfg.setClientMode(true);
-
         CacheConfiguration<Integer, Integer> cachePCfg = new CacheConfiguration<>(DEFAULT_CACHE_NAME);
 
         cachePCfg.setName(CACHE_NAME_DHT_PARTITIONED);
@@ -129,6 +130,7 @@
         cachePCfg.setRebalanceBatchesPrefetchCount(1);
         cachePCfg.setRebalanceOrder(2);
         cachePCfg.setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL);
+        cachePCfg.setAffinity(new RendezvousAffinityFunction().setPartitions(32));
 
         CacheConfiguration<Integer, Integer> cachePCfg2 = new CacheConfiguration<>(DEFAULT_CACHE_NAME);
 
@@ -139,7 +141,7 @@
         cachePCfg2.setRebalanceOrder(2);
         cachePCfg2.setRebalanceDelay(SF.applyLB(5000, 500));
         cachePCfg2.setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL);
-
+        cachePCfg2.setAffinity(new RendezvousAffinityFunction().setPartitions(32));
 
         CacheConfiguration<Integer, Integer> cacheRCfg = new CacheConfiguration<>(DEFAULT_CACHE_NAME);
 
@@ -149,8 +151,7 @@
         cacheRCfg.setRebalanceBatchSize(1);
         cacheRCfg.setRebalanceBatchesPrefetchCount(Integer.MAX_VALUE);
         cacheRCfg.setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL);
-
-        ((TcpCommunicationSpi)iCfg.getCommunicationSpi()).setSharedMemoryPort(-1);//Shmem fail fix for Integer.MAX_VALUE.
+        cacheRCfg.setAffinity(new RendezvousAffinityFunction().setPartitions(32));
 
         CacheConfiguration<Integer, Integer> cacheRCfg2 = new CacheConfiguration<>(DEFAULT_CACHE_NAME);
 
@@ -159,6 +160,7 @@
         cacheRCfg2.setRebalanceMode(CacheRebalanceMode.SYNC);
         cacheRCfg2.setRebalanceOrder(4);
         cacheRCfg2.setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL);
+        cacheRCfg2.setAffinity(new RendezvousAffinityFunction().setPartitions(32));
 
         iCfg.setCacheConfiguration(cachePCfg, cachePCfg2, cacheRCfg, cacheRCfg2);
 
@@ -231,7 +233,7 @@
                         TEST_SIZE + ", iteration=" + iter + ", cache=" + name + "]");
 
                 assertEquals("Value does not match [key=" + entry.getKey() + ", cache=" + name + ']',
-                    entry.getValue().intValue(), entry.getKey() + name.hashCode() + iter);
+                    entry.getKey() + name.hashCode() + iter, entry.getValue().intValue());
             });
 
             assertEquals(TEST_SIZE, cnt.get());
@@ -260,8 +262,6 @@
      */
     @Test
     public void testSimpleRebalancing() throws Exception {
-        Assume.assumeFalse("https://issues.apache.org/jira/browse/IGNITE-10560", MvccFeatureChecker.forcedMvcc());
-
         IgniteKernal ignite = (IgniteKernal)startGrid(0);
 
         generateData(ignite, 0, 0);
@@ -502,8 +502,6 @@
      */
     @Test
     public void testComplexRebalancing() throws Exception {
-        Assume.assumeFalse("https://issues.apache.org/jira/browse/IGNITE-10561", MvccFeatureChecker.forcedMvcc());
-
         final Ignite ignite = startGrid(0);
 
         generateData(ignite, 0, 0);
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/rebalancing/GridCacheRebalancingUnmarshallingFailedSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/rebalancing/GridCacheRebalancingUnmarshallingFailedSelfTest.java
index 9ee0892..81cfaad 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/rebalancing/GridCacheRebalancingUnmarshallingFailedSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/rebalancing/GridCacheRebalancingUnmarshallingFailedSelfTest.java
@@ -29,6 +29,9 @@
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.internal.binary.BinaryMarshaller;
+import org.apache.ignite.internal.marshaller.optimized.OptimizedMarshaller;
+import org.apache.ignite.marshaller.Marshaller;
+import org.apache.ignite.marshaller.jdk.JdkMarshaller;
 import org.apache.ignite.testframework.config.GridTestProperties;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
 import org.apache.ignite.thread.IgniteThread;
@@ -44,6 +47,9 @@
     /** Allows to change behavior of readExternal method. */
     protected static AtomicInteger readCnt = new AtomicInteger();
 
+    /** */
+    private volatile Marshaller marshaller;
+
     /** Test key 1. */
     private static class TestKey implements Externalizable {
         /** Field. */
@@ -109,6 +115,7 @@
         cfg.setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL);
 
         iCfg.setCacheConfiguration(cfg);
+        iCfg.setMarshaller(marshaller);
 
         return iCfg;
     }
@@ -117,12 +124,38 @@
      * @throws Exception e.
      */
     @Test
-    public void test() throws Exception {
-        String marshClsName = GridTestProperties.getProperty(GridTestProperties.MARSH_CLASS_NAME);
+    public void testBinary() throws Exception {
+        marshaller = new BinaryMarshaller();
 
-        // This test passes with binary marshaller because we do not unmarshall keys.
-        if (marshClsName != null && marshClsName.contains(BinaryMarshaller.class.getSimpleName()))
-            return;
+        runTest();
+    }
+
+
+    /**
+     * @throws Exception e.
+     */
+    @Test
+    public void testOptimized() throws Exception {
+        marshaller = new OptimizedMarshaller();
+
+        runTest();
+    }
+
+    /**
+     * @throws Exception e.
+     */
+    @Test
+    public void testJdk() throws Exception {
+        marshaller = new JdkMarshaller();
+
+        runTest();
+    }
+
+    /**
+     * @throws Exception e.
+     */
+    private void runTest() throws Exception {
+        assert marshaller != null;
 
         readCnt.set(Integer.MAX_VALUE);
 
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/replicated/GridCacheReplicatedMvccTxMultiThreadedSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/replicated/GridCacheReplicatedMvccTxMultiThreadedSelfTest.java
index 2df5d45..87e69df 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/replicated/GridCacheReplicatedMvccTxMultiThreadedSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/replicated/GridCacheReplicatedMvccTxMultiThreadedSelfTest.java
@@ -17,6 +17,7 @@
 
 package org.apache.ignite.internal.processors.cache.distributed.replicated;
 
+import org.apache.ignite.cache.CacheAtomicityMode;
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.internal.processors.cache.IgniteMvccTxMultiThreadedAbstractTest;
@@ -34,6 +35,7 @@
 
         CacheConfiguration ccfg = defaultCacheConfiguration();
 
+        ccfg.setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL_SNAPSHOT);
         ccfg.setCacheMode(REPLICATED);
         ccfg.setEvictionPolicy(null);
 
@@ -78,4 +80,4 @@
     @Override protected boolean printMemoryStats() {
         return true;
     }
-}
\ No newline at end of file
+}
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/replicated/GridCacheReplicatedTxExceptionSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/replicated/GridCacheReplicatedTxExceptionSelfTest.java
index c51d85a..c989822 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/replicated/GridCacheReplicatedTxExceptionSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/replicated/GridCacheReplicatedTxExceptionSelfTest.java
@@ -20,8 +20,6 @@
 import org.apache.ignite.cache.CacheMode;
 import org.apache.ignite.configuration.NearCacheConfiguration;
 import org.apache.ignite.internal.processors.cache.IgniteTxExceptionAbstractSelfTest;
-import org.junit.Ignore;
-import org.junit.Test;
 
 import static org.apache.ignite.cache.CacheMode.REPLICATED;
 
@@ -38,60 +36,4 @@
     @Override protected NearCacheConfiguration nearConfiguration() {
         return null;
     }
-
-    /** */
-    @Ignore("https://issues.apache.org/jira/browse/IGNITE-10377")
-    @Test
-    @Override public void testPutAll() throws Exception {
-        super.testPutAll();
-    }
-
-    /** */
-    @Ignore("https://issues.apache.org/jira/browse/IGNITE-10377")
-    @Test
-    @Override public void testPutBackup() throws Exception {
-        super.testPutBackup();
-    }
-
-    /** */
-    @Ignore("https://issues.apache.org/jira/browse/IGNITE-10377")
-    @Test
-    @Override public void testPutBackupTx() throws Exception {
-        super.testPutBackupTx();
-    }
-
-    /** */
-    @Ignore("https://issues.apache.org/jira/browse/IGNITE-10377")
-    @Test
-    @Override public void testPutMultipleKeysTx() throws Exception {
-        super.testPutMultipleKeysTx();
-    }
-
-    /** */
-    @Ignore("https://issues.apache.org/jira/browse/IGNITE-10377")
-    @Test
-    @Override public void testPutNear() throws Exception {
-        super.testPutNear();
-    }
-
-    /** */
-    @Ignore("https://issues.apache.org/jira/browse/IGNITE-10377")
-    @Test
-    @Override public void testPutNearTx() throws Exception {
-        super.testPutNearTx();
-    }
-
-    /** */
-    @Ignore("https://issues.apache.org/jira/browse/IGNITE-10377")
-    @Test
-    @Override public void testPutPrimary() throws Exception {
-        super.testPutPrimary();
-    }
-
-    /** */
-    @Ignore("https://issues.apache.org/jira/browse/IGNITE-10377")
-    @Test
-    @Override public void testPutPrimaryTx() throws Exception {
-        super.testPutPrimaryTx();
-    }
 }
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/mvcc/CacheMvccConfigurationValidationTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/mvcc/CacheMvccConfigurationValidationTest.java
index 3b65818..fb83ae0 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/mvcc/CacheMvccConfigurationValidationTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/mvcc/CacheMvccConfigurationValidationTest.java
@@ -31,6 +31,7 @@
 import org.apache.ignite.cache.CacheAtomicityMode;
 import org.apache.ignite.cache.CacheInterceptor;
 import org.apache.ignite.cache.CacheMode;
+import org.apache.ignite.cache.CacheRebalanceMode;
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.DataRegionConfiguration;
 import org.apache.ignite.configuration.DataStorageConfiguration;
@@ -286,6 +287,11 @@
         );
 
         assertCannotStart(
+            mvccCacheConfig().setRebalanceMode(CacheRebalanceMode.NONE),
+            "Rebalance mode NONE cannot be used with TRANSACTIONAL_SNAPSHOT atomicity mode"
+        );
+
+        assertCannotStart(
             mvccCacheConfig().setNearConfiguration(new NearCacheConfiguration<>()),
             "near cache cannot be used with TRANSACTIONAL_SNAPSHOT atomicity mode"
         );
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 ad19735..8243336 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
@@ -82,18 +82,15 @@
 import org.apache.ignite.internal.util.typedef.X;
 import org.apache.ignite.internal.util.typedef.internal.CU;
 import org.apache.ignite.internal.util.typedef.internal.S;
-import org.apache.ignite.internal.util.typedef.internal.U;
-import org.apache.ignite.lang.IgniteBiInClosure;
 import org.apache.ignite.lang.IgniteBiPredicate;
 import org.apache.ignite.lang.IgniteBiTuple;
 import org.apache.ignite.lang.IgniteInClosure;
 import org.apache.ignite.plugin.extensions.communication.Message;
 import org.apache.ignite.testframework.GridTestUtils;
+import org.apache.ignite.testframework.MvccFeatureChecker;
 import org.apache.ignite.transactions.Transaction;
 import org.apache.ignite.transactions.TransactionIsolation;
-import org.apache.ignite.transactions.TransactionSerializationException;
 import org.jetbrains.annotations.Nullable;
-import org.junit.Assert;
 import org.junit.Ignore;
 import org.junit.Test;
 
@@ -107,9 +104,7 @@
 import static org.apache.ignite.transactions.TransactionIsolation.REPEATABLE_READ;
 
 /**
- * TODO IGNITE-6739: tests reload
- * TODO IGNITE-6739: extend tests to use single/mutiple nodes, all tx types.
- * TODO IGNITE-6739: test with cache groups.
+ *
  */
 @SuppressWarnings("unchecked")
 public class CacheMvccTransactionsTest extends CacheMvccAbstractTest {
@@ -895,7 +890,6 @@
     /**
      * @throws Exception If failed.
      */
-    @Ignore("https://issues.apache.org/jira/browse/IGNITE-9470")
     @Test
     public void testWaitPreviousTxAck() throws Exception {
         testSpi = true;
@@ -912,33 +906,18 @@
         try (Transaction tx = ignite.transactions().txStart(PESSIMISTIC, REPEATABLE_READ)) {
             cache.put(1, 1);
             cache.put(2, 1);
-            cache.put(3, 1);
 
             tx.commit();
         }
 
         TestRecordingCommunicationSpi clientSpi = TestRecordingCommunicationSpi.spi(ignite);
 
-        clientSpi.blockMessages(new IgniteBiPredicate<ClusterNode, Message>() {
-            /** */
-            boolean block = true;
-
-            @Override public boolean apply(ClusterNode node, Message msg) {
-                if (block && msg instanceof MvccAckRequestTx) {
-                    block = false;
-
-                    return true;
-                }
-
-                return false;
-            }
-        });
+        clientSpi.blockMessages((node, msg) -> msg instanceof MvccAckRequestTx);
 
         IgniteInternalFuture<?> txFut1 = GridTestUtils.runAsync(new Callable<Void>() {
             @Override public Void call() throws Exception {
                 try (Transaction tx = ignite.transactions().txStart(PESSIMISTIC, REPEATABLE_READ)) {
-                    cache.put(2, 2);
-                    cache.put(3, 2);
+                    cache.put(1, 2);
 
                     tx.commit();
                 }
@@ -950,24 +929,22 @@
         IgniteInternalFuture<?> txFut2 = GridTestUtils.runAsync(new Callable<Void>() {
             @Override public Void call() throws Exception {
                 try (Transaction tx = ignite.transactions().txStart(PESSIMISTIC, REPEATABLE_READ)) {
-                    cache.put(1, 3);
                     cache.put(2, 3);
 
                     tx.commit();
                 }
 
-                // Should see changes mady by both tx1 and tx2.
-                Map<Object, Object> res = checkAndGetAll(false, cache, F.asSet(1, 2, 3), SCAN, GET);
+                // Should see changes made by both tx1 and tx2.
+                Map<Object, Object> res = checkAndGetAll(false, cache, F.asSet(1, 2), SCAN, GET);
 
-                assertEquals(3, res.get(1));
+                assertEquals(2, res.get(1));
                 assertEquals(3, res.get(2));
-                assertEquals(2, res.get(3));
 
                 return null;
             }
         });
 
-        clientSpi.waitForBlocked();
+        clientSpi.waitForBlocked(2);
 
         Thread.sleep(1000);
 
@@ -976,11 +953,10 @@
         txFut1.get();
         txFut2.get();
 
-        Map<Object, Object> res = checkAndGetAll(false, cache, F.asSet(1, 2, 3), SCAN, GET);
+        Map<Object, Object> res = checkAndGetAll(false, cache, F.asSet(1, 2), SCAN, GET);
 
-        assertEquals(3, res.get(1));
+        assertEquals(2, res.get(1));
         assertEquals(3, res.get(2));
-        assertEquals(2, res.get(3));
     }
 
     /**
@@ -1212,115 +1188,6 @@
     /**
      * @throws Exception If failed.
      */
-    @Ignore("https://issues.apache.org/jira/browse/IGNITE-9470")
-    @Test
-    public void testCleanupWaitsForGet2() throws Exception {
-        /*
-        Simulate case when there are two active transactions modifying the same key
-        (it is possible if key lock is released but ack message is delayed), and at this moment
-        query is started.
-         */
-        testSpi = true;
-
-        client = false;
-
-        startGrids(2);
-
-        client = true;
-
-        final Ignite client = startGrid(2);
-
-        awaitPartitionMapExchange();
-
-        final IgniteCache<Object, Object> cache = client.createCache(cacheConfiguration(PARTITIONED, FULL_SYNC, 0, 16).
-            setNodeFilter(new TestCacheNodeExcludingFilter(ignite(0).name())));
-
-        final Integer key1 = 1;
-        final Integer key2 = 2;
-
-        try (Transaction tx = client.transactions().txStart(PESSIMISTIC, REPEATABLE_READ)) {
-            cache.put(key1, 0);
-            cache.put(key2, 0);
-
-            tx.commit();
-        }
-
-        TestRecordingCommunicationSpi crdSpi = TestRecordingCommunicationSpi.spi(grid(0));
-
-        TestRecordingCommunicationSpi clientSpi = TestRecordingCommunicationSpi.spi(client);
-
-        final CountDownLatch getLatch = new CountDownLatch(1);
-
-        clientSpi.closure(new IgniteBiInClosure<ClusterNode, Message>() {
-            @Override public void apply(ClusterNode node, Message msg) {
-                if (msg instanceof MvccAckRequestTx)
-                    doSleep(2000);
-            }
-        });
-
-        crdSpi.closure(new IgniteBiInClosure<ClusterNode, Message>() {
-            /** */
-            private AtomicInteger cntr = new AtomicInteger();
-
-            @Override public void apply(ClusterNode node, Message msg) {
-                if (msg instanceof MvccSnapshotResponse) {
-                    if (cntr.incrementAndGet() == 2) {
-                        getLatch.countDown();
-
-                        doSleep(1000);
-                    }
-                }
-            }
-        });
-
-        final IgniteInternalFuture<?> putFut1 = GridTestUtils.runAsync(new Callable<Void>() {
-            @Override public Void call() throws Exception {
-                try (Transaction tx = client.transactions().txStart(PESSIMISTIC, REPEATABLE_READ)) {
-                    cache.put(key1, 1);
-
-                    tx.commit();
-                }
-
-                return null;
-            }
-        }, "put1");
-
-        final IgniteInternalFuture<?> putFut2 = GridTestUtils.runAsync(new Callable<Void>() {
-            @Override public Void call() throws Exception {
-                try (Transaction tx = client.transactions().txStart(PESSIMISTIC, REPEATABLE_READ)) {
-                    cache.put(key1, 2);
-
-                    tx.commit();
-                }
-
-                return null;
-            }
-        }, "put2");
-
-        IgniteInternalFuture<?> getFut = GridTestUtils.runMultiThreadedAsync(new Callable<Void>() {
-            @Override public Void call() throws Exception {
-                U.await(getLatch);
-
-                while (!putFut1.isDone() || !putFut2.isDone()) {
-                    Map<Object, Object> vals1 = checkAndGetAll(false, cache, F.asSet(key1, key2), SCAN);
-                    Map<Object, Object> vals2 = checkAndGetAll(false, cache, F.asSet(key1, key2), GET);
-
-                    assertEquals(2, vals1.size());
-                    assertEquals(2, vals2.size());
-                }
-
-                return null;
-            }
-        }, 4, "get-thread");
-
-        putFut1.get();
-        putFut2.get();
-        getFut.get();
-    }
-
-    /**
-     * @throws Exception If failed.
-     */
     @Test
     public void testCleanupWaitsForGet3() throws Exception {
         for (int i = 0; i < 4; i++) {
@@ -1740,7 +1607,6 @@
     /**
      * @throws Exception If failed.
      */
-    @Ignore("https://issues.apache.org/jira/browse/IGNITE-9470")
     @Test
     public void testPessimisticTxGetAllReadsSnapshot_SingleNode_SinglePartition() throws Exception {
         txReadsSnapshot(1, 0, 0, 1, GET);
@@ -1749,7 +1615,6 @@
     /**
      * @throws Exception If failed.
      */
-    @Ignore("https://issues.apache.org/jira/browse/IGNITE-9470")
     @Test
     public void testPessimisticTxGetAllReadsSnapshot_ClientServer() throws Exception {
         txReadsSnapshot(4, 2, 1, 64, GET);
@@ -1758,7 +1623,6 @@
     /**
      * @throws Exception If failed.
      */
-    @Ignore("https://issues.apache.org/jira/browse/IGNITE-9470")
     @Test
     public void testPessimisticTxScanReadsSnapshot_SingleNode_SinglePartition() throws Exception {
         txReadsSnapshot(1, 0, 0, 1, SCAN);
@@ -1767,7 +1631,6 @@
     /**
      * @throws Exception If failed.
      */
-    @Ignore("https://issues.apache.org/jira/browse/IGNITE-9470")
     @Test
     public void testPessimisticTxScanReadsSnapshot_ClientServer() throws Exception {
         txReadsSnapshot(4, 2, 1, 64, SCAN);
@@ -1863,10 +1726,7 @@
                                 tx.commit();
                             }
                             catch (CacheException ex) {
-                                if (ex.getCause() instanceof TransactionSerializationException)
-                                    continue;
-
-                                throw ex;
+                                MvccFeatureChecker.assertMvccWriteConflict(ex);
                             }
                         }
                         finally {
@@ -2216,10 +2076,8 @@
                                 tx.commit();
                             }
                             catch (Exception e) {
-                                if (e.getCause() instanceof TransactionSerializationException)
-                                    continue;
-
-                                Assert.assertTrue("Unexpected error: " + e, X.hasCause(e, ClusterTopologyException.class));
+                                if (!X.hasCause(e, ClusterTopologyException.class))
+                                    MvccFeatureChecker.assertMvccWriteConflict(e);
                             }
                         }
                         finally {
@@ -2901,7 +2759,6 @@
     /**
      * @throws Exception If failed.
      */
-    @Ignore("https://issues.apache.org/jira/browse/IGNITE-9470")
     @Test
     public void testImplicitPartsScan_SingleNode_SinglePartition() throws Exception {
         doImplicitPartsScanTest(1, 0, 0, 1, 10_000);
@@ -2910,7 +2767,6 @@
     /**
      * @throws Exception If failed.
      */
-    @Ignore("https://issues.apache.org/jira/browse/IGNITE-9470")
     @Test
     public void testImplicitPartsScan_SingleNode() throws Exception {
         doImplicitPartsScanTest(1, 0, 0, 64, 10_000);
@@ -2919,7 +2775,6 @@
     /**
      * @throws Exception If failed.
      */
-    @Ignore("https://issues.apache.org/jira/browse/IGNITE-9470")
     @Test
     public void testImplicitPartsScan_ClientServer_Backups0() throws Exception {
         doImplicitPartsScanTest(4, 2, 0, 64, 10_000);
@@ -2928,7 +2783,6 @@
     /**
      * @throws Exception If failed.
      */
-    @Ignore("https://issues.apache.org/jira/browse/IGNITE-9470")
     @Test
     public void testImplicitPartsScan_ClientServer_Backups1() throws Exception {
         doImplicitPartsScanTest(4, 2, 1, 64, 10_000);
@@ -2937,7 +2791,6 @@
     /**
      * @throws Exception If failed.
      */
-    @Ignore("https://issues.apache.org/jira/browse/IGNITE-9470")
     @Test
     public void testImplicitPartsScan_ClientServer_Backups2() throws Exception {
         doImplicitPartsScanTest(4, 2, 2, 64, 10_000);
@@ -3049,10 +2902,7 @@
                             tx.commit();
                         }
                         catch (CacheException ex) {
-                            if (ex.getCause() instanceof TransactionSerializationException)
-                                continue;
-
-                            throw ex;
+                            MvccFeatureChecker.assertMvccWriteConflict(ex);
                         }
                         finally {
                             cache.readUnlock();
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/IgnitePdsCacheStartStopWithFreqCheckpointTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/IgnitePdsCacheStartStopWithFreqCheckpointTest.java
index dc24c0b..382bb2e 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/IgnitePdsCacheStartStopWithFreqCheckpointTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/IgnitePdsCacheStartStopWithFreqCheckpointTest.java
@@ -37,6 +37,7 @@
 import org.apache.ignite.internal.IgniteInternalFuture;
 import org.apache.ignite.internal.util.typedef.internal.U;
 import org.apache.ignite.testframework.GridTestUtils;
+import org.apache.ignite.testframework.MvccFeatureChecker;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
 import org.junit.Assert;
 import org.junit.Test;
@@ -80,11 +81,17 @@
 
     /** {@inheritDoc} */
     private CacheConfiguration cacheConfiguration(int cacheIdx) {
-        return new CacheConfiguration(CACHE_NAME + cacheIdx)
+        CacheConfiguration ccfg = new CacheConfiguration(CACHE_NAME + cacheIdx)
             .setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL)
             .setCacheMode(CacheMode.REPLICATED)
-            .setBackups(0)
-            .setRebalanceMode(CacheRebalanceMode.NONE);
+            .setBackups(0);
+
+        if (MvccFeatureChecker.forcedMvcc())
+            ccfg.setRebalanceDelay(Long.MAX_VALUE);
+        else
+            ccfg.setRebalanceMode(CacheRebalanceMode.NONE);
+
+        return ccfg;
     }
 
     /** {@inheritDoc} */
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/IgnitePdsContinuousRestartTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/IgnitePdsContinuousRestartTest.java
index 8b33339..b52d03d 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/IgnitePdsContinuousRestartTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/IgnitePdsContinuousRestartTest.java
@@ -116,13 +116,6 @@
     }
 
     /** {@inheritDoc} */
-    @Override protected void beforeTest() throws Exception {
-        Assume.assumeFalse("https://issues.apache.org/jira/browse/IGNITE-10561", MvccFeatureChecker.forcedMvcc());
-
-        super.beforeTest();
-    }
-
-    /** {@inheritDoc} */
     @Override protected void afterTest() throws Exception {
         stopAllGrids();
 
@@ -230,8 +223,6 @@
      */
     @Test
     public void testRebalancingDuringLoad_10_10_1_1() throws Exception {
-        Assume.assumeFalse("https://issues.apache.org/jira/browse/IGNITE-10583", MvccFeatureChecker.forcedMvcc());
-
         checkRebalancingDuringLoad(10, 10, 1, 1);
     }
 
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/IgnitePdsDynamicCacheTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/IgnitePdsDynamicCacheTest.java
index 13936ee..993f372 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/IgnitePdsDynamicCacheTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/IgnitePdsDynamicCacheTest.java
@@ -33,6 +33,7 @@
 import org.apache.ignite.configuration.WALMode;
 import org.apache.ignite.internal.processors.database.IgniteDbDynamicCacheSelfTest;
 import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.testframework.MvccFeatureChecker;
 import org.junit.Test;
 
 /**
@@ -96,18 +97,26 @@
         ccfg1.setName("cache1");
         ccfg1.setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL);
         ccfg1.setWriteSynchronizationMode(CacheWriteSynchronizationMode.FULL_SYNC);
-        ccfg1.setRebalanceMode(CacheRebalanceMode.NONE);
         ccfg1.setAffinity(new RendezvousAffinityFunction(false, 32));
 
+        if (MvccFeatureChecker.forcedMvcc())
+            ccfg1.setRebalanceDelay(Long.MAX_VALUE);
+        else
+            ccfg1.setRebalanceMode(CacheRebalanceMode.NONE);
+
         CacheConfiguration ccfg2 = new CacheConfiguration();
 
         ccfg2.setName("cache2");
         ccfg2.setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL);
         ccfg2.setWriteSynchronizationMode(CacheWriteSynchronizationMode.FULL_SYNC);
-        ccfg2.setRebalanceMode(CacheRebalanceMode.NONE);
         ccfg2.setAffinity(new RendezvousAffinityFunction(false, 32));
         ccfg2.setIndexedTypes(Integer.class, Value.class);
 
+        if (MvccFeatureChecker.forcedMvcc())
+            ccfg2.setRebalanceDelay(Long.MAX_VALUE);
+        else
+            ccfg2.setRebalanceMode(CacheRebalanceMode.NONE);
+
         CacheConfiguration ccfg3 = new CacheConfiguration();
 
         ccfg3.setName("cache3");
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/IgnitePdsPartitionsStateRecoveryTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/IgnitePdsPartitionsStateRecoveryTest.java
index 2037a67..40c8a98 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/IgnitePdsPartitionsStateRecoveryTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/IgnitePdsPartitionsStateRecoveryTest.java
@@ -62,10 +62,15 @@
 
         CacheConfiguration ccfg = defaultCacheConfiguration()
             .setBackups(0)
-            .setRebalanceMode(CacheRebalanceMode.NONE) // Disable rebalance to prevent owning MOVING partitions.
             .setWriteSynchronizationMode(CacheWriteSynchronizationMode.FULL_SYNC)
             .setAffinity(new RendezvousAffinityFunction(false, PARTS_CNT));
 
+        // Disable rebalance to prevent owning MOVING partitions.
+        if (MvccFeatureChecker.forcedMvcc())
+            ccfg.setRebalanceDelay(Long.MAX_VALUE);
+        else
+            ccfg.setRebalanceMode(CacheRebalanceMode.NONE);
+
         cfg.setCacheConfiguration(ccfg);
 
         return cfg;
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/IgnitePdsRecoveryAfterFileCorruptionTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/IgnitePdsRecoveryAfterFileCorruptionTest.java
index 0af7629..6928cc2 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/IgnitePdsRecoveryAfterFileCorruptionTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/IgnitePdsRecoveryAfterFileCorruptionTest.java
@@ -49,6 +49,7 @@
 import org.apache.ignite.internal.processors.cache.persistence.pagemem.PageMemoryImpl;
 import org.apache.ignite.internal.processors.cache.persistence.tree.io.PageIO;
 import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.testframework.MvccFeatureChecker;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
 import org.junit.Test;
 
@@ -72,7 +73,10 @@
         CacheConfiguration ccfg = new CacheConfiguration(cacheName);
         ccfg.setAffinity(new RendezvousAffinityFunction(true, 1));
 
-        ccfg.setRebalanceMode(CacheRebalanceMode.NONE);
+        if (MvccFeatureChecker.forcedMvcc())
+            ccfg.setRebalanceDelay(Long.MAX_VALUE);
+        else
+            ccfg.setRebalanceMode(CacheRebalanceMode.NONE);
 
         ccfg.setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL);
 
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/LocalWalModeChangeDuringRebalancingSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/LocalWalModeChangeDuringRebalancingSelfTest.java
index 78940a8..fb99aa8 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/LocalWalModeChangeDuringRebalancingSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/LocalWalModeChangeDuringRebalancingSelfTest.java
@@ -22,6 +22,8 @@
 import java.nio.ByteBuffer;
 import java.nio.MappedByteBuffer;
 import java.nio.file.OpenOption;
+import java.util.Set;
+import java.util.TreeSet;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.ThreadLocalRandom;
 import java.util.concurrent.atomic.AtomicReference;
@@ -570,7 +572,14 @@
         cache = newIgnite.cache(DEFAULT_CACHE_NAME);
 
         for (int k = 0; k < keysCnt; k++)
-            assertFalse("k=" + k +", v=" + cache.get(k), cache.containsKey(k));
+            assertFalse("k=" + k +", v="  + cache.get(k), cache.containsKey(k));
+
+        Set<Integer> keys = new TreeSet<>();
+
+        for (int k = 0; k < keysCnt; k++)
+            keys.add(k);
+
+        assertFalse(cache.containsKeys(keys));
     }
 
     /**
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/baseline/ClientAffinityAssignmentWithBaselineTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/baseline/ClientAffinityAssignmentWithBaselineTest.java
index f081aac..7788193 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/baseline/ClientAffinityAssignmentWithBaselineTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/baseline/ClientAffinityAssignmentWithBaselineTest.java
@@ -46,15 +46,16 @@
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.internal.IgniteEx;
 import org.apache.ignite.internal.IgniteNodeAttributes;
+import org.apache.ignite.internal.util.typedef.X;
 import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.lang.IgniteFuture;
 import org.apache.ignite.lang.IgnitePredicate;
 import org.apache.ignite.testframework.GridTestUtils;
-import org.apache.ignite.testframework.MvccFeatureChecker;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
 import org.apache.ignite.transactions.Transaction;
 import org.apache.ignite.transactions.TransactionConcurrency;
 import org.apache.ignite.transactions.TransactionIsolation;
-import org.junit.Assume;
+import org.junit.Ignore;
 import org.junit.Test;
 
 import static org.apache.ignite.IgniteSystemProperties.IGNITE_BASELINE_AUTO_ADJUST_ENABLED;
@@ -174,8 +175,6 @@
 
     /** {@inheritDoc} */
     @Override protected void beforeTest() throws Exception {
-        Assume.assumeFalse("https://issues.apache.org/jira/browse/IGNITE-10261", MvccFeatureChecker.forcedMvcc());
-
         stopAllGrids();
 
         cleanPersistenceDir();
@@ -554,10 +553,9 @@
      * Tests that if dynamic cache has no affinity nodes at the moment of start,
      * it will still work correctly when affinity nodes will appear.
      */
+    @Ignore("https://issues.apache.org/jira/browse/IGNITE-8652")
     @Test
     public void testDynamicCacheStartNoAffinityNodes() throws Exception {
-        fail("IGNITE-8652");
-
         IgniteEx ig0 = startGrid(0);
 
         ig0.cluster().active(true);
@@ -850,8 +848,12 @@
                                 (tId, ops) -> ops == null ? 1 : ops + 1);
                         }
                         catch (CacheException e) {
-                            if (e.getCause() instanceof ClusterTopologyException)
-                                ((ClusterTopologyException)e.getCause()).retryReadyFuture().get();
+                            if (e.getCause() instanceof ClusterTopologyException) {
+                                IgniteFuture retryFut = ((ClusterTopologyException)e.getCause()).retryReadyFuture();
+
+                                if (retryFut != null)
+                                    retryFut.get();
+                            }
                         }
                         catch (ClusterTopologyException e) {
                             e.retryReadyFuture().get();
@@ -961,11 +963,10 @@
         while (U.currentTimeMillis() < startTs + waitMs) {
             Map<Long, Long> view2 = new HashMap<>(threadProgressTracker);
 
-            if (loadError.get() != null) {
-                loadError.get().printStackTrace();
+            Throwable t;
 
-                fail("Unexpected error in load thread: " + loadError.get().toString());
-            }
+            if ((t = loadError.get()) != null)
+                fail("Unexpected error in load thread: " + X.getFullStackTrace(t));
 
             boolean frozenThreadExists = false;
 
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/checkpoint/CheckpointFreeListTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/checkpoint/CheckpointFreeListTest.java
index c5cbb5d..655a687 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/checkpoint/CheckpointFreeListTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/checkpoint/CheckpointFreeListTest.java
@@ -29,9 +29,11 @@
 import java.util.Objects;
 import java.util.Optional;
 import java.util.Random;
+import java.util.concurrent.BrokenBarrierException;
 import java.util.concurrent.ConcurrentLinkedQueue;
 import java.util.concurrent.CyclicBarrier;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
 import java.util.concurrent.atomic.AtomicReferenceArray;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
@@ -303,7 +305,7 @@
         GridTestUtils.runAsync(() -> {
             while (true) {
                 try {
-                    nodeStartBarrier.await(20000, TimeUnit.MILLISECONDS);
+                    nodeStartBarrier.await(10000, TimeUnit.MILLISECONDS);
 
                     Ignite ignite = ignite(0);
 
@@ -319,6 +321,9 @@
                         iter.remove();
                     }
                 }
+                catch (TimeoutException | InterruptedException | BrokenBarrierException e) {
+                    return;
+                }
                 catch (Exception e) {
                     if (Thread.currentThread().isInterrupted())
                         return;
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/file/IgnitePdsCheckpointSimulationWithRealCpDisabledTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/file/IgnitePdsCheckpointSimulationWithRealCpDisabledTest.java
index b4ec7e9..b9e819c 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/file/IgnitePdsCheckpointSimulationWithRealCpDisabledTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/file/IgnitePdsCheckpointSimulationWithRealCpDisabledTest.java
@@ -110,7 +110,7 @@
 
         CacheConfiguration mvccCfg =  new CacheConfiguration(MVCC_CACHE_NAME)
                 .setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL_SNAPSHOT)
-                .setRebalanceMode(CacheRebalanceMode.NONE);
+                .setRebalanceDelay(Long.MAX_VALUE);
 
         cfg.setCacheConfiguration(ccfg, mvccCfg);
 
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/query/continuous/CacheContinuousQueryOperationFromCallbackTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/query/continuous/CacheContinuousQueryOperationFromCallbackTest.java
index a3f822d..5b3565f 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/query/continuous/CacheContinuousQueryOperationFromCallbackTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/query/continuous/CacheContinuousQueryOperationFromCallbackTest.java
@@ -56,15 +56,19 @@
 import org.apache.ignite.testframework.GridTestUtils;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
 import org.apache.ignite.transactions.Transaction;
+import org.apache.ignite.transactions.TransactionSerializationException;
 import org.jetbrains.annotations.Nullable;
 import org.junit.Test;
 
 import static org.apache.ignite.cache.CacheAtomicityMode.ATOMIC;
 import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL;
+import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL_SNAPSHOT;
 import static org.apache.ignite.cache.CacheMode.PARTITIONED;
 import static org.apache.ignite.cache.CacheMode.REPLICATED;
 import static org.apache.ignite.cache.CacheWriteSynchronizationMode.FULL_SYNC;
 import static org.apache.ignite.cache.CacheWriteSynchronizationMode.PRIMARY_SYNC;
+import static org.apache.ignite.transactions.TransactionConcurrency.PESSIMISTIC;
+import static org.apache.ignite.transactions.TransactionIsolation.REPEATABLE_READ;
 
 /**
  *
@@ -77,6 +81,9 @@
     public static final int KEYS_FROM_CALLBACK = 20;
 
     /** */
+    public static final int KEYS_FROM_CALLBACK_RANGE = 10_000;
+
+    /** */
     private static final int NODES = 5;
 
     /** */
@@ -238,9 +245,100 @@
     }
 
     /**
+     * @throws Exception If failed.
+     */
+    @Test
+    public void testMvccTxTwoBackupsFilter() throws Exception {
+        CacheConfiguration<Object, Object> ccfg = cacheConfiguration(PARTITIONED, 2, TRANSACTIONAL_SNAPSHOT, FULL_SYNC);
+
+        doTest(ccfg, false);
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    @Test
+    public void testMvccTxTwoBackupsFilterPrimary() throws Exception {
+        CacheConfiguration<Object, Object> ccfg = cacheConfiguration(PARTITIONED, 2, TRANSACTIONAL_SNAPSHOT, PRIMARY_SYNC);
+
+        doTest(ccfg, false);
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    @Test
+    public void testMvccTxReplicatedFilter() throws Exception {
+        CacheConfiguration<Object, Object> ccfg = cacheConfiguration(REPLICATED, 0, TRANSACTIONAL_SNAPSHOT, FULL_SYNC);
+
+        doTest(ccfg, false);
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    @Test
+    public void testMvccTxTwoBackup() throws Exception {
+        CacheConfiguration<Object, Object> ccfg = cacheConfiguration(PARTITIONED, 2, TRANSACTIONAL_SNAPSHOT, FULL_SYNC);
+
+        doTest(ccfg, true);
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    @Test
+    public void testMvccTxReplicated() throws Exception {
+        CacheConfiguration<Object, Object> ccfg = cacheConfiguration(REPLICATED, 2, TRANSACTIONAL_SNAPSHOT, FULL_SYNC);
+
+        doTest(ccfg, true);
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    @Test
+    public void testMvccTxReplicatedPrimary() throws Exception {
+        CacheConfiguration<Object, Object> ccfg = cacheConfiguration(REPLICATED, 2, TRANSACTIONAL_SNAPSHOT, PRIMARY_SYNC);
+
+        doTest(ccfg, true);
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    @Test
+    public void testMvccTxOneBackupFilter() throws Exception {
+        CacheConfiguration<Object, Object> ccfg = cacheConfiguration(PARTITIONED, 1, TRANSACTIONAL_SNAPSHOT, FULL_SYNC);
+
+        doTest(ccfg, false);
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    @Test
+    public void testMvccTxOneBackupFilterPrimary() throws Exception {
+        CacheConfiguration<Object, Object> ccfg = cacheConfiguration(PARTITIONED, 1, TRANSACTIONAL_SNAPSHOT, PRIMARY_SYNC);
+
+        doTest(ccfg, false);
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    @Test
+    public void testMvccTxOneBackup() throws Exception {
+        CacheConfiguration<Object, Object> ccfg = cacheConfiguration(PARTITIONED, 1, TRANSACTIONAL_SNAPSHOT, FULL_SYNC);
+
+        doTest(ccfg, true);
+    }
+
+    /**
      * @param ccfg Cache configuration.
      * @throws Exception If failed.
      */
+    @SuppressWarnings({"TypeMayBeWeakened", "unchecked", "TooBroadScope"})
     protected void doTest(final CacheConfiguration ccfg, boolean fromLsnr) throws Exception {
         ignite(0).createCache(ccfg);
 
@@ -291,35 +389,48 @@
                         IgniteCache<QueryTestKey, QueryTestValue> cache =
                             grid(rnd.nextInt(NODES)).cache(ccfg.getName());
 
-                        QueryTestKey key = new QueryTestKey(rnd.nextInt(KEYS));
+                        QueryTestKey key = new QueryTestKey(rnd.nextInt(KEYS) - KEYS);
 
-                        boolean startTx = cache.getConfiguration(CacheConfiguration.class).getAtomicityMode() ==
-                            TRANSACTIONAL && rnd.nextBoolean();
+                        boolean startTx = cache.getConfiguration(CacheConfiguration.class).getAtomicityMode() !=
+                            ATOMIC && rnd.nextBoolean();
 
                         Transaction tx = null;
 
-                        if (startTx)
-                            tx = cache.unwrap(Ignite.class).transactions().txStart();
+                        boolean committed = false;
 
-                        try {
-                            if ((cache.get(key) == null) || rnd.nextBoolean())
-                                cache.invoke(key, new IncrementTestEntryProcessor());
-                            else {
-                                QueryTestValue val;
-                                QueryTestValue newVal;
+                        while (!committed && !Thread.currentThread().isInterrupted()) {
+                            try {
+                                if (startTx)
+                                    tx = cache.unwrap(Ignite.class).transactions().txStart(PESSIMISTIC, REPEATABLE_READ);
 
-                                do {
-                                    val = cache.get(key);
+                                if ((cache.get(key) == null) || rnd.nextBoolean())
+                                    cache.invoke(key, new IncrementTestEntryProcessor());
+                                else {
+                                    QueryTestValue val;
+                                    QueryTestValue newVal;
 
-                                    newVal = val == null ?
-                                        new QueryTestValue(0) : new QueryTestValue(val.val1 + 1);
+                                    do {
+                                        val = cache.get(key);
+
+                                        newVal = val == null ?
+                                            new QueryTestValue(0) : new QueryTestValue(val.val1 + 1);
+                                    }
+                                    while (!cache.replace(key, val, newVal));
                                 }
-                                while (!cache.replace(key, val, newVal));
+
+                                if (tx != null)
+                                    tx.commit();
+
+                                committed = true;
                             }
-                        }
-                        finally {
-                            if (tx != null)
-                                tx.commit();
+                            catch (Exception e) {
+                                assertTrue(e.getCause() instanceof TransactionSerializationException);
+                                assertEquals(ccfg.getAtomicityMode(), TRANSACTIONAL_SNAPSHOT);
+                            }
+                            finally {
+                                if (tx != null)
+                                    tx.close();
+                            }
                         }
                     }
                 }
@@ -331,7 +442,7 @@
                 @Override public boolean apply() {
                     return qryCntr.get() >= ITERATION_CNT * threadCnt * NODES;
                 }
-            }, TimeUnit.MINUTES.toMillis(2));
+            }, getTestTimeout());
 
             for (Set<T2<QueryTestKey, QueryTestValue>> set : rcvdEvts)
                 checkEvents(set, ITERATION_CNT * threadCnt, grid(0).cache(ccfg.getName()), false);
@@ -343,7 +454,7 @@
                     @Override public boolean apply() {
                         return cbCntr.get() >= expCnt;
                     }
-                }, TimeUnit.SECONDS.toMillis(60));
+                }, getTestTimeout());
 
                 assertTrue("Failed to wait events [exp=" + expCnt + ", act=" + cbCntr.get() + "]", res);
 
@@ -360,7 +471,7 @@
                     @Override public boolean apply() {
                         return filterCbCntr.get() >= expInvkCnt;
                     }
-                }, TimeUnit.SECONDS.toMillis(60));
+                }, getTestTimeout());
 
                 assertEquals(expInvkCnt, filterCbCntr.get());
 
@@ -388,21 +499,39 @@
             @Override public boolean apply() {
                 return set.size() >= expCnt;
             }
-        }, 10000L));
+        }, getTestTimeout()));
 
-        int startKey = cb ? KEYS : 0;
-        int endKey = cb ? KEYS + KEYS_FROM_CALLBACK : KEYS;
+        final int setSize = set.size();
 
-        for (int i = startKey; i < endKey; i++) {
-            QueryTestKey key = new QueryTestKey(i);
+        if (cb) {
+            int cntr = 0;
 
-            QueryTestValue maxVal = (QueryTestValue)cache.get(key);
+            while (!set.isEmpty()) {
+                T2<QueryTestKey, QueryTestValue> t = set.iterator().next();
 
-            for (int val = 0; val <= maxVal.val1; val++)
-                assertTrue(set.remove(new T2<>(key, new QueryTestValue(val))));
+                QueryTestKey key = t.getKey();
+
+                QueryTestValue maxVal = (QueryTestValue)cache.get(key);
+
+                for (int val = 0; val <= maxVal.val1; val++)
+                    assertTrue(set.remove(new T2<>(key, new QueryTestValue(val))));
+
+                if (cntr++ > setSize)
+                    fail();
+            }
         }
+        else {
+            for (int i = -KEYS; i < 0; i++) {
+                QueryTestKey key = new QueryTestKey(i);
 
-        assertTrue(set.isEmpty());
+                QueryTestValue maxVal = (QueryTestValue)cache.get(key);
+
+                for (int val = 0; val <= maxVal.val1; val++)
+                    assertTrue(set.remove(new T2<>(key, new QueryTestValue(val))));
+            }
+
+            assertTrue(set.isEmpty());
+        }
     }
 
     /**
@@ -445,20 +574,46 @@
         /** {@inheritDoc} */
         @Override public boolean evaluate(CacheEntryEvent<? extends QueryTestKey, ? extends QueryTestValue> e)
             throws CacheEntryListenerException {
-            if (e.getKey().compareTo(new QueryTestKey(KEYS)) < 0) {
+            if (e.getKey().key() < 0) {
                 IgniteCache<QueryTestKey, QueryTestValue> cache = ignite.cache(cacheName);
 
-                if (ThreadLocalRandom.current().nextBoolean()) {
-                    Set<QueryTestKey> keys = new LinkedHashSet<>();
+                boolean committed = false;
+                Transaction tx = null;
+                boolean startTx = cache.getConfiguration(CacheConfiguration.class).getAtomicityMode() != ATOMIC;
 
-                    for (int key = KEYS; key < KEYS + KEYS_FROM_CALLBACK; key++)
-                        keys.add(new QueryTestKey(key));
+                Set<QueryTestKey> keys = new LinkedHashSet<>();
 
-                    cache.invokeAll(keys, new IncrementTestEntryProcessor());
-                }
-                else {
-                    for (int key = KEYS; key < KEYS + KEYS_FROM_CALLBACK; key++)
-                        cache.invoke(new QueryTestKey(key), new IncrementTestEntryProcessor());
+                int startKey = ThreadLocalRandom.current().nextInt(KEYS_FROM_CALLBACK_RANGE - KEYS_FROM_CALLBACK);
+
+                for (int key = startKey; key < startKey + KEYS_FROM_CALLBACK; key++)
+                    keys.add(new QueryTestKey(key));
+
+                while (!committed && !Thread.currentThread().isInterrupted()) {
+                    try {
+                        if (startTx)
+                            tx = ignite.transactions().txStart(PESSIMISTIC, REPEATABLE_READ);
+
+                        if (ThreadLocalRandom.current().nextBoolean())
+                            cache.invokeAll(keys, new IncrementTestEntryProcessor());
+                        else {
+                            for (QueryTestKey key : keys)
+                                cache.invoke(key, new IncrementTestEntryProcessor());
+                        }
+
+                        if (tx != null)
+                            tx.commit();
+
+                        committed = true;
+                    }
+                    catch (Exception ex) {
+                        assertTrue(ex.getCause() instanceof TransactionSerializationException);
+                        assertEquals(cache.getConfiguration(CacheConfiguration.class).getAtomicityMode(),
+                            TRANSACTIONAL_SNAPSHOT);
+                    }
+                    finally {
+                        if (tx != null)
+                            tx.close();
+                    }
                 }
 
                 filterCbCntr.incrementAndGet();
@@ -512,23 +667,49 @@
         @Override public void onUpdated(Iterable<CacheEntryEvent<? extends QueryTestKey, ? extends QueryTestValue>> evts)
             throws CacheEntryListenerException {
             for (CacheEntryEvent<? extends QueryTestKey, ? extends QueryTestValue> e : evts) {
-                if (e.getKey().compareTo(new QueryTestKey(KEYS)) < 0) {
+                if (e.getKey().key() < 0) {
                     rcvsEvts.add(new T2<>(e.getKey(), e.getValue()));
 
                     cntr.incrementAndGet();
 
                     if (cache != null) {
-                        if (ThreadLocalRandom.current().nextBoolean()) {
-                            Set<QueryTestKey> keys = new LinkedHashSet<>();
+                        boolean committed = false;
+                        Transaction tx = null;
+                        boolean startTx = cache.getConfiguration(CacheConfiguration.class).getAtomicityMode() != ATOMIC;
 
-                            for (int key = KEYS; key < KEYS + KEYS_FROM_CALLBACK; key++)
-                                keys.add(new QueryTestKey(key));
+                        Set<QueryTestKey> keys = new LinkedHashSet<>();
 
-                            cache.invokeAll(keys, new IncrementTestEntryProcessor());
-                        }
-                        else {
-                            for (int key = KEYS; key < KEYS + KEYS_FROM_CALLBACK; key++)
-                                cache.invoke(new QueryTestKey(key), new IncrementTestEntryProcessor());
+                        int startKey = ThreadLocalRandom.current().nextInt(KEYS_FROM_CALLBACK_RANGE - KEYS_FROM_CALLBACK);
+
+                        for (int key = startKey; key < startKey + KEYS_FROM_CALLBACK; key++)
+                            keys.add(new QueryTestKey(key));
+
+                        while (!committed && !Thread.currentThread().isInterrupted()) {
+                            try {
+                                if (startTx)
+                                    tx = cache.unwrap(Ignite.class).transactions().txStart(PESSIMISTIC, REPEATABLE_READ);
+
+                                if (ThreadLocalRandom.current().nextBoolean())
+                                    cache.invokeAll(keys, new IncrementTestEntryProcessor());
+                                else {
+                                    for (QueryTestKey key : keys)
+                                        cache.invoke(key, new IncrementTestEntryProcessor());
+                                }
+
+                                if (tx != null)
+                                    tx.commit();
+
+                                committed = true;
+                            }
+                            catch (Exception ex) {
+                                assertTrue(ex.getCause() instanceof TransactionSerializationException);
+                                assertEquals(cache.getConfiguration(CacheConfiguration.class).getAtomicityMode(),
+                                    TRANSACTIONAL_SNAPSHOT);
+                            }
+                            finally {
+                                if (tx != null)
+                                    tx.close();
+                            }
                         }
                     }
                 }
@@ -580,6 +761,13 @@
             this.key = key;
         }
 
+        /**
+         * @return Key.
+         */
+        public Integer key() {
+            return key;
+        }
+
         /** {@inheritDoc} */
         @Override public boolean equals(Object o) {
             if (this == o)
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/query/continuous/CacheContinuousQueryOrderingEventTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/query/continuous/CacheContinuousQueryOrderingEventTest.java
index 7b2e605..95f99f8 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/query/continuous/CacheContinuousQueryOrderingEventTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/query/continuous/CacheContinuousQueryOrderingEventTest.java
@@ -32,6 +32,7 @@
 import javax.cache.CacheException;
 import javax.cache.configuration.FactoryBuilder;
 import javax.cache.event.CacheEntryEvent;
+import javax.cache.event.CacheEntryListenerException;
 import javax.cache.event.CacheEntryUpdatedListener;
 import javax.cache.processor.EntryProcessorException;
 import javax.cache.processor.MutableEntry;
@@ -47,9 +48,11 @@
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.internal.IgniteInternalFuture;
+import org.apache.ignite.internal.IgniteInterruptedCheckedException;
 import org.apache.ignite.internal.util.tostring.GridToStringInclude;
 import org.apache.ignite.internal.util.typedef.PA;
 import org.apache.ignite.internal.util.typedef.internal.S;
+import org.apache.ignite.internal.util.typedef.internal.U;
 import org.apache.ignite.lang.IgniteAsyncCallback;
 import org.apache.ignite.resources.IgniteInstanceResource;
 import org.apache.ignite.spi.communication.tcp.TcpCommunicationSpi;
@@ -196,6 +199,16 @@
         doOrderingTest(ccfg, false);
     }
 
+    /**
+     * @throws Exception If failed.
+     */
+    @Test
+    public void testAtomicOnheapWithoutBackup() throws Exception {
+        CacheConfiguration<Object, Object> ccfg = cacheConfiguration(PARTITIONED, 0, ATOMIC, PRIMARY_SYNC);
+
+        doOrderingTest(ccfg, false);
+    }
+
     // ASYNC
 
     /**
@@ -544,7 +557,7 @@
          */
         public TestCacheAsyncEventListener(BlockingQueue<CacheEntryEvent<QueryTestKey, QueryTestValue>> queue,
             AtomicInteger cntr) {
-            super(queue, cntr);
+            super(queue, cntr, false);
         }
     }
 
@@ -558,19 +571,42 @@
         /** */
         private final AtomicInteger cntr;
 
+        /** */
+        private final boolean delayOp;
+
         /**
          * @param queue Queue.
          * @param cntr Received events counter.
          */
         public TestCacheEventListener(BlockingQueue<CacheEntryEvent<QueryTestKey, QueryTestValue>> queue,
             AtomicInteger cntr) {
+            this(queue, cntr, true);
+        }
+
+        /**
+         * @param queue Queue.
+         * @param cntr Received events counter.
+         * @param delayOp Delay operation to ensure verification of the serialization of notifications.
+         */
+        public TestCacheEventListener(BlockingQueue<CacheEntryEvent<QueryTestKey, QueryTestValue>> queue,
+            AtomicInteger cntr, boolean delayOp) {
             this.queue = queue;
             this.cntr = cntr;
+            this.delayOp = delayOp;
         }
 
         /** {@inheritDoc} */
         @Override public void onUpdated(Iterable<CacheEntryEvent<? extends QueryTestKey,
             ? extends QueryTestValue>> evts) {
+            if (delayOp && ThreadLocalRandom.current().nextInt(5) == 1) {
+                try {
+                    U.sleep(10);
+                }
+                catch (IgniteInterruptedCheckedException ex) {
+                    throw new CacheEntryListenerException(ex);
+                }
+            }
+
             for (CacheEntryEvent<? extends QueryTestKey, ? extends QueryTestValue> e : evts) {
                 queue.add((CacheEntryEvent<QueryTestKey, QueryTestValue>)e);
 
@@ -696,3 +732,4 @@
         }
     }
 }
+
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/query/continuous/CacheKeepBinaryIterationTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/query/continuous/CacheKeepBinaryIterationTest.java
index ffec514..8c97915 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/query/continuous/CacheKeepBinaryIterationTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/query/continuous/CacheKeepBinaryIterationTest.java
@@ -28,11 +28,9 @@
 import org.apache.ignite.cache.query.ScanQuery;
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
-import org.apache.ignite.internal.binary.BinaryMarshaller;
 import org.apache.ignite.internal.util.tostring.GridToStringInclude;
 import org.apache.ignite.internal.util.typedef.internal.S;
 import org.apache.ignite.spi.communication.tcp.TcpCommunicationSpi;
-import org.apache.ignite.testframework.config.GridTestProperties;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
 import org.junit.Test;
 
@@ -52,10 +50,6 @@
     /** */
     private static final int KEYS = 1025;
 
-    static {
-        GridTestProperties.setProperty(GridTestProperties.MARSH_CLASS_NAME, BinaryMarshaller.class.getName());
-    }
-
     /** {@inheritDoc} */
     @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception {
         IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName);
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/query/continuous/IgniteCacheContinuousQueryBackupQueueTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/query/continuous/IgniteCacheContinuousQueryBackupQueueTest.java
index 34273b6..090291d 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/query/continuous/IgniteCacheContinuousQueryBackupQueueTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/query/continuous/IgniteCacheContinuousQueryBackupQueueTest.java
@@ -169,8 +169,11 @@
 
         int size = backupQueueSize();
 
-        assertTrue(size > 0);
-        assertTrue(size <= BACKUP_ACK_THRESHOLD * QUERY_COUNT * /* partition count */1024);
+        // Backup queues total size should not exceed one entry per query per partition. This is because
+        // {@link CacheContinuousQueryEventBuffer} is optimized to store filtered events and
+        // used in this test {@link AlwaysFalseFilterFactory} always declines updates.
+        // Zero total size is possible when backup queue is cleaned by timeout.
+        assertTrue(size <= QUERY_COUNT * /* partition count */1024);
 
         for (QueryCursor qry : qryCursors)
             qry.close();
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxRollbackAsyncTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxRollbackAsyncTest.java
index f5401a0..25ed33b 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxRollbackAsyncTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxRollbackAsyncTest.java
@@ -537,8 +537,6 @@
      */
     @Test
     public void testRollbackDelayNearLockRequest() throws Exception {
-        Assume.assumeFalse("https://issues.apache.org/jira/browse/IGNITE-9470", MvccFeatureChecker.forcedMvcc());
-
         final Ignite client = startClient();
 
         final Ignite prim = primaryNode(0, CACHE_NAME);
@@ -567,7 +565,7 @@
             fail();
         }
         catch (CacheException e) {
-            assertTrue(X.getFullStackTrace(e),X.hasCause(e, TransactionRollbackException.class));
+            assertTrue(X.getFullStackTrace(e), X.hasCause(e, TransactionRollbackException.class));
         }
 
         rollbackFut.get();
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cluster/BaselineConfigurationMXBeanTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cluster/BaselineConfigurationMXBeanTest.java
new file mode 100644
index 0000000..ed3b617
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cluster/BaselineConfigurationMXBeanTest.java
@@ -0,0 +1,84 @@
+/*
+ * 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.cluster;
+
+import java.lang.management.ManagementFactory;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerInvocationHandler;
+import javax.management.ObjectName;
+import org.apache.ignite.Ignite;
+import org.apache.ignite.IgniteCluster;
+import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.mxbean.BaselineConfigurationMXBean;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+import org.junit.Test;
+
+/** */
+public class BaselineConfigurationMXBeanTest extends GridCommonAbstractTest {
+    /** */
+    @Test
+    public void testTimeoutAndEnabledFlag() throws Exception {
+        Ignite ignite = startGrid();
+
+        try {
+            IgniteCluster cluster = ignite.cluster();
+
+            BaselineConfigurationMXBean bltMxBean = bltMxBean();
+
+            assertTrue(cluster.isBaselineAutoAdjustEnabled());
+            assertTrue(bltMxBean.isAutoAdjustmentEnabled());
+
+            assertEquals(0L, cluster.baselineAutoAdjustTimeout());
+            assertEquals(0L, bltMxBean.getAutoAdjustmentTimeout());
+
+            cluster.baselineAutoAdjustEnabled(false);
+            assertFalse(bltMxBean.isAutoAdjustmentEnabled());
+
+            cluster.baselineAutoAdjustTimeout(30_000L);
+            assertEquals(30_000L, bltMxBean.getAutoAdjustmentTimeout());
+
+            bltMxBean.setAutoAdjustmentEnabled(true);
+            assertTrue(cluster.isBaselineAutoAdjustEnabled());
+
+            bltMxBean.setAutoAdjustmentEnabled(false);
+            assertFalse(cluster.isBaselineAutoAdjustEnabled());
+
+            bltMxBean.setAutoAdjustmentTimeout(60_000L);
+            assertEquals(60_000L, cluster.baselineAutoAdjustTimeout());
+        }
+        finally {
+            stopGrid();
+        }
+    }
+
+    /**
+     *
+     */
+    private BaselineConfigurationMXBean bltMxBean() throws Exception {
+        ObjectName mBeanName = U.makeMBeanName(getTestIgniteInstanceName(), "Baseline",
+            BaselineConfigurationMXBeanImpl.class.getSimpleName());
+
+        MBeanServer mBeanSrv = ManagementFactory.getPlatformMBeanServer();
+
+        assertTrue(mBeanSrv.isRegistered(mBeanName));
+
+        Class<BaselineConfigurationMXBean> itfCls = BaselineConfigurationMXBean.class;
+
+        return MBeanServerInvocationHandler.newProxyInstance(mBeanSrv, mBeanName, itfCls, true);
+    }
+}
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cluster/ChangeTopologyWatcherTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cluster/ChangeTopologyWatcherTest.java
index 1b97edf..89fe806 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cluster/ChangeTopologyWatcherTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cluster/ChangeTopologyWatcherTest.java
@@ -98,7 +98,7 @@
 
         ignite0.cluster().active(true);
 
-        ignite0.cluster().baselineConfiguration().updateBaselineAutoAdjustTimeoutAsync(AUTO_ADJUST_TIMEOUT).get();
+        ignite0.cluster().baselineAutoAdjustTimeout(AUTO_ADJUST_TIMEOUT);
 
         Set<Object> initBaseline = ignite0.cluster().currentBaselineTopology().stream()
             .map(BaselineNode::consistentId)
@@ -127,7 +127,7 @@
 
         ignite0.cluster().active(true);
 
-        ignite0.cluster().baselineConfiguration().updateBaselineAutoAdjustTimeoutAsync(AUTO_ADJUST_TIMEOUT).get();
+        ignite0.cluster().baselineAutoAdjustTimeout(AUTO_ADJUST_TIMEOUT);
 
         Set<Object> initBaseline = ignite0.cluster().currentBaselineTopology().stream()
             .map(BaselineNode::consistentId)
@@ -162,7 +162,7 @@
 
         ignite0.cluster().active(true);
 
-        ignite0.cluster().baselineConfiguration().updateBaselineAutoAdjustTimeoutAsync(AUTO_ADJUST_TIMEOUT).get();
+        ignite0.cluster().baselineAutoAdjustTimeout(AUTO_ADJUST_TIMEOUT);
 
         Set<Object> initBaseline = ignite0.cluster().currentBaselineTopology().stream()
             .map(BaselineNode::consistentId)
@@ -199,7 +199,7 @@
 
         ignite0.cluster().active(true);
 
-        ignite0.cluster().baselineConfiguration().updateBaselineAutoAdjustTimeoutAsync(AUTO_ADJUST_TIMEOUT).get();
+        ignite0.cluster().baselineAutoAdjustTimeout(AUTO_ADJUST_TIMEOUT);
 
         assertTrue(isCurrentBaselineFromOneNode(ignite0));
 
@@ -238,7 +238,7 @@
             .map(BaselineNode::consistentId)
             .collect(Collectors.toSet());
 
-        ignite0.cluster().baselineConfiguration().updateBaselineAutoAdjustTimeoutAsync(AUTO_ADJUST_TIMEOUT).get();
+        ignite0.cluster().baselineAutoAdjustTimeout(AUTO_ADJUST_TIMEOUT);
 
         IgniteCache<Object, Object> cache = ignite0.getOrCreateCache(new CacheConfiguration<>(TEST_NAME)
             .setBackups(0)
@@ -268,7 +268,7 @@
 
         ignite0.cluster().active(true);
 
-        ignite0.cluster().baselineConfiguration().updateBaselineAutoAdjustTimeoutAsync(AUTO_ADJUST_TIMEOUT).get();
+        ignite0.cluster().baselineAutoAdjustTimeout(AUTO_ADJUST_TIMEOUT);
 
         Collection<BaselineNode> baselineNodes = ignite0.cluster().currentBaselineTopology();
 
@@ -290,9 +290,9 @@
 
         ignite0.cluster().active(true);
 
-        ignite0.cluster().baselineConfiguration().updateBaselineAutoAdjustTimeoutAsync(AUTO_ADJUST_TIMEOUT).get();
+        ignite0.cluster().baselineAutoAdjustTimeout(AUTO_ADJUST_TIMEOUT);
 
-        assertTrue(ignite0.cluster().baselineConfiguration().isBaselineAutoAdjustEnabled());
+        assertTrue(ignite0.cluster().isBaselineAutoAdjustEnabled());
 
         Set<Object> baselineNodes = ignite0.cluster().currentBaselineTopology().stream()
             .map(BaselineNode::consistentId)
@@ -331,9 +331,9 @@
 
         ignite0.cluster().active(true);
 
-        ignite0.cluster().baselineConfiguration().updateBaselineAutoAdjustTimeoutAsync(AUTO_ADJUST_TIMEOUT).get();
+        ignite0.cluster().baselineAutoAdjustTimeout(AUTO_ADJUST_TIMEOUT);
 
-        assertTrue(ignite0.cluster().baselineConfiguration().isBaselineAutoAdjustEnabled());
+        assertTrue(ignite0.cluster().isBaselineAutoAdjustEnabled());
 
         stopGrid(1);
 
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/database/IgniteDbDynamicCacheSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/database/IgniteDbDynamicCacheSelfTest.java
index 1f09cb2..b418dd2 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/database/IgniteDbDynamicCacheSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/database/IgniteDbDynamicCacheSelfTest.java
@@ -29,6 +29,7 @@
 import org.apache.ignite.configuration.DataStorageConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.testframework.MvccFeatureChecker;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
 import org.junit.Test;
 
@@ -95,9 +96,13 @@
         ccfg.setName("cache1");
         ccfg.setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL);
         ccfg.setWriteSynchronizationMode(CacheWriteSynchronizationMode.FULL_SYNC);
-        ccfg.setRebalanceMode(CacheRebalanceMode.NONE);
         ccfg.setAffinity(new RendezvousAffinityFunction(false, 32));
 
+        if (MvccFeatureChecker.forcedMvcc())
+            ccfg.setRebalanceDelay(Long.MAX_VALUE);
+        else
+            ccfg.setRebalanceMode(CacheRebalanceMode.NONE);
+
         for (int k = 0; k < iterations; k++) {
             System.out.println("Iteration: " + k);
 
@@ -130,9 +135,13 @@
 
         ccfg.setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL);
         ccfg.setWriteSynchronizationMode(CacheWriteSynchronizationMode.FULL_SYNC);
-        ccfg.setRebalanceMode(CacheRebalanceMode.NONE);
         ccfg.setAffinity(new RendezvousAffinityFunction(false, 32));
 
+        if (MvccFeatureChecker.forcedMvcc())
+            ccfg.setRebalanceDelay(Long.MAX_VALUE);
+        else
+            ccfg.setRebalanceMode(CacheRebalanceMode.NONE);
+
         ccfg.setIndexedTypes(Integer.class, String.class);
 
         long finishTime = U.currentTimeMillis() + 20_000;
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/service/ServiceHotRedeploymentViaDeploymentSpiTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/service/ServiceHotRedeploymentViaDeploymentSpiTest.java
new file mode 100644
index 0000000..c14f0bb
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/service/ServiceHotRedeploymentViaDeploymentSpiTest.java
@@ -0,0 +1,161 @@
+/*
+ * 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.service;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import javax.tools.JavaCompiler;
+import javax.tools.ToolProvider;
+import org.apache.ignite.Ignite;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.services.Service;
+import org.apache.ignite.spi.deployment.DeploymentSpi;
+import org.apache.ignite.spi.deployment.local.LocalDeploymentSpi;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+import org.junit.After;
+import org.junit.Assume;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * Tests services hot redeployment via {@link DeploymentSpi}.
+ *
+ * <b>NOTE:</b> to run test via Maven Surefire Plugin, the property "forkCount' should be set great than '0' or profile
+ * 'surefire-fork-count-1' enabled.
+ */
+public class ServiceHotRedeploymentViaDeploymentSpiTest extends GridCommonAbstractTest {
+    /** */
+    private static final String SERVICE_NAME = "test-service";
+
+    /** */
+    private Path srcTmpDir;
+
+    /** {@inheritDoc} */
+    @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception {
+        IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName);
+
+        cfg.setDeploymentSpi(new LocalDeploymentSpi());
+
+        return cfg;
+    }
+
+    /** */
+    @BeforeClass
+    public static void check() {
+        Assume.assumeTrue(isEventDrivenServiceProcessorEnabled());
+    }
+
+    /** */
+    @Before
+    public void prepare() throws IOException {
+        srcTmpDir = Files.createTempDirectory(getClass().getSimpleName());
+    }
+
+    /** */
+    @After
+    public void cleanup() {
+        U.delete(srcTmpDir);
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    @Test
+    public void serviceHotRedeploymentTest() throws Exception {
+        URLClassLoader clsLdr = prepareClassLoader(1);
+        Class<?> cls = clsLdr.loadClass("MyRenewServiceImpl");
+
+        MyRenewService srvc = (MyRenewService)cls.newInstance();
+
+        assertEquals(1, srvc.version());
+
+        try {
+            Ignite ignite = startGrid(0);
+
+            final DeploymentSpi depSpi = ignite.configuration().getDeploymentSpi();
+
+            depSpi.register(clsLdr, srvc.getClass());
+
+            ignite.services().deployClusterSingleton(SERVICE_NAME, srvc);
+            MyRenewService proxy = ignite.services().serviceProxy(SERVICE_NAME, MyRenewService.class, false);
+            assertEquals(1, proxy.version());
+
+            ignite.services().cancel(SERVICE_NAME);
+            depSpi.unregister(srvc.getClass().getName());
+
+            clsLdr.close();
+
+            clsLdr = prepareClassLoader(2);
+            depSpi.register(clsLdr, srvc.getClass());
+
+            ignite.services().deployClusterSingleton(SERVICE_NAME, srvc);
+            proxy = ignite.services().serviceProxy(SERVICE_NAME, MyRenewService.class, false);
+            assertEquals(2, proxy.version());
+        }
+        finally {
+            stopAllGrids();
+        }
+    }
+
+    /** */
+    public interface MyRenewService extends Service {
+        /**
+         * @return Service's version.
+         */
+        public int version();
+    }
+
+    /**
+     * @param ver Version of generated class.
+     * @return Prepared classloader.
+     * @throws Exception In case of an error.
+     */
+    private URLClassLoader prepareClassLoader(int ver) throws Exception {
+        String source = "import org.apache.ignite.internal.processors.service.ServiceHotRedeploymentViaDeploymentSpiTest;\n" +
+            "import org.apache.ignite.services.ServiceContext;\n" +
+            "public class MyRenewServiceImpl implements ServiceHotRedeploymentViaDeploymentSpiTest.MyRenewService {\n" +
+            "    @Override public int version() {\n" +
+            "        return " + ver + ";\n" +
+            "    }\n" +
+            "    @Override public void cancel(ServiceContext ctx) {}\n" +
+            "    @Override public void init(ServiceContext ctx) throws Exception {}\n" +
+            "    @Override public void execute(ServiceContext ctx) throws Exception {}\n" +
+            "}";
+
+        Files.createDirectories(srcTmpDir); // To avoid possible NoSuchFileException on some OS.
+
+        File srcFile = new File(srcTmpDir.toFile(), "MyRenewServiceImpl.java");
+
+        Path srcFilePath = Files.write(srcFile.toPath(), source.getBytes(StandardCharsets.UTF_8));
+
+        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
+
+        compiler.run(null, null, null, srcFilePath.toString());
+
+        assertTrue("Failed to remove source file.", srcFile.delete());
+
+        return new URLClassLoader(new URL[] {srcTmpDir.toUri().toURL()});
+    }
+}
\ No newline at end of file
diff --git a/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoveryNetworkIssuesTest.java b/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoveryNetworkIssuesTest.java
new file mode 100644
index 0000000..8191bca
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoveryNetworkIssuesTest.java
@@ -0,0 +1,215 @@
+/*
+ * 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.spi.discovery.tcp;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.net.SocketTimeoutException;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicBoolean;
+import org.apache.ignite.Ignite;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.events.EventType;
+import org.apache.ignite.internal.IgniteEx;
+import org.apache.ignite.internal.managers.GridManagerAdapter;
+import org.apache.ignite.internal.managers.discovery.GridDiscoveryManager;
+import org.apache.ignite.spi.IgniteSpiOperationTimeoutException;
+import org.apache.ignite.spi.IgniteSpiOperationTimeoutHelper;
+import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
+import org.apache.ignite.testframework.GridTestUtils;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+import org.junit.After;
+import org.junit.Test;
+
+/**
+ *
+ */
+public class TcpDiscoveryNetworkIssuesTest extends GridCommonAbstractTest {
+    /** */
+    private static final int NODE_0_PORT = 47500;
+
+    /** */
+    private static final int NODE_1_PORT = 47501;
+
+    /** */
+    private static final int NODE_2_PORT = 47502;
+
+    /** */
+    private static final int NODE_3_PORT = 47503;
+
+    /** */
+    private static final int NODE_4_PORT = 47504;
+
+    /** */
+    private static final int NODE_5_PORT = 47505;
+
+    /** */
+    private static final String NODE_0_NAME = "node00-" + NODE_0_PORT;
+
+    /** */
+    private static final String NODE_1_NAME = "node01-" + NODE_1_PORT;
+
+    /** */
+    private static final String NODE_2_NAME = "node02-" + NODE_2_PORT;
+
+    /** */
+    private static final String NODE_3_NAME = "node03-" + NODE_3_PORT;
+
+    /** */
+    private static final String NODE_4_NAME = "node04-" + NODE_4_PORT;
+
+    /** */
+    private static final String NODE_5_NAME = "node05-" + NODE_5_PORT;
+
+    /** */
+    private TcpDiscoveryVmIpFinder ipFinder = new TcpDiscoveryVmIpFinder(true);
+
+    /** */
+    private TcpDiscoverySpi specialSpi;
+
+    /** */
+    private boolean usePortFromNodeName;
+
+    /** */
+    private int connectionRecoveryTimeout = -1;
+
+    /** {@inheritDoc} */
+    @Override protected void afterTest() {
+        stopAllGrids();
+    }
+
+    /** {@inheritDoc} */
+    @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception {
+        IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName);
+
+        TcpDiscoverySpi spi = (specialSpi != null) ? specialSpi : new TcpDiscoverySpi();
+
+        if (usePortFromNodeName)
+            spi.setLocalPort(Integer.parseInt(igniteInstanceName.split("-")[1]));
+
+        spi.setIpFinder(ipFinder);
+
+        if (connectionRecoveryTimeout >= 0)
+            spi.setConnectionRecoveryTimeout(connectionRecoveryTimeout);
+
+        cfg.setFailureDetectionTimeout(2_000);
+
+        cfg.setDiscoverySpi(spi);
+
+        return cfg;
+    }
+
+    /**
+     * Test scenario: some node (lets call it IllN) in the middle experience network issues: its previous cannot see it,
+     * and the node cannot see two nodes in front of it.
+     *
+     * IllN is considered failed by othen nodes in topology but IllN manages to connect to topology and
+     * sends StatusCheckMessage with non-empty failedNodes collection.
+     *
+     * Expected outcome: IllN eventually segments from topology, other healthy nodes work normally.
+     *
+     * @see <a href="https://issues.apache.org/jira/browse/IGNITE-11364">IGNITE-11364</a>
+     * for more details about actual bug.
+     */
+    @Test
+    public void testServerGetsSegmentedOnBecomeDangling() throws Exception {
+        usePortFromNodeName = true;
+        connectionRecoveryTimeout = 0;
+
+        AtomicBoolean networkBroken = new AtomicBoolean(false);
+
+        IgniteEx ig0 = startGrid(NODE_0_NAME);
+
+        IgniteEx ig1 = startGrid(NODE_1_NAME);
+
+        specialSpi = new TcpDiscoverySpi() {
+            @Override protected int readReceipt(Socket sock, long timeout) throws IOException {
+                if (networkBroken.get() && sock.getPort() == NODE_3_PORT)
+                    throw new SocketTimeoutException("Read timed out");
+
+                return super.readReceipt(sock, timeout);
+            }
+
+            @Override protected Socket openSocket(InetSocketAddress sockAddr,
+                IgniteSpiOperationTimeoutHelper timeoutHelper) throws IOException, IgniteSpiOperationTimeoutException {
+                if (networkBroken.get() && sockAddr.getPort() == NODE_4_PORT)
+                    throw new SocketTimeoutException("connect timed out");
+
+                return super.openSocket(sockAddr, timeoutHelper);
+            }
+        };
+
+        Ignite ig2 = startGrid(NODE_2_NAME);
+
+        AtomicBoolean illNodeSegmented = new AtomicBoolean(false);
+
+        ig2.events().localListen((e) -> {
+            illNodeSegmented.set(true);
+
+            return false;
+            }, EventType.EVT_NODE_SEGMENTED);
+
+        specialSpi = null;
+
+        startGrid(NODE_3_NAME);
+
+        startGrid(NODE_4_NAME);
+
+        startGrid(NODE_5_NAME);
+
+        breakDiscoConnectionToNext(ig1);
+
+        networkBroken.set(true);
+
+        GridTestUtils.waitForCondition(illNodeSegmented::get, 10_000);
+
+        assertTrue(illNodeSegmented.get());
+
+        Map failedNodes = getFailedNodesCollection(ig0);
+
+        assertTrue(String.format("Failed nodes is expected to be empty, but contains %s nodes.", failedNodes.size()),
+            failedNodes.isEmpty());
+    }
+
+    /**
+     * @param ig Ignite instance to get failedNodes collection from.
+     */
+    private Map getFailedNodesCollection(IgniteEx ig) {
+        GridDiscoveryManager disco = ig.context().discovery();
+
+        Object spis = GridTestUtils.getFieldValue(disco, GridManagerAdapter.class, "spis");
+
+        return GridTestUtils.getFieldValue(((Object[])spis)[0], "impl", "failedNodes");
+    }
+
+    /**
+     * Breaks connectivity of passed server node to its next to simulate network failure.
+     *
+     * @param ig Ignite instance which connection to next node has to be broken.
+     */
+    private void breakDiscoConnectionToNext(IgniteEx ig) throws Exception {
+        GridDiscoveryManager disco = ig.context().discovery();
+
+        Object spis = GridTestUtils.getFieldValue(disco, GridManagerAdapter.class, "spis");
+
+        OutputStream out = GridTestUtils.getFieldValue(((Object[])spis)[0], "impl", "msgWorker", "out");
+
+        out.close();
+    }
+}
diff --git a/modules/core/src/test/java/org/apache/ignite/testframework/GridTestUtils.java b/modules/core/src/test/java/org/apache/ignite/testframework/GridTestUtils.java
index 29ee741..75b5367 100644
--- a/modules/core/src/test/java/org/apache/ignite/testframework/GridTestUtils.java
+++ b/modules/core/src/test/java/org/apache/ignite/testframework/GridTestUtils.java
@@ -74,6 +74,7 @@
 import org.apache.ignite.IgniteException;
 import org.apache.ignite.IgniteLogger;
 import org.apache.ignite.Ignition;
+import org.apache.ignite.cache.query.annotations.QuerySqlFunction;
 import org.apache.ignite.cluster.ClusterNode;
 import org.apache.ignite.internal.IgniteEx;
 import org.apache.ignite.internal.IgniteFutureCancelledCheckedException;
@@ -2049,43 +2050,6 @@
         }
     }
 
-    /** Adds system property on initialization and removes it when closed. */
-    public static final class SystemProperty implements AutoCloseable {
-        /** Name of property. */
-        private final String name;
-
-        /** Original value of property. */
-        private final String originalValue;
-
-        /**
-         * Constructor.
-         *
-         * @param name Name.
-         * @param val Value.
-         */
-        public SystemProperty(String name, String val) {
-            this.name = name;
-
-            Properties props = System.getProperties();
-
-            originalValue = (String)props.put(name, val);
-
-            System.setProperties(props);
-        }
-
-        /** {@inheritDoc} */
-        @Override public void close() {
-            Properties props = System.getProperties();
-
-            if (originalValue != null)
-                props.put(name, originalValue);
-            else
-                props.remove(name);
-
-            System.setProperties(props);
-        }
-    }
-
     /**
      * @param node Node to connect to.
      * @param params Connection parameters.
@@ -2123,4 +2087,41 @@
         for (File f : dir.listFiles(n -> n.getName().startsWith(IdleVerifyResultV2.IDLE_VERIFY_FILE_PREFIX)))
             f.delete();
     }
+
+    public static class SqlTestFunctions {
+        /** Sleep milliseconds. */
+        public static volatile long sleepMs = 0;
+        /** Fail flag. */
+        public static volatile boolean fail = false;
+
+        /**
+         * Do sleep {@code sleepMs} milliseconds
+         *
+         * @return amount of milliseconds to sleep
+         */
+        @QuerySqlFunction
+        public static long sleep() {
+            try {
+                Thread.sleep(sleepMs);
+            }
+            catch (InterruptedException ignored) {
+                // No-op
+            }
+
+            return sleepMs;
+        }
+
+        /**
+         * Function do fail in case of {@code fail} is true, return 0 otherwise.
+         *
+         * @return in case of {@code fail} is false return 0, fail otherwise.
+         */
+        @QuerySqlFunction
+        public static int can_fail() {
+            if (fail)
+                throw new IllegalArgumentException();
+            else
+                return 0;
+        }
+    }
 }
diff --git a/modules/core/src/test/java/org/apache/ignite/testframework/MvccFeatureChecker.java b/modules/core/src/test/java/org/apache/ignite/testframework/MvccFeatureChecker.java
index b37c0490..674c86a 100644
--- a/modules/core/src/test/java/org/apache/ignite/testframework/MvccFeatureChecker.java
+++ b/modules/core/src/test/java/org/apache/ignite/testframework/MvccFeatureChecker.java
@@ -123,7 +123,6 @@
     }
 
     /**
-     * TODO proper exception handling after https://issues.apache.org/jira/browse/IGNITE-9470
      * Checks if given exception was caused by MVCC write conflict.
      *
      * @param e Exception.
diff --git a/modules/core/src/test/java/org/apache/ignite/testframework/config/GridTestProperties.java b/modules/core/src/test/java/org/apache/ignite/testframework/config/GridTestProperties.java
index 9f6feab..8efd190 100644
--- a/modules/core/src/test/java/org/apache/ignite/testframework/config/GridTestProperties.java
+++ b/modules/core/src/test/java/org/apache/ignite/testframework/config/GridTestProperties.java
@@ -73,9 +73,6 @@
     private static final Map<String, Map<String, String>> pathProps = new HashMap<>();
 
     /** */
-    public static final String MARSH_CLASS_NAME = "marshaller.class";
-
-    /** */
     public static final String ENTRY_PROCESSOR_CLASS_NAME = "entry.processor.class";
 
     /** Binary marshaller compact footers property. */
diff --git a/modules/core/src/test/java/org/apache/ignite/testframework/junits/GridAbstractTest.java b/modules/core/src/test/java/org/apache/ignite/testframework/junits/GridAbstractTest.java
index b5edfd9..32944e4 100755
--- a/modules/core/src/test/java/org/apache/ignite/testframework/junits/GridAbstractTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/testframework/junits/GridAbstractTest.java
@@ -32,6 +32,7 @@
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.UUID;
@@ -85,6 +86,7 @@
 import org.apache.ignite.internal.util.lang.GridAbsPredicate;
 import org.apache.ignite.internal.util.typedef.F;
 import org.apache.ignite.internal.util.typedef.G;
+import org.apache.ignite.internal.util.typedef.T2;
 import org.apache.ignite.internal.util.typedef.internal.LT;
 import org.apache.ignite.internal.util.typedef.internal.U;
 import org.apache.ignite.lang.IgniteBiTuple;
@@ -123,6 +125,8 @@
 import org.apache.log4j.RollingFileAppender;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
+import org.junit.After;
+import org.junit.Before;
 import org.junit.ClassRule;
 import org.junit.Rule;
 import org.junit.rules.TestRule;
@@ -156,9 +160,6 @@
     /** Null name for execution map. */
     private static final String NULL_NAME = UUID.randomUUID().toString();
 
-    /** */
-    private static final boolean BINARY_MARSHALLER = false;
-
     /** Ip finder for TCP discovery. */
     public static final TcpDiscoveryIpFinder LOCAL_IP_FINDER = new TcpDiscoveryVmIpFinder(false) {{
         setAddresses(Collections.singleton("127.0.0.1:47500..47509"));
@@ -214,7 +215,10 @@
     private static String forceFailureMsg;
 
     /** Lazily initialized current test method. */
-    private static volatile Method currTestMtd;
+    private volatile Method currTestMtd;
+
+    /** List of system properties to set when test is finished. */
+    private final List<T2<String, String>> sysProps = new LinkedList<>();
 
     /** */
     static {
@@ -224,9 +228,6 @@
         System.setProperty(IGNITE_DISCO_FAILED_CLIENT_RECONNECT_DELAY, "1");
         System.setProperty(IGNITE_CLIENT_CACHE_CHANGE_MESSAGE_TIMEOUT, "1000");
 
-        if (BINARY_MARSHALLER)
-            GridTestProperties.setProperty(GridTestProperties.MARSH_CLASS_NAME, BinaryMarshaller.class.getName());
-
         if (GridTestClockTimer.startTestTimer()) {
             Thread timer = new Thread(new GridTestClockTimer(), "ignite-clock-for-tests");
 
@@ -645,6 +646,57 @@
         }
     }
 
+    /** */
+    @Before
+    public void setSystemPropertiesBeforeTest() {
+        List<WithSystemProperty[]> allProps = new LinkedList<>();
+
+        for (Class<?> clazz = getClass(); clazz != GridAbstractTest.class; clazz = clazz.getSuperclass()) {
+            SystemPropertiesList clsProps = clazz.getAnnotation(SystemPropertiesList.class);
+
+            if (clsProps != null)
+                allProps.add(0, clsProps.value());
+            else {
+                WithSystemProperty clsProp = clazz.getAnnotation(WithSystemProperty.class);
+
+                if (clsProp != null)
+                    allProps.add(0, new WithSystemProperty[] {clsProp});
+            }
+        }
+
+        SystemPropertiesList testProps = currentTestAnnotation(SystemPropertiesList.class);
+
+        if (testProps != null)
+            allProps.add(testProps.value());
+        else {
+            WithSystemProperty testProp = currentTestAnnotation(WithSystemProperty.class);
+
+            if (testProp != null)
+                allProps.add(new WithSystemProperty[] {testProp});
+        }
+
+        for (WithSystemProperty[] props : allProps) {
+            for (WithSystemProperty prop : props) {
+                String oldVal = System.setProperty(prop.key(), prop.value());
+
+                sysProps.add(0, new T2<>(prop.key(), oldVal));
+            }
+        }
+    }
+
+    /** */
+    @After
+    public void clearSystemPropertiesAfterTest() {
+        for (T2<String, String> t2 : sysProps) {
+            if (t2.getValue() == null)
+                System.clearProperty(t2.getKey());
+            else
+                System.setProperty(t2.getKey(), t2.getValue());
+        }
+
+        sysProps.clear();
+    }
+
     /**
      * @return Test description.
      */
@@ -666,7 +718,13 @@
     @NotNull protected Method currentTestMethod() {
         if (currTestMtd == null) {
             try {
-                currTestMtd = getClass().getMethod(getName());
+                String testName = getName();
+
+                int bracketIdx = testName.indexOf('[');
+
+                String mtdName = bracketIdx >= 0 ? testName.substring(0, bracketIdx) : testName;
+
+                currTestMtd = getClass().getMethod(mtdName);
             }
             catch (NoSuchMethodException e) {
                 throw new NoSuchMethodError("Current test method is not found: " + getName());
diff --git a/modules/core/src/test/java/org/apache/ignite/testframework/junits/IgniteTestResources.java b/modules/core/src/test/java/org/apache/ignite/testframework/junits/IgniteTestResources.java
index 156f99b..a424779 100644
--- a/modules/core/src/test/java/org/apache/ignite/testframework/junits/IgniteTestResources.java
+++ b/modules/core/src/test/java/org/apache/ignite/testframework/junits/IgniteTestResources.java
@@ -39,7 +39,6 @@
 import org.apache.ignite.marshaller.MarshallerContextTestImpl;
 import org.apache.ignite.resources.IgniteInstanceResource;
 import org.apache.ignite.resources.LoggerResource;
-import org.apache.ignite.testframework.config.GridTestProperties;
 import org.apache.ignite.testframework.junits.logger.GridTestLog4jLogger;
 import org.apache.ignite.thread.IgniteThreadPoolExecutor;
 import org.jetbrains.annotations.Nullable;
@@ -243,8 +242,7 @@
      * @throws IgniteCheckedException If failed.
      */
     public static synchronized Marshaller getMarshaller() throws IgniteCheckedException {
-        String marshallerName =
-            System.getProperty(MARSH_CLASS_NAME, GridTestProperties.getProperty(GridTestProperties.MARSH_CLASS_NAME));
+        String marshallerName = System.getProperty(MARSH_CLASS_NAME);
 
         Marshaller marsh;
 
diff --git a/modules/core/src/test/java/org/apache/ignite/testframework/junits/SystemPropertiesList.java b/modules/core/src/test/java/org/apache/ignite/testframework/junits/SystemPropertiesList.java
new file mode 100644
index 0000000..cf43b24
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/testframework/junits/SystemPropertiesList.java
@@ -0,0 +1,33 @@
+/*
+ * 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.testframework.junits;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ *
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE, ElementType.METHOD})
+public @interface SystemPropertiesList {
+    /** */
+    WithSystemProperty[] value();
+}
diff --git a/modules/core/src/test/java/org/apache/ignite/testframework/junits/WithSystemProperty.java b/modules/core/src/test/java/org/apache/ignite/testframework/junits/WithSystemProperty.java
new file mode 100644
index 0000000..e163e82
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/testframework/junits/WithSystemProperty.java
@@ -0,0 +1,38 @@
+/*
+ * 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.testframework.junits;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Repeatable;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ *
+ */
+@Repeatable(SystemPropertiesList.class)
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE, ElementType.METHOD})
+public @interface WithSystemProperty {
+    /** */
+    String key();
+
+    /** */
+    String value();
+}
diff --git a/modules/core/src/test/java/org/apache/ignite/testframework/junits/multijvm/IgniteClusterProcessProxy.java b/modules/core/src/test/java/org/apache/ignite/testframework/junits/multijvm/IgniteClusterProcessProxy.java
index d0d3a5a..b5edb0b 100644
--- a/modules/core/src/test/java/org/apache/ignite/testframework/junits/multijvm/IgniteClusterProcessProxy.java
+++ b/modules/core/src/test/java/org/apache/ignite/testframework/junits/multijvm/IgniteClusterProcessProxy.java
@@ -192,11 +192,6 @@
     }
 
     /** {@inheritDoc} */
-    @Override public DistributedBaselineConfiguration baselineConfiguration() {
-        return null;
-    }
-
-    /** {@inheritDoc} */
     @Override public boolean isAsync() {
         throw new UnsupportedOperationException("Operation is not supported yet.");
     }
@@ -371,6 +366,26 @@
         throw new UnsupportedOperationException("Operation is not supported yet.");
     }
 
+    /** {@inheritDoc} */
+    @Override public boolean isBaselineAutoAdjustEnabled() {
+        throw new UnsupportedOperationException("Operation is not supported yet.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void baselineAutoAdjustEnabled(boolean baselineAutoAdjustEnabled) throws IgniteException {
+        throw new UnsupportedOperationException("Operation is not supported yet.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public long baselineAutoAdjustTimeout() {
+        throw new UnsupportedOperationException("Operation is not supported yet.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void baselineAutoAdjustTimeout(long baselineAutoAdjustTimeout) throws IgniteException {
+        throw new UnsupportedOperationException("Operation is not supported yet.");
+    }
+
     /**
      *
      */
diff --git a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBasicTestSuite.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBasicTestSuite.java
index 9168e76..40b3f22 100644
--- a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBasicTestSuite.java
+++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBasicTestSuite.java
@@ -65,6 +65,7 @@
 import org.apache.ignite.internal.processors.closure.GridClosureProcessorRemoteTest;
 import org.apache.ignite.internal.processors.closure.GridClosureProcessorSelfTest;
 import org.apache.ignite.internal.processors.closure.GridClosureSerializationTest;
+import org.apache.ignite.internal.processors.cluster.BaselineConfigurationMXBeanTest;
 import org.apache.ignite.internal.processors.configuration.distributed.DistributedConfigurationInMemoryTest;
 import org.apache.ignite.internal.processors.continuous.GridEventConsumeSelfTest;
 import org.apache.ignite.internal.processors.continuous.GridMessageListenSelfTest;
@@ -216,6 +217,7 @@
     // In-memory Distributed MetaStorage.
     DistributedMetaStorageTest.class,
     DistributedConfigurationInMemoryTest.class,
+    BaselineConfigurationMXBeanTest.class,
 
     ConsistentIdImplicitlyExplicitlyTest.class,
 
diff --git a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBinaryObjectsSimpleNameMapperComputeGridTestSuite.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBinaryObjectsSimpleNameMapperComputeGridTestSuite.java
index b655c04..2c9bc6a 100644
--- a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBinaryObjectsSimpleNameMapperComputeGridTestSuite.java
+++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBinaryObjectsSimpleNameMapperComputeGridTestSuite.java
@@ -32,7 +32,6 @@
     /** */
     @BeforeClass
     public static void init() {
-        GridTestProperties.setProperty(GridTestProperties.MARSH_CLASS_NAME, BinaryMarshaller.class.getName());
         GridTestProperties.setProperty(GridTestProperties.BINARY_MARSHALLER_USE_SIMPLE_NAME_MAPPER, "true");
     }
 }
diff --git a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBinarySimpleNameMapperBasicTestSuite.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBinarySimpleNameMapperBasicTestSuite.java
index 99540a9..d66c63f 100644
--- a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBinarySimpleNameMapperBasicTestSuite.java
+++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBinarySimpleNameMapperBasicTestSuite.java
@@ -32,7 +32,6 @@
     /** */
     @BeforeClass
     public static void init() {
-        GridTestProperties.setProperty(GridTestProperties.MARSH_CLASS_NAME, BinaryMarshaller.class.getName());
         GridTestProperties.setProperty(GridTestProperties.BINARY_MARSHALLER_USE_SIMPLE_NAME_MAPPER, "true");
     }
 }
diff --git a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBinarySimpleNameMapperCacheFullApiTestSuite.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBinarySimpleNameMapperCacheFullApiTestSuite.java
index 90fa9e0..453b999 100644
--- a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBinarySimpleNameMapperCacheFullApiTestSuite.java
+++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBinarySimpleNameMapperCacheFullApiTestSuite.java
@@ -34,7 +34,6 @@
     /** */
     @BeforeClass
     public static void init() {
-        GridTestProperties.setProperty(GridTestProperties.MARSH_CLASS_NAME, BinaryMarshaller.class.getName());
         GridTestProperties.setProperty(GridTestProperties.BINARY_MARSHALLER_USE_SIMPLE_NAME_MAPPER, "true");
     }
 }
diff --git a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteServiceGridTestSuite.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteServiceGridTestSuite.java
index 675f0b3..02691ae 100644
--- a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteServiceGridTestSuite.java
+++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteServiceGridTestSuite.java
@@ -53,6 +53,7 @@
 import org.apache.ignite.internal.processors.service.ServiceDeploymentProcessingOnCoordinatorLeftTest;
 import org.apache.ignite.internal.processors.service.ServiceDeploymentProcessingOnNodesFailTest;
 import org.apache.ignite.internal.processors.service.ServiceDeploymentProcessingOnNodesLeftTest;
+import org.apache.ignite.internal.processors.service.ServiceHotRedeploymentViaDeploymentSpiTest;
 import org.apache.ignite.internal.processors.service.ServiceInfoSelfTest;
 import org.apache.ignite.internal.processors.service.ServicePredicateAccessCacheTest;
 import org.apache.ignite.internal.processors.service.ServiceReassignmentFunctionSelfTest;
@@ -109,6 +110,7 @@
     ServiceReassignmentFunctionSelfTest.class,
     ServiceInfoSelfTest.class,
     ServiceDeploymentProcessIdSelfTest.class,
+    ServiceHotRedeploymentViaDeploymentSpiTest.class,
 })
 public class IgniteServiceGridTestSuite {
 }
diff --git a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteSpiDiscoverySelfTestSuite.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteSpiDiscoverySelfTestSuite.java
index a17639e..c1d85e5 100644
--- a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteSpiDiscoverySelfTestSuite.java
+++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteSpiDiscoverySelfTestSuite.java
@@ -41,6 +41,7 @@
 import org.apache.ignite.spi.discovery.tcp.TcpDiscoveryIpFinderCleanerTest;
 import org.apache.ignite.spi.discovery.tcp.TcpDiscoveryMarshallerCheckSelfTest;
 import org.apache.ignite.spi.discovery.tcp.TcpDiscoveryMultiThreadedTest;
+import org.apache.ignite.spi.discovery.tcp.TcpDiscoveryNetworkIssuesTest;
 import org.apache.ignite.spi.discovery.tcp.TcpDiscoveryNodeAttributesUpdateOnReconnectTest;
 import org.apache.ignite.spi.discovery.tcp.TcpDiscoveryNodeConfigConsistentIdSelfTest;
 import org.apache.ignite.spi.discovery.tcp.TcpDiscoveryNodeConsistentIdSelfTest;
@@ -124,6 +125,8 @@
 
     TcpDiscoverySpiReconnectDelayTest.class,
 
+    TcpDiscoveryNetworkIssuesTest.class,
+
     IgniteDiscoveryMassiveNodeFailTest.class,
     TcpDiscoveryCoordinatorFailureTest.class,
 
diff --git a/modules/core/src/test/java/org/apache/ignite/util/GridCommandHandlerTest.java b/modules/core/src/test/java/org/apache/ignite/util/GridCommandHandlerTest.java
index a9afd4f..7356c7a 100644
--- a/modules/core/src/test/java/org/apache/ignite/util/GridCommandHandlerTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/util/GridCommandHandlerTest.java
@@ -52,6 +52,7 @@
 import org.apache.ignite.IgniteAtomicSequence;
 import org.apache.ignite.IgniteCache;
 import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.IgniteCluster;
 import org.apache.ignite.IgniteDataStreamer;
 import org.apache.ignite.cache.affinity.rendezvous.RendezvousAffinityFunction;
 import org.apache.ignite.cluster.BaselineNode;
@@ -67,7 +68,6 @@
 import org.apache.ignite.internal.IgniteEx;
 import org.apache.ignite.internal.IgniteInternalFuture;
 import org.apache.ignite.internal.TestRecordingCommunicationSpi;
-import org.apache.ignite.internal.cluster.DistributedBaselineConfiguration;
 import org.apache.ignite.internal.commandline.Command;
 import org.apache.ignite.internal.commandline.CommandArgFactory;
 import org.apache.ignite.internal.commandline.CommandHandler;
@@ -126,6 +126,7 @@
 import static org.apache.ignite.internal.commandline.OutputFormat.SINGLE_LINE;
 import static org.apache.ignite.internal.commandline.cache.CacheCommand.HELP;
 import static org.apache.ignite.internal.processors.cache.verify.VerifyBackupPartitionsDumpTask.IDLE_DUMP_FILE_PREFIX;
+import static org.apache.ignite.testframework.GridTestUtils.waitForCondition;
 import static org.apache.ignite.transactions.TransactionConcurrency.OPTIMISTIC;
 import static org.apache.ignite.transactions.TransactionConcurrency.PESSIMISTIC;
 import static org.apache.ignite.transactions.TransactionIsolation.READ_COMMITTED;
@@ -194,9 +195,9 @@
 
         // Delete idle-verify dump files.
         try (DirectoryStream<Path> files = newDirectoryStream(
-                Paths.get(U.defaultWorkDirectory()),
-                entry -> entry.toFile().getName().startsWith(IDLE_DUMP_FILE_PREFIX)
-            )
+            Paths.get(U.defaultWorkDirectory()),
+            entry -> entry.toFile().getName().startsWith(IDLE_DUMP_FILE_PREFIX)
+        )
         ) {
             for (Path path : files)
                 delete(path);
@@ -206,6 +207,7 @@
 
         System.setOut(sysOut);
 
+        log.info("----------------------------------------");
         if (testOut != null)
             System.out.println(testOut.toString());
     }
@@ -586,7 +588,7 @@
     }
 
     /**
-     * Test that baseline autoadjustment settings update works via control.sh
+     * Test that baseline auto_adjustment settings update works via control.sh
      *
      * @throws Exception If failed.
      */
@@ -596,38 +598,44 @@
 
         ignite.cluster().active(true);
 
-        DistributedBaselineConfiguration bc = ignite.cluster().baselineConfiguration();
+        IgniteCluster cl = ignite.cluster();
 
-        assertFalse(bc.isBaselineAutoAdjustEnabled());
+        assertFalse(cl.isBaselineAutoAdjustEnabled());
 
-        long softTimeout = bc.getBaselineAutoAdjustTimeout();
+        long timeout = cl.baselineAutoAdjustTimeout();
 
         assertEquals(EXIT_CODE_OK, execute(
             "--baseline",
-            "autoadjust",
+            "auto_adjust",
             "enable",
-            Long.toString(softTimeout + 1)
+            "timeout",
+            Long.toString(timeout + 1)
         ));
 
-        assertTrue(bc.isBaselineAutoAdjustEnabled());
+        assertTrue(cl.isBaselineAutoAdjustEnabled());
 
-        assertEquals(softTimeout + 1, bc.getBaselineAutoAdjustTimeout());
+        assertEquals(timeout + 1, cl.baselineAutoAdjustTimeout());
 
-        assertEquals(EXIT_CODE_OK, execute("--baseline", "autoadjust", "disable"));
+        assertEquals(EXIT_CODE_OK, execute("--baseline", "auto_adjust", "disable"));
 
-        assertFalse(bc.isBaselineAutoAdjustEnabled());
+        assertFalse(cl.isBaselineAutoAdjustEnabled());
 
-        assertEquals(EXIT_CODE_INVALID_ARGUMENTS, execute("--baseline", "autoadjust"));
+        assertEquals(EXIT_CODE_INVALID_ARGUMENTS, execute("--baseline", "auto_adjust"));
 
-        assertEquals(EXIT_CODE_INVALID_ARGUMENTS, execute("--baseline", "autoadjust", "true"));
+        assertEquals(EXIT_CODE_INVALID_ARGUMENTS, execute("--baseline", "auto_adjust", "true"));
 
-        assertEquals(EXIT_CODE_INVALID_ARGUMENTS, execute("--baseline", "autoadjust", "enable", "x"));
+        assertEquals(EXIT_CODE_INVALID_ARGUMENTS, execute("--baseline", "auto_adjust", "enable", "x"));
 
-        assertEquals(EXIT_CODE_INVALID_ARGUMENTS, execute("--baseline", "autoadjust", "disable", "x"));
+        assertEquals(EXIT_CODE_INVALID_ARGUMENTS, execute("--baseline", "auto_adjust", "disable", "x"));
+
+        log.info("================================================");
+        System.out.println(testOut.toString());
+
+        log.info("================================================");
     }
 
     /**
-     * Test that updating of baseline autoadjustment settings via control.sh actually influence cluster's baseline.
+     * Test that updating of baseline auto_adjustment settings via control.sh actually influence cluster's baseline.
      *
      * @throws Exception If failed.
      */
@@ -637,7 +645,7 @@
 
         ignite.cluster().active(true);
 
-        assertEquals(EXIT_CODE_OK, execute("--baseline", "autoadjust", "enable", "2000"));
+        assertEquals(EXIT_CODE_OK, execute("--baseline", "auto_adjust", "enable", "timeout", "2000"));
 
         assertEquals(3, ignite.cluster().currentBaselineTopology().size());
 
@@ -645,13 +653,11 @@
 
         assertEquals(3, ignite.cluster().currentBaselineTopology().size());
 
-        Thread.sleep(3000L);
+        assertTrue(waitForCondition(() -> ignite.cluster().currentBaselineTopology().size() == 2, 10000));
 
         Collection<BaselineNode> baselineNodesAfter = ignite.cluster().currentBaselineTopology();
 
-        assertEquals(2, baselineNodesAfter.size());
-
-        assertEquals(EXIT_CODE_OK, execute("--baseline", "autoadjust", "disable"));
+        assertEquals(EXIT_CODE_OK, execute("--baseline", "auto_adjust", "disable"));
 
         stopGrid(1);
 
@@ -666,7 +672,7 @@
     }
 
     /**
-     * Test that updating of baseline autoadjustment settings via control.sh actually influence cluster's baseline.
+     * Test that updating of baseline auto_adjustment settings via control.sh actually influence cluster's baseline.
      *
      * @throws Exception If failed.
      */
@@ -676,7 +682,7 @@
 
         ignite.cluster().active(true);
 
-        assertEquals(EXIT_CODE_OK, execute("--baseline", "autoadjust", "enable", "2000"));
+        assertEquals(EXIT_CODE_OK, execute("--baseline", "auto_adjust", "enable", "timeout", "2000"));
 
         assertEquals(1, ignite.cluster().currentBaselineTopology().size());
 
@@ -684,13 +690,13 @@
 
         assertEquals(1, ignite.cluster().currentBaselineTopology().size());
 
-        Thread.sleep(3000L);
+        assertEquals(EXIT_CODE_OK, execute("--baseline"));
+
+        assertTrue(waitForCondition(() -> ignite.cluster().currentBaselineTopology().size() == 2, 10000));
 
         Collection<BaselineNode> baselineNodesAfter = ignite.cluster().currentBaselineTopology();
 
-        assertEquals(2, baselineNodesAfter.size());
-
-        assertEquals(EXIT_CODE_OK, execute("--baseline", "autoadjust", "disable"));
+        assertEquals(EXIT_CODE_OK, execute("--baseline", "auto_adjust", "disable"));
 
         startGrid(2);
 
@@ -1045,7 +1051,7 @@
 
             Collection<IgniteInternalTx> txs = ((IgniteEx)ignite).context().cache().context().tm().activeTransactions();
 
-            GridTestUtils.waitForCondition(new GridAbsPredicate() {
+            waitForCondition(new GridAbsPredicate() {
                 @Override public boolean apply() {
                     for (IgniteInternalTx tx : txs)
                         if (!tx.local()) {
@@ -1169,7 +1175,7 @@
     public void testCorrectCacheOptionsNaming() throws Exception {
         Pattern p = Pattern.compile("^--([a-z]+(-)?)+([a-z]+)");
 
-        for(CacheCommand cmd : CacheCommand.values()) {
+        for (CacheCommand cmd : CacheCommand.values()) {
             for (CommandArg arg : CommandArgFactory.getArgs(cmd))
                 assertTrue(arg.toString(), p.matcher(arg.toString()).matches());
         }
@@ -1549,7 +1555,7 @@
     private void corruptPartition(File partitionsDir) throws IOException {
         ThreadLocalRandom rand = ThreadLocalRandom.current();
 
-        for(File partFile : partitionsDir.listFiles((d, n) -> n.startsWith("part"))) {
+        for (File partFile : partitionsDir.listFiles((d, n) -> n.startsWith("part"))) {
             try (RandomAccessFile raf = new RandomAccessFile(partFile, "rw")) {
                 byte[] buf = new byte[1024];
 
diff --git a/modules/hibernate-4.2/src/test/java/org/apache/ignite/testsuites/IgniteBinaryHibernateTestSuite.java b/modules/hibernate-4.2/src/test/java/org/apache/ignite/testsuites/IgniteBinaryHibernateTestSuite.java
deleted file mode 100644
index 7425238..0000000
--- a/modules/hibernate-4.2/src/test/java/org/apache/ignite/testsuites/IgniteBinaryHibernateTestSuite.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * 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.testsuites;
-
-import org.apache.ignite.internal.binary.BinaryMarshaller;
-import org.apache.ignite.testframework.config.GridTestProperties;
-import org.junit.BeforeClass;
-import org.junit.runner.RunWith;
-import org.junit.runners.Suite;
-
-/** */
-@RunWith(Suite.class)
-@Suite.SuiteClasses({
-    IgniteHibernateTestSuite.class
-})
-public class IgniteBinaryHibernateTestSuite {
-    /** */
-    @BeforeClass
-    public static void init() {
-        GridTestProperties.setProperty(GridTestProperties.MARSH_CLASS_NAME, BinaryMarshaller.class.getName());
-    }
-}
diff --git a/modules/hibernate-5.1/src/test/java/org/apache/ignite/testsuites/IgniteBinaryHibernate5TestSuite.java b/modules/hibernate-5.1/src/test/java/org/apache/ignite/testsuites/IgniteBinaryHibernate5TestSuite.java
deleted file mode 100644
index 2a33e08..0000000
--- a/modules/hibernate-5.1/src/test/java/org/apache/ignite/testsuites/IgniteBinaryHibernate5TestSuite.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * 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.testsuites;
-
-import org.apache.ignite.internal.binary.BinaryMarshaller;
-import org.apache.ignite.testframework.config.GridTestProperties;
-import org.junit.BeforeClass;
-import org.junit.runner.RunWith;
-import org.junit.runners.Suite;
-
-/** */
-@RunWith(Suite.class)
-@Suite.SuiteClasses({
-    IgniteHibernate5TestSuite.class
-})
-public class IgniteBinaryHibernate5TestSuite {
-    /** */
-    @BeforeClass
-    public static void init() {
-        GridTestProperties.setProperty(GridTestProperties.MARSH_CLASS_NAME, BinaryMarshaller.class.getName());
-    }
-}
diff --git a/modules/hibernate-5.3/src/test/java/org/apache/ignite/testsuites/IgniteBinaryHibernate53TestSuite.java b/modules/hibernate-5.3/src/test/java/org/apache/ignite/testsuites/IgniteBinaryHibernate53TestSuite.java
deleted file mode 100644
index 6ce688c..0000000
--- a/modules/hibernate-5.3/src/test/java/org/apache/ignite/testsuites/IgniteBinaryHibernate53TestSuite.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * 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.testsuites;
-
-import org.apache.ignite.internal.binary.BinaryMarshaller;
-import org.apache.ignite.testframework.config.GridTestProperties;
-import org.junit.BeforeClass;
-import org.junit.runner.RunWith;
-import org.junit.runners.Suite;
-
-/** */
-@RunWith(Suite.class)
-@Suite.SuiteClasses({
-    IgniteHibernate53TestSuite.class
-})
-public class IgniteBinaryHibernate53TestSuite {
-    /** */
-    @BeforeClass
-    public static void init()  {
-        GridTestProperties.setProperty(GridTestProperties.MARSH_CLASS_NAME, BinaryMarshaller.class.getName());
-    }
-}
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/CommandProcessor.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/CommandProcessor.java
index 0007fd8..c71a5c2 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/CommandProcessor.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/CommandProcessor.java
@@ -37,7 +37,6 @@
 import org.apache.ignite.cache.QueryIndexType;
 import org.apache.ignite.cache.query.BulkLoadContextCursor;
 import org.apache.ignite.cache.query.FieldsQueryCursor;
-import org.apache.ignite.cache.query.SqlFieldsQuery;
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.internal.GridKernalContext;
 import org.apache.ignite.internal.IgniteInternalFuture;
@@ -50,7 +49,6 @@
 import org.apache.ignite.internal.processors.cache.distributed.near.GridNearTxLocal;
 import org.apache.ignite.internal.processors.cache.mvcc.MvccUtils;
 import org.apache.ignite.internal.processors.cache.query.IgniteQueryErrorCode;
-import org.apache.ignite.internal.processors.cache.query.SqlFieldsQueryEx;
 import org.apache.ignite.internal.processors.query.GridQueryProperty;
 import org.apache.ignite.internal.processors.query.GridQueryTypeDescriptor;
 import org.apache.ignite.internal.processors.query.IgniteSQLException;
@@ -160,15 +158,16 @@
     /**
      * Execute command.
      *
-     * @param qry Query.
+     * @param sql SQL.
      * @param cmdNative Native command (if any).
      * @param cmdH2 H2 command (if any).
+     * @param params Parameters.
      * @param cliCtx Client context.
      * @param qryId Running query ID.
      * @return Result.
      */
-    public CommandResult runCommand(SqlFieldsQuery qry, SqlCommand cmdNative, GridSqlStatement cmdH2,
-        @Nullable SqlClientContext cliCtx, Long qryId) throws IgniteCheckedException {
+    public CommandResult runCommand(String sql, SqlCommand cmdNative, GridSqlStatement cmdH2,
+        QueryParameters params, @Nullable SqlClientContext cliCtx, Long qryId) throws IgniteCheckedException {
         assert cmdNative != null || cmdH2 != null;
 
         // Do execute.
@@ -179,7 +178,7 @@
             assert cmdH2 == null;
 
             if (isDdl(cmdNative))
-                runCommandNativeDdl(qry.getSql(), cmdNative);
+                runCommandNativeDdl(sql, cmdNative);
             else if (cmdNative instanceof SqlBulkLoadCommand) {
                 res = processBulkLoadCommand((SqlBulkLoadCommand) cmdNative, qryId);
 
@@ -188,12 +187,12 @@
             else if (cmdNative instanceof SqlSetStreamingCommand)
                 processSetStreamingCommand((SqlSetStreamingCommand)cmdNative, cliCtx);
             else
-                processTxCommand(cmdNative, qry);
+                processTxCommand(cmdNative, params);
         }
         else {
             assert cmdH2 != null;
 
-            runCommandH2(qry.getSql(), cmdH2);
+            runCommandH2(sql, cmdH2);
         }
 
         return new CommandResult(res, unregister);
@@ -839,13 +838,12 @@
     /**
      * Process transactional command.
      * @param cmd Command.
-     * @param qry Query.
+     * @param params Parameters.
      * @throws IgniteCheckedException if failed.
      */
-    private void processTxCommand(SqlCommand cmd, SqlFieldsQuery qry)
+    private void processTxCommand(SqlCommand cmd, QueryParameters params)
         throws IgniteCheckedException {
-        NestedTxMode nestedTxMode = qry instanceof SqlFieldsQueryEx ? ((SqlFieldsQueryEx)qry).getNestedTxMode() :
-            NestedTxMode.DEFAULT;
+        NestedTxMode nestedTxMode = params.nestedTxMode();
 
         GridNearTxLocal tx = tx(ctx);
 
@@ -862,7 +860,7 @@
                     case COMMIT:
                         doCommit(tx);
 
-                        txStart(ctx, qry.getTimeout());
+                        txStart(ctx, params.timeout());
 
                         break;
 
@@ -881,7 +879,7 @@
                 }
             }
             else
-                txStart(ctx, qry.getTimeout());
+                txStart(ctx, params.timeout());
         }
         else if (cmd instanceof SqlCommitTransactionCommand) {
             // Do nothing if there's no transaction.
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 3e1d776..8164787 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,14 +71,12 @@
 import org.apache.ignite.internal.processors.cache.query.indexing.GridCacheTwoStepQuery;
 import org.apache.ignite.internal.processors.cache.query.IgniteQueryErrorCode;
 import org.apache.ignite.internal.processors.cache.query.indexing.RegisteredQueryCursor;
-import org.apache.ignite.internal.processors.cache.query.SqlFieldsQueryEx;
 import org.apache.ignite.internal.processors.cache.transactions.IgniteTxAdapter;
 import org.apache.ignite.internal.processors.cache.tree.CacheDataTree;
 import org.apache.ignite.internal.processors.odbc.SqlStateCode;
 import org.apache.ignite.internal.processors.query.EnlistOperation;
 import org.apache.ignite.internal.processors.query.GridQueryCacheObjectsIterator;
 import org.apache.ignite.internal.processors.query.GridQueryCancel;
-import org.apache.ignite.internal.processors.query.GridQueryFieldMetadata;
 import org.apache.ignite.internal.processors.query.GridQueryFieldsResult;
 import org.apache.ignite.internal.processors.query.GridQueryFieldsResultAdapter;
 import org.apache.ignite.internal.processors.query.GridQueryIndexing;
@@ -420,32 +418,27 @@
     /**
      * Queries individual fields (generally used by JDBC drivers).
      *
-     * @param schemaName Schema name.
-     * @param qry Query.
-     * @param params Query parameters.
+     * @param qryDesc Query descriptor.
+     * @param qryParams Query parameters.
+     * @param select Select.
      * @param filter Cache name and key filter.
-     * @param enforceJoinOrder Enforce join order of tables in the query.
-     * @param startTx Start transaction flag.
-     * @param qryTimeout Query timeout in milliseconds.
-     * @param cancel Query cancel.
+     * @param autoStartTx Start transaction flag.
      * @param mvccTracker Query tracker.
-     * @param dataPageScanEnabled If data page scan is enabled.
+     * @param cancel Query cancel.
      * @return Query result.
      * @throws IgniteCheckedException If failed.
      */
-    private GridQueryFieldsResult executeQueryLocal0(
-        final String schemaName,
-        String qry,
-        @Nullable final Collection<Object> params,
-        @Nullable List<GridQueryFieldMetadata> meta,
+    private GridQueryFieldsResult executeSelectLocal(
+        QueryDescriptor qryDesc,
+        QueryParameters qryParams,
+        QueryParserResultSelect select,
         final IndexingQueryFilter filter,
-        boolean enforceJoinOrder,
-        boolean startTx,
-        int qryTimeout,
-        final GridQueryCancel cancel,
+        boolean autoStartTx,
         MvccQueryTracker mvccTracker,
-        Boolean dataPageScanEnabled
+        GridQueryCancel cancel
     ) throws IgniteCheckedException {
+        String qry = qryDesc.sql();
+
         GridNearTxLocal tx = null;
 
         boolean mvccEnabled = mvccEnabled(kernalContext());
@@ -453,37 +446,6 @@
         assert mvccEnabled || mvccTracker == null;
 
         try {
-            SqlFieldsQuery fieldsQry = new SqlFieldsQuery(qry)
-                .setLocal(true)
-                .setEnforceJoinOrder(enforceJoinOrder)
-                .setDataPageScanEnabled(dataPageScanEnabled)
-                .setTimeout(qryTimeout, TimeUnit.MILLISECONDS);
-
-            if (params != null)
-                fieldsQry.setArgs(params.toArray());
-
-            QueryParserResult parseRes = parser.parse(schemaName, fieldsQry, false);
-
-            if (parseRes.isDml()) {
-                QueryParserResultDml dml = parseRes.dml();
-
-                assert dml != null;
-
-                UpdateResult updRes = executeUpdate(schemaName, dml, fieldsQry, true, filter, cancel);
-
-                List<?> updResRow = Collections.singletonList(updRes.counter());
-
-                return new GridQueryFieldsResultAdapter(UPDATE_RESULT_META, new IgniteSingletonIterator<>(updResRow));
-            }
-            else if (parseRes.isCommand()) {
-                throw new IgniteSQLException("DDL statements are supported for the whole cluster only.",
-                    IgniteQueryErrorCode.UNSUPPORTED_OPERATION);
-            }
-
-            assert parseRes.isSelect();
-
-            QueryParserResultSelect select = parseRes.select();
-
             assert select != null;
 
             MvccSnapshot mvccSnapshot = null;
@@ -494,12 +456,9 @@
                 throw new IgniteSQLException("SELECT FOR UPDATE query requires transactional " +
                     "cache with MVCC enabled.", IgniteQueryErrorCode.UNSUPPORTED_OPERATION);
 
-            if (ctx.security().enabled())
-                checkSecurity(select.cacheIds());
-
             GridNearTxSelectForUpdateFuture sfuFut = null;
 
-            int opTimeout = qryTimeout;
+            int opTimeout = qryParams.timeout();
 
             if (mvccEnabled) {
                 if (mvccTracker == null) {
@@ -512,7 +471,7 @@
                             throw new IgniteCheckedException("Cache has been stopped concurrently [cacheId=" +
                                 mvccCacheId + ']');
 
-                        mvccTracker = MvccUtils.mvccTracker(mvccCacheCtx, startTx);
+                        mvccTracker = MvccUtils.mvccTracker(mvccCacheCtx, autoStartTx);
                     }
                 }
 
@@ -563,7 +522,7 @@
                 null
             );
 
-            return new GridQueryFieldsResultAdapter(meta, null) {
+            return new GridQueryFieldsResultAdapter(select.meta(), null) {
                 @Override public GridCloseableIterator<List<?>> iterator() throws IgniteCheckedException {
                     assert qryCtxRegistry.getThreadLocal() == null;
 
@@ -572,12 +531,17 @@
                     ThreadLocalObjectPool<H2ConnectionWrapper>.Reusable conn = connMgr.detachThreadConnection();
 
                     try {
-                        Connection conn0 = conn.object().connection(schemaName);
+                        Connection conn0 = conn.object().connection(qryDesc.schemaName());
+
+                        H2Utils.setupConnection(conn0,
+                            qryDesc.distributedJoins(), qryDesc.enforceJoinOrder(), qryParams.lazy());
+
+                        List<Object> args = F.asList(qryParams.arguments());
 
                         PreparedStatement stmt = preparedStatementWithParams(
                             conn0,
                             qry0,
-                            params,
+                            args,
                             true
                         );
 
@@ -585,10 +549,10 @@
                             stmt,
                             conn0,
                             qry0,
-                            params,
+                            args,
                             timeout0,
                             cancel,
-                            dataPageScanEnabled
+                            qryParams.dataPageScanEnabled()
                         );
 
                         if (sfuFut0 != null) {
@@ -991,65 +955,11 @@
     }
 
     /**
-     * Queries individual fields (generally used by JDBC drivers).
-     *
-     * @param schemaName Schema name.
-     * @param qry Query.
-     * @param keepBinary Keep binary flag.
-     * @param filter Cache name and key filter.
-     * @param cancel Query cancel.
-     * @param qryId Running query id. {@code null} in case query is not registered.
-     * @return Cursor.
-     */
-    private FieldsQueryCursor<List<?>> executeQueryLocal(
-        String schemaName,
-        SqlFieldsQuery qry,
-        List<GridQueryFieldMetadata> meta,
-        final boolean keepBinary,
-        IndexingQueryFilter filter,
-        GridQueryCancel cancel,
-        Long qryId
-    ) throws IgniteCheckedException {
-        boolean startTx = autoStartTx(qry);
-
-        final GridQueryFieldsResult res = executeQueryLocal0(
-            schemaName,
-            qry.getSql(),
-            F.asList(qry.getArgs()),
-            meta,
-            filter,
-            qry.isEnforceJoinOrder(),
-            startTx,
-            qry.getTimeout(),
-            cancel,
-            null,
-            qry.isDataPageScanEnabled()
-        );
-
-        Iterable<List<?>> iter = () -> {
-            try {
-                return new GridQueryCacheObjectsIterator(res.iterator(), objectContext(), keepBinary);
-            }
-            catch (IgniteCheckedException e) {
-                throw new IgniteException(e);
-            }
-        };
-
-        QueryCursorImpl<List<?>> cursor = qryId != null
-            ? new RegisteredQueryCursor<>(iter, cancel, runningQueryManager(), qryId)
-            : new QueryCursorImpl<>(iter, cancel);
-
-        cursor.fieldsMeta(res.metaData());
-
-        return cursor;
-    }
-
-    /**
      * @param schemaName Schema name.
      * @param qry Query.
      * @param keepCacheObj Flag to keep cache object.
      * @param enforceJoinOrder Enforce join order of tables.
-     * @param startTx Start transaction flag.
+     * @param autoStartTx Start transaction flag.
      * @param qryTimeout Query timeout.
      * @param cancel Cancel object.
      * @param params Query parameters.
@@ -1060,12 +970,13 @@
      * @param pageSize Page size.
      * @return Iterable result.
      */
+    @SuppressWarnings("IfMayBeConditional")
     private Iterable<List<?>> runQueryTwoStep(
         final String schemaName,
         final GridCacheTwoStepQuery qry,
         final boolean keepCacheObj,
         final boolean enforceJoinOrder,
-        boolean startTx,
+        boolean autoStartTx,
         final int qryTimeout,
         final GridQueryCancel cancel,
         final Object[] params,
@@ -1078,10 +989,18 @@
         assert !qry.mvccEnabled() || !F.isEmpty(qry.cacheIds());
 
         try {
-            final MvccQueryTracker tracker = mvccTracker == null && qry.mvccEnabled() ?
-                MvccUtils.mvccTracker(ctx.cache().context().cacheContext(qry.cacheIds().get(0)), startTx) : mvccTracker;
+            final MvccQueryTracker mvccTracker0;
 
-            GridNearTxLocal tx = tracker != null ? tx(ctx) : null;
+            if (mvccTracker == null && qry.mvccEnabled()) {
+                mvccTracker0 = MvccUtils.mvccTracker(
+                    ctx.cache().context().cacheContext(qry.cacheIds().get(0)),
+                    autoStartTx
+                );
+            }
+            else
+                mvccTracker0 = mvccTracker;
+
+            GridNearTxLocal tx = mvccTracker0 != null ? tx(ctx) : null;
 
             // Locking has no meaning if SELECT FOR UPDATE is not executed in explicit transaction.
             // So, we can can reset forUpdate flag if there is no explicit transaction.
@@ -1103,15 +1022,15 @@
                             params,
                             parts,
                             lazy,
-                            tracker,
+                            mvccTracker0,
                             dataPageScanEnabled,
                             forUpdate,
                             pageSize
                         );
                     }
                     catch (Throwable e) {
-                        if (tracker != null)
-                            tracker.onDone();
+                        if (mvccTracker0 != null)
+                            mvccTracker0.onDone();
 
                         throw e;
                     }
@@ -1166,15 +1085,15 @@
     /**
      * Execute command.
      *
-     * @param schemaName Schema name.
-     * @param qry Query.
+     * @param qryDesc Query descriptor.
+     * @param qryParams Query parameters.
      * @param cliCtx CLient context.
      * @param cmd Command (native).
      * @return Result.
      */
     private FieldsQueryCursor<List<?>> executeCommand(
-        String schemaName,
-        SqlFieldsQuery qry,
+        QueryDescriptor qryDesc,
+        QueryParameters qryParams,
         @Nullable SqlClientContext cliCtx,
         QueryParserResultCommand cmd
     ) {
@@ -1184,26 +1103,26 @@
         SqlCommand cmdNative = cmd.commandNative();
         GridSqlStatement cmdH2 = cmd.commandH2();
 
-        if (qry.isLocal()) {
+        if (qryDesc.local()) {
             throw new IgniteSQLException("DDL statements are not supported for LOCAL caches",
                 IgniteQueryErrorCode.UNSUPPORTED_OPERATION);
         }
 
-        Long qryId = registerRunningQuery(schemaName, null, qry.getSql(), qry.isLocal(), true);
+        Long qryId = registerRunningQuery(qryDesc, null);
 
         boolean fail = false;
 
         CommandResult res = null;
 
         try {
-            res = cmdProc.runCommand(qry, cmdNative, cmdH2, cliCtx, qryId);
+            res = cmdProc.runCommand(qryDesc.sql(), cmdNative, cmdH2, qryParams, cliCtx, qryId);
 
             return res.cursor();
         }
         catch (IgniteCheckedException e) {
             fail = true;
 
-            throw new IgniteSQLException("Failed to execute DDL statement [stmt=" + qry.getSql() +
+            throw new IgniteSQLException("Failed to execute DDL statement [stmt=" + qryDesc.sql() +
                 ", err=" + e.getMessage() + ']', e);
         }
         finally {
@@ -1244,11 +1163,9 @@
         @Nullable SqlClientContext cliCtx,
         boolean keepBinary,
         boolean failOnMultipleStmts,
-        MvccQueryTracker tracker,
-        GridQueryCancel cancel,
-        boolean registerAsNewQry
+        GridQueryCancel cancel
     ) {
-        boolean mvccEnabled = mvccEnabled(ctx), startTx = autoStartTx(qry);
+        boolean mvccEnabled = mvccEnabled(ctx);
 
         try {
             List<FieldsQueryCursor<List<?>>> res = new ArrayList<>(1);
@@ -1262,12 +1179,13 @@
                 remainingQry = parseRes.remainingQuery();
 
                 // Get next command.
-                SqlFieldsQuery newQry = parseRes.query();
+                QueryDescriptor newQryDesc = parseRes.queryDescriptor();
+                QueryParameters newQryParams = parseRes.queryParameters();
 
                 // Check if there is enough parameters. Batched statements are not checked at this point
                 // since they pass parameters differently.
-                if (!DmlUtils.isBatched(newQry)) {
-                    int qryParamsCnt = F.isEmpty(newQry.getArgs()) ? 0 : newQry.getArgs().length;
+                if (!newQryDesc.batched()) {
+                    int qryParamsCnt = F.isEmpty(newQryParams.arguments()) ? 0 : newQryParams.arguments().length;
 
                     if (qryParamsCnt < parseRes.parametersCount())
                         throw new IgniteSQLException("Invalid number of query parameters [expected=" +
@@ -1283,28 +1201,42 @@
 
                     assert cmd != null;
 
-                    // Execute command.
                     FieldsQueryCursor<List<?>> cmdRes = executeCommand(
-                        schemaName,
-                        newQry,
+                        newQryDesc,
+                        newQryParams,
                         cliCtx,
                         cmd
                     );
 
                     res.add(cmdRes);
                 }
+                else if (parseRes.isDml()) {
+                    QueryParserResultDml dml = parseRes.dml();
+
+                    assert dml != null;
+
+                    List<? extends FieldsQueryCursor<List<?>>> dmlRes = executeDml(
+                        newQryDesc,
+                        newQryParams,
+                        dml,
+                        cancel
+                    );
+
+                    res.addAll(dmlRes);
+                }
                 else {
-                    // Execute query or DML.
-                    List<? extends FieldsQueryCursor<List<?>>> qryRes = executeSelectOrDml(
-                        schemaName,
-                        newQry,
-                        parseRes.select(),
-                        parseRes.dml(),
+                    assert parseRes.isSelect();
+
+                    QueryParserResultSelect select = parseRes.select();
+
+                    assert select != null;
+
+                    List<? extends FieldsQueryCursor<List<?>>> qryRes = executeSelect(
+                        newQryDesc,
+                        newQryParams,
+                        select,
                         keepBinary,
-                        startTx,
-                        tracker,
-                        cancel,
-                        registerAsNewQry
+                        cancel
                     );
 
                     res.addAll(qryRes);
@@ -1329,137 +1261,236 @@
 
     /**
      * Execute an all-ready {@link SqlFieldsQuery}.
-     * @param schemaName Schema name.
-     * @param qry Fields query with flags.
-     * @param select Select.
+     *
+     * @param qryDesc Plan key.
+     * @param qryParams Parameters.
      * @param dml DML.
-     * @param keepBinary Whether binary objects must not be deserialized automatically.
-     * @param startTx Start transaction flag.
-     * @param mvccTracker MVCC tracker.
      * @param cancel Query cancel state holder.
-     * @param registerAsNewQry {@code true} In case it's new query which should be registered as running query,
      * @return Query result.
      */
-    private List<? extends FieldsQueryCursor<List<?>>> executeSelectOrDml(
-        String schemaName,
-        SqlFieldsQuery qry,
-        @Nullable QueryParserResultSelect select,
-        @Nullable QueryParserResultDml dml,
-        boolean keepBinary,
-        boolean startTx,
-        MvccQueryTracker mvccTracker,
-        GridQueryCancel cancel,
-        boolean registerAsNewQry
+    private List<? extends FieldsQueryCursor<List<?>>> executeDml(
+        QueryDescriptor qryDesc,
+        QueryParameters qryParams,
+        QueryParserResultDml dml,
+        GridQueryCancel cancel
     ) {
-        String sqlQry = qry.getSql();
+        IndexingQueryFilter filter = (qryDesc.local() ? backupFilter(null, qryParams.partitions()) : null);
 
-        boolean loc = qry.isLocal();
+        Long qryId = registerRunningQuery(qryDesc, cancel);
 
-        IndexingQueryFilter filter = (loc ? backupFilter(null, qry.getPartitions()) : null);
+        boolean fail = false;
 
-        if (dml != null) {
-            Long qryId = registerRunningQuery(schemaName, cancel, sqlQry, loc, registerAsNewQry);
-
-            boolean fail = false;
-
-            try {
-                if (!dml.mvccEnabled() && !updateInTxAllowed && ctx.cache().context().tm().inUserTx()) {
-                    throw new IgniteSQLException("DML statements are not allowed inside a transaction over " +
-                        "cache(s) with TRANSACTIONAL atomicity mode (change atomicity mode to " +
-                        "TRANSACTIONAL_SNAPSHOT or disable this error message with system property " +
-                        "\"-DIGNITE_ALLOW_DML_INSIDE_TRANSACTION=true\")");
-                }
-
-                if (!loc)
-                    return executeUpdateDistributed(schemaName, dml , qry, cancel);
-                else {
-                    UpdateResult updRes = executeUpdate(schemaName, dml , qry, true, filter, cancel);
-
-                    return Collections.singletonList(new QueryCursorImpl<>(new Iterable<List<?>>() {
-                        @SuppressWarnings("NullableProblems")
-                        @Override public Iterator<List<?>> iterator() {
-                            return new IgniteSingletonIterator<>(Collections.singletonList(updRes.counter()));
-                        }
-                    }, cancel));
-                }
+        try {
+            if (!dml.mvccEnabled() && !updateInTxAllowed && ctx.cache().context().tm().inUserTx()) {
+                throw new IgniteSQLException("DML statements are not allowed inside a transaction over " +
+                    "cache(s) with TRANSACTIONAL atomicity mode (change atomicity mode to " +
+                    "TRANSACTIONAL_SNAPSHOT or disable this error message with system property " +
+                    "\"-DIGNITE_ALLOW_DML_INSIDE_TRANSACTION=true\")");
             }
-            catch (IgniteCheckedException e) {
-                fail = true;
 
-                throw new IgniteSQLException("Failed to execute DML statement [stmt=" + sqlQry +
-                    ", params=" + Arrays.deepToString(qry.getArgs()) + "]", e);
+            if (!qryDesc.local()) {
+                return executeUpdateDistributed(
+                    qryDesc,
+                    qryParams,
+                    dml,
+                    cancel
+                );
             }
-            finally {
-                runningQryMgr.unregister(qryId, fail);
+            else {
+                UpdateResult updRes = executeUpdate(
+                    qryDesc,
+                    qryParams,
+                    dml,
+                    true,
+                    filter,
+                    cancel
+                );
+
+                return Collections.singletonList(new QueryCursorImpl<>(new Iterable<List<?>>() {
+                    @SuppressWarnings("NullableProblems")
+                    @Override public Iterator<List<?>> iterator() {
+                        return new IgniteSingletonIterator<>(Collections.singletonList(updRes.counter()));
+                    }
+                }, cancel));
             }
         }
+        catch (IgniteCheckedException e) {
+            fail = true;
 
-        // Execute SQL.
+            throw new IgniteSQLException("Failed to execute DML statement [stmt=" + qryDesc.sql() +
+                ", params=" + Arrays.deepToString(qryParams.arguments()) + "]", e);
+        }
+        finally {
+            runningQryMgr.unregister(qryId, fail);
+        }
+    }
+
+    /**
+     * Execute an all-ready {@link SqlFieldsQuery}.
+     *
+     * @param qryDesc Plan key.
+     * @param qryParams Parameters.
+     * @param select Select.
+     * @param keepBinary Whether binary objects must not be deserialized automatically.
+     * @param cancel Query cancel state holder.
+     * @return Query result.
+     */
+    private List<? extends FieldsQueryCursor<List<?>>> executeSelect(
+        QueryDescriptor qryDesc,
+        QueryParameters qryParams,
+        QueryParserResultSelect select,
+        boolean keepBinary,
+        GridQueryCancel cancel
+    ) {
+        if (cancel == null)
+            cancel = new GridQueryCancel();
+
+        // Check security.
+        if (ctx.security().enabled())
+            checkSecurity(select.cacheIds());
+
+        // Register query.
+        Long qryId = registerRunningQuery(qryDesc, cancel);
+
+        try {
+            Iterable<List<?>> iter = executeSelect0(qryDesc, qryParams, select, keepBinary, null, cancel);
+
+            QueryCursorImpl<List<?>> cursor = qryId != null
+                ? new RegisteredQueryCursor<>(iter, cancel, runningQueryManager(), qryId)
+                : new QueryCursorImpl<>(iter, cancel);
+
+            cursor.fieldsMeta(select.meta());
+
+            return Collections.singletonList(cursor);
+        }
+        catch (Exception e) {
+            runningQryMgr.unregister(qryId, true);
+
+            throw new IgniteSQLException("Failed to execute SELECT statement: " + qryDesc.sql(), e);
+        }
+    }
+
+    /**
+     * Execute SELECT statement for DML.
+     *
+     * @param schema Schema.
+     * @param selectQry Select query.
+     * @param mvccTracker MVCC tracker.
+     * @param cancel Cancel.
+     * @return Fields query.
+     */
+    private QueryCursorImpl<List<?>> executeSelectForDml(
+        String schema,
+        SqlFieldsQuery selectQry,
+        MvccQueryTracker mvccTracker,
+        GridQueryCancel cancel
+    ) throws IgniteCheckedException {
+        QueryParserResult parseRes = parser.parse(schema, selectQry, false);
+
+        QueryParserResultSelect select = parseRes.select();
+
         assert select != null;
 
+        Iterable<List<?>> iter = executeSelect0(
+            parseRes.queryDescriptor(),
+            parseRes.queryParameters(),
+            select,
+            true,
+            mvccTracker,
+            cancel
+        );
+
+        QueryCursorImpl<List<?>> cursor = new QueryCursorImpl<>(iter, cancel);
+
+        cursor.fieldsMeta(select.meta());
+
+        return cursor;
+    }
+
+    /**
+     * Execute an all-ready {@link SqlFieldsQuery}.
+     *
+     * @param qryDesc Plan key.
+     * @param qryParams Parameters.
+     * @param select Select.
+     * @param keepBinary Whether binary objects must not be deserialized automatically.
+     * @param mvccTracker MVCC tracker.
+     * @param cancel Query cancel state holder.
+     * @return Query result.
+     */
+    private Iterable<List<?>> executeSelect0(
+        QueryDescriptor qryDesc,
+        QueryParameters qryParams,
+        QueryParserResultSelect select,
+        boolean keepBinary,
+        MvccQueryTracker mvccTracker,
+        GridQueryCancel cancel
+    ) throws IgniteCheckedException {
+        if (ctx.security().enabled())
+            checkSecurity(select.cacheIds());
+
+        boolean autoStartTx = mvccEnabled(ctx) && !qryParams.autoCommit() && tx(ctx) == null;
+
+        Iterable<List<?>> iter;
+
         if (select.splitNeeded()) {
             // Distributed query.
             GridCacheTwoStepQuery twoStepQry = select.twoStepQuery();
 
             assert twoStepQry != null;
 
-            if (ctx.security().enabled())
-                checkSecurity(twoStepQry.cacheIds());
-
-            FieldsQueryCursor<List<?>> res = executeQueryWithSplit(
-                schemaName,
-                qry,
+            iter = executeSelectDistributed(
+                qryDesc,
+                qryParams,
                 twoStepQry,
-                select.meta(),
                 keepBinary,
-                startTx,
+                autoStartTx,
                 mvccTracker,
-                cancel,
-                registerAsNewQry
+                cancel
             );
-
-            return Collections.singletonList(res);
         }
         else {
             // Local query.
-            Long qryId = registerRunningQuery(schemaName, cancel, sqlQry, loc, registerAsNewQry);
+            IndexingQueryFilter filter = (qryDesc.local() ? backupFilter(null, qryParams.partitions()) : null);
 
-            try {
-                FieldsQueryCursor<List<?>> res = executeQueryLocal(
-                    schemaName,
-                    qry,
-                    select.meta(),
-                    keepBinary,
-                    filter,
-                    cancel,
-                    qryId
-                );
+            GridQueryFieldsResult res = executeSelectLocal(
+                qryDesc,
+                qryParams,
+                select,
+                filter,
+                autoStartTx,
+                mvccTracker,
+                cancel
+            );
 
-                return Collections.singletonList(res);
-            }
-            catch (IgniteCheckedException e) {
-                runningQryMgr.unregister(qryId, true);
-
-                throw new IgniteSQLException("Failed to execute local statement [stmt=" + sqlQry +
-                    ", params=" + Arrays.deepToString(qry.getArgs()) + "]", e);
-            }
+            iter = () -> {
+                try {
+                    return new GridQueryCacheObjectsIterator(res.iterator(), objectContext(), keepBinary);
+                }
+                catch (IgniteCheckedException e) {
+                    throw new IgniteException(e);
+                }
+            };
         }
+
+        return iter;
     }
 
     /**
-     * @param schemaName Schema name.
+     * Register running query.
+     *
+     * @param qryDesc Query descriptor.
      * @param cancel Query cancel state holder.
-     * @param qry Query.
-     * @param loc {@code true} for local query.
-     * @param registerAsNewQry {@code true} In case it's new query which should be registered as running query,
      * @return Id of registered query or {@code null} if query wasn't registered.
      */
-    private Long registerRunningQuery(String schemaName, GridQueryCancel cancel, String qry, boolean loc,
-        boolean registerAsNewQry) {
-        if (registerAsNewQry)
-            return runningQryMgr.register(qry, GridCacheQueryType.SQL_FIELDS, schemaName, loc, cancel);
-
-        return null;
+    private Long registerRunningQuery(QueryDescriptor qryDesc, GridQueryCancel cancel) {
+        return runningQryMgr.register(
+            qryDesc.sql(),
+            GridCacheQueryType.SQL_FIELDS,
+            qryDesc.schemaName(),
+            qryDesc.local(),
+            cancel
+        );
     }
 
     /**
@@ -1479,18 +1510,6 @@
         }
     }
 
-    /**
-     * @param qry Sql fields query.autoStartTx(qry)
-     * @return {@code True} if need to start transaction.
-     */
-    @SuppressWarnings("SimplifiableIfStatement")
-    private boolean autoStartTx(SqlFieldsQuery qry) {
-        if (!mvccEnabled(ctx))
-            return false;
-
-        return qry instanceof SqlFieldsQueryEx && !((SqlFieldsQueryEx)qry).isAutoCommit() && tx(ctx) == null;
-    }
-
     /** {@inheritDoc} */
     @Override public UpdateSourceIterator<?> executeUpdateOnDataNodeTransactional(
         GridCacheContext<?, ?> cctx,
@@ -1549,44 +1568,40 @@
         // Force keepBinary for operation context to avoid binary deserialization inside entry processor
         DmlUtils.setKeepBinaryContext(planCctx);
 
+        SqlFieldsQuery selectFieldsQry = new SqlFieldsQuery(plan.selectQuery(), fldsQry.isCollocated())
+            .setArgs(fldsQry.getArgs())
+            .setDistributedJoins(fldsQry.isDistributedJoins())
+            .setEnforceJoinOrder(fldsQry.isEnforceJoinOrder())
+            .setLocal(fldsQry.isLocal())
+            .setPageSize(fldsQry.getPageSize())
+            .setTimeout(fldsQry.getTimeout(), TimeUnit.MILLISECONDS)
+            .setDataPageScanEnabled(fldsQry.isDataPageScanEnabled());
+
         QueryCursorImpl<List<?>> cur;
 
         // Do a two-step query only if locality flag is not set AND if plan's SELECT corresponds to an actual
         // sub-query and not some dummy stuff like "select 1, 2, 3;"
         if (!loc && !plan.isLocalSubquery()) {
-            SqlFieldsQuery newFieldsQry = new SqlFieldsQuery(plan.selectQuery(), fldsQry.isCollocated())
-                .setArgs(fldsQry.getArgs())
-                .setDistributedJoins(fldsQry.isDistributedJoins())
-                .setEnforceJoinOrder(fldsQry.isEnforceJoinOrder())
-                .setLocal(fldsQry.isLocal())
-                .setPageSize(fldsQry.getPageSize())
-                .setTimeout(fldsQry.getTimeout(), TimeUnit.MILLISECONDS)
-                .setDataPageScanEnabled(fldsQry.isDataPageScanEnabled());
-
-            cur = (QueryCursorImpl<List<?>>)querySqlFields(
+            cur = executeSelectForDml(
                 schema,
-                newFieldsQry,
-                null,
-                true,
-                true,
+                selectFieldsQry,
                 new StaticMvccQueryTracker(planCctx, mvccSnapshot),
-                cancel,
-                false
-            ).get(0);
+                cancel
+            );
         }
         else {
-            GridQueryFieldsResult res = executeQueryLocal0(
-                schema,
-                plan.selectQuery(),
-                F.asList(fldsQry.getArgs()),
-                null,
+            selectFieldsQry.setLocal(true);
+
+            QueryParserResult selectParseRes = parser.parse(schema, selectFieldsQry, false);
+
+            GridQueryFieldsResult res = executeSelectLocal(
+                selectParseRes.queryDescriptor(),
+                selectParseRes.queryParameters(),
+                selectParseRes.select(),
                 filter,
-                fldsQry.isEnforceJoinOrder(),
                 false,
-                fldsQry.getTimeout(),
-                cancel,
                 new StaticMvccQueryTracker(planCctx, mvccSnapshot),
-                null
+                cancel
             );
 
             cur = new QueryCursorImpl<>(new Iterable<List<?>>() {
@@ -1607,88 +1622,73 @@
 
     /**
      * Run distributed query on detected set of partitions.
-     * @param schemaName Schema name.
-     * @param qry Original query.
+     *
+     * @param qryDesc Query descriptor.
+     * @param qryParams Query parameters.
      * @param twoStepQry Two-step query.
-     * @param meta Metadata to set to cursor.
      * @param keepBinary Keep binary flag.
-     * @param startTx Start transaction flag.
+     * @param autoStartTx Start transaction flag.
      * @param mvccTracker Query tracker.
      * @param cancel Cancel handler.
-     * @param registerAsNewQry {@code true} In case it's new query which should be registered as running query,
      * @return Cursor representing distributed query result.
      */
-    private FieldsQueryCursor<List<?>> executeQueryWithSplit(String schemaName, SqlFieldsQuery qry,
-        GridCacheTwoStepQuery twoStepQry, List<GridQueryFieldMetadata> meta, boolean keepBinary,
-        boolean startTx, MvccQueryTracker mvccTracker, GridQueryCancel cancel, boolean registerAsNewQry) {
-        if (log.isDebugEnabled())
-            log.debug("Parsed query: `" + qry.getSql() + "` into two step query: " + twoStepQry);
+    @SuppressWarnings("IfMayBeConditional")
+    private Iterable<List<?>> executeSelectDistributed(
+        QueryDescriptor qryDesc,
+        QueryParameters qryParams,
+        GridCacheTwoStepQuery twoStepQry,
+        boolean keepBinary,
+        boolean autoStartTx,
+        MvccQueryTracker mvccTracker,
+        GridQueryCancel cancel
+    ) {
+        // When explicit partitions are set, there must be an owning cache they should be applied to.
+        PartitionResult derivedParts = twoStepQry.derivedPartitions();
 
-        if (cancel == null)
-            cancel = new GridQueryCancel();
+        int parts[] = PartitionResult.calculatePartitions(
+            qryParams.partitions(),
+            derivedParts,
+            qryParams.arguments()
+        );
 
-        Long qryId = registerRunningQuery(schemaName, cancel, qry.getSql(), qry.isLocal(), registerAsNewQry);
+        Iterable<List<?>> iter;
 
-        boolean cursorCreated = false;
-        boolean failed = true;
+        if (parts != null && parts.length == 0) {
+            iter = new Iterable<List<?>>() {
+                @SuppressWarnings("NullableProblems")
+                @Override public Iterator<List<?>> iterator() {
+                    return new Iterator<List<?>>() {
+                        @Override public boolean hasNext() {
+                            return false;
+                        }
 
-        try {
-            // When explicit partitions are set, there must be an owning cache they should be applied to.
-            int explicitParts[] = qry.getPartitions();
-            PartitionResult derivedParts = twoStepQry.derivedPartitions();
-
-            int parts[] = PartitionResult.calculatePartitions(explicitParts, derivedParts, qry.getArgs());
-
-            if (parts != null && parts.length == 0) {
-                failed = false;
-
-                return new QueryCursorImpl<>(new Iterable<List<?>>() {
-                    @SuppressWarnings("NullableProblems")
-                    @Override public Iterator<List<?>> iterator() {
-                        return new Iterator<List<?>>() {
-                            @Override public boolean hasNext() {
-                                return false;
-                            }
-
-                            @SuppressWarnings("IteratorNextCanNotThrowNoSuchElementException")
-                            @Override public List<?> next() {
-                                return null;
-                            }
-                        };
-                    }
-                });
-            }
-
-            Iterable<List<?>> iter = runQueryTwoStep(
-                schemaName,
+                        @SuppressWarnings("IteratorNextCanNotThrowNoSuchElementException")
+                        @Override public List<?> next() {
+                            return null;
+                        }
+                    };
+                }
+            };
+        }
+        else {
+            iter = runQueryTwoStep(
+                qryDesc.schemaName(),
                 twoStepQry,
                 keepBinary,
-                qry.isEnforceJoinOrder(),
-                startTx,
-                qry.getTimeout(),
+                qryDesc.enforceJoinOrder(),
+                autoStartTx,
+                qryParams.timeout(),
                 cancel,
-                qry.getArgs(),
+                qryParams.arguments(),
                 parts,
-                qry.isLazy(),
+                qryParams.lazy(),
                 mvccTracker,
-                qry.isDataPageScanEnabled(),
-                qry.getPageSize()
+                qryParams.dataPageScanEnabled(),
+                qryParams.pageSize()
             );
-
-            QueryCursorImpl<List<?>> cursor = registerAsNewQry
-                ? new RegisteredQueryCursor<>(iter, cancel, runningQueryManager(), qryId)
-                : new QueryCursorImpl<>(iter, cancel);
-
-            cursor.fieldsMeta(meta);
-
-            cursorCreated = true;
-
-            return cursor;
         }
-        finally {
-            if (!cursorCreated)
-                runningQryMgr.unregister(qryId, failed);
-        }
+
+        return iter;
     }
 
     /**
@@ -1733,7 +1733,14 @@
 
         assert dml != null;
 
-        return executeUpdate(schemaName, dml, qry, loc, filter, cancel);
+        return executeUpdate(
+            parseRes.queryDescriptor(),
+            parseRes.queryParameters(),
+            dml,
+            loc,
+            filter,
+            cancel
+        );
     }
 
     /**
@@ -2260,26 +2267,24 @@
     }
 
     /**
-     * @param schemaName Schema.
+     * @param qryDesc Query descriptor.
+     * @param qryParams Query parameters.
      * @param dml DML statement.
-     * @param fieldsQry Initial query
      * @param cancel Query cancel.
      * @return Update result wrapped into {@link GridQueryFieldsResult}
      * @throws IgniteCheckedException if failed.
      */
     @SuppressWarnings("unchecked")
     private List<QueryCursorImpl<List<?>>> executeUpdateDistributed(
-        String schemaName,
+        QueryDescriptor qryDesc,
+        QueryParameters qryParams,
         QueryParserResultDml dml,
-        SqlFieldsQuery fieldsQry,
         GridQueryCancel cancel
     ) throws IgniteCheckedException {
-        if (DmlUtils.isBatched(fieldsQry)) {
-            SqlFieldsQueryEx fieldsQry0 = (SqlFieldsQueryEx)fieldsQry;
-
+        if (qryDesc.batched()) {
             Collection<UpdateResult> ress;
 
-            List<Object[]> argss = fieldsQry0.batchedArguments();
+            List<Object[]> argss = qryParams.batchedArguments();
 
             UpdatePlan plan = dml.plan();
 
@@ -2292,7 +2297,7 @@
                 try {
                     List<List<List<?>>> cur = plan.createRows(argss);
 
-                    ress = DmlUtils.processSelectResultBatched(plan, cur, fieldsQry0.getPageSize());
+                    ress = DmlUtils.processSelectResultBatched(plan, cur, qryParams.pageSize());
                 }
                 finally {
                     DmlUtils.restoreKeepBinaryContext(cctx, opCtx);
@@ -2309,15 +2314,17 @@
                 int cntr = 0;
 
                 for (Object[] args : argss) {
-                    SqlFieldsQueryEx qry0 = (SqlFieldsQueryEx)fieldsQry0.copy();
-
-                    qry0.clearBatchedArgs();
-                    qry0.setArgs(args);
-
                     UpdateResult res;
 
                     try {
-                        res = executeUpdate(schemaName, dml, qry0, false, null, cancel);
+                        res = executeUpdate(
+                            qryDesc,
+                            qryParams.toSingleBatchedArguments(args),
+                            dml,
+                            false,
+                            null,
+                            cancel
+                        );
 
                         cntPerRow[cntr++] = (int)res.counter();
 
@@ -2356,7 +2363,14 @@
             return resCurs;
         }
         else {
-            UpdateResult res = executeUpdate(schemaName, dml, fieldsQry, false, null, cancel);
+            UpdateResult res = executeUpdate(
+                qryDesc,
+                qryParams,
+                dml,
+                false,
+                null,
+                cancel
+            );
 
             res.throwIfError();
 
@@ -2372,19 +2386,20 @@
     /**
      * Execute DML statement, possibly with few re-attempts in case of concurrent data modifications.
      *
-     * @param schemaName Schema.
+     * @param qryDesc Query descriptor.
+     * @param qryParams Query parameters.
      * @param dml DML command.
-     * @param fieldsQry Original query.
      * @param loc Query locality flag.
      * @param filters Cache name and key filter.
      * @param cancel Cancel.
      * @return Update result (modified items count and failed keys).
      * @throws IgniteCheckedException if failed.
      */
+    @SuppressWarnings("IfMayBeConditional")
     private UpdateResult executeUpdate(
-        String schemaName,
+        QueryDescriptor qryDesc,
+        QueryParameters qryParams,
         QueryParserResultDml dml,
-        SqlFieldsQuery fieldsQry,
         boolean loc,
         IndexingQueryFilter filters,
         GridQueryCancel cancel
@@ -2393,20 +2408,39 @@
 
         long items = 0;
 
-        UpdatePlan plan = dml.plan();
+        GridCacheContext<?, ?> cctx = dml.plan().cacheContext();
 
-        GridCacheContext<?, ?> cctx = plan.cacheContext();
+        boolean transactional = cctx != null && cctx.mvccEnabled();
 
-        for (int i = 0; i < DFLT_UPDATE_RERUN_ATTEMPTS; i++) {
-            CacheOperationContext opCtx = DmlUtils.setKeepBinaryContext(cctx);
+        int maxRetryCnt = transactional ? 1 : DFLT_UPDATE_RERUN_ATTEMPTS;
+
+        for (int i = 0; i < maxRetryCnt; i++) {
+            CacheOperationContext opCtx = cctx != null ? DmlUtils.setKeepBinaryContext(cctx) : null;
 
             UpdateResult r;
 
             try {
-                r = executeUpdate0(schemaName, plan, fieldsQry, loc, filters, cancel);
+                if (transactional)
+                    r = executeUpdateTransactional(
+                        qryDesc,
+                        qryParams,
+                        dml,
+                        loc,
+                        cancel
+                    );
+                else
+                    r = executeUpdateNonTransactional(
+                        qryDesc,
+                        qryParams,
+                        dml,
+                        loc,
+                        filters,
+                        cancel
+                    );
             }
             finally {
-                DmlUtils.restoreKeepBinaryContext(cctx, opCtx);
+                if (opCtx != null)
+                    DmlUtils.restoreKeepBinaryContext(cctx, opCtx);
             }
 
             items += r.counter();
@@ -2427,185 +2461,65 @@
     }
 
     /**
-     * Actually perform SQL DML operation locally.
+     * Execute update in non-transactional mode.
      *
-     * @param schemaName Schema name.
-     * @param plan Cache context.
-     * @param fieldsQry Fields query.
-     * @param loc Local query flag.
-     * @param filters Cache name and key filter.
-     * @param cancel Query cancel state holder.
-     * @return Pair [number of successfully processed items; keys that have failed to be processed]
-     * @throws IgniteCheckedException if failed.
+     * @param qryDesc Query descriptor.
+     * @param qryParams Query parameters.
+     * @param dml Plan.
+     * @param loc Local flag.
+     * @param filters Filters.
+     * @param cancel Cancel hook.
+     * @return Update result.
+     * @throws IgniteCheckedException If failed.
      */
-    @SuppressWarnings({"ConstantConditions"})
-    private UpdateResult executeUpdate0(
-        String schemaName,
-        final UpdatePlan plan,
-        SqlFieldsQuery fieldsQry,
+    private UpdateResult executeUpdateNonTransactional(
+        QueryDescriptor qryDesc,
+        QueryParameters qryParams,
+        QueryParserResultDml dml,
         boolean loc,
         IndexingQueryFilter filters,
         GridQueryCancel cancel
     ) throws IgniteCheckedException {
-        GridCacheContext cctx = plan.cacheContext();
+        UpdatePlan plan = dml.plan();
 
-        DmlDistributedPlanInfo distributedPlan = loc ? null : plan.distributedPlan();
-
-        if (cctx != null && cctx.mvccEnabled()) {
-            assert cctx.transactional();
-
-            GridNearTxLocal tx = tx(ctx);
-
-            boolean implicit = (tx == null);
-
-            boolean commit = implicit && (!(fieldsQry instanceof SqlFieldsQueryEx) ||
-                ((SqlFieldsQueryEx)fieldsQry).isAutoCommit());
-
-            if (implicit)
-                tx = txStart(cctx, fieldsQry.getTimeout());
-
-            requestSnapshot(tx);
-
-            try (GridNearTxLocal toCommit = commit ? tx : null) {
-                long timeout = implicit
-                    ? tx.remainingTime()
-                    : operationTimeout(fieldsQry.getTimeout(), tx);
-
-                if (cctx.isReplicated() || distributedPlan == null || ((plan.mode() == UpdateMode.INSERT
-                    || plan.mode() == UpdateMode.MERGE) && !plan.isLocalSubquery())) {
-
-                    boolean sequential = true;
-
-                    UpdateSourceIterator<?> it;
-
-                    if (plan.fastResult()) {
-                        IgniteBiTuple row = plan.getFastRow(fieldsQry.getArgs());
-
-                        EnlistOperation op = UpdatePlan.enlistOperation(plan.mode());
-
-                        it = new DmlUpdateSingleEntryIterator<>(op, op.isDeleteOrLock() ? row.getKey() : row);
-                    }
-                    else if (plan.hasRows())
-                        it = new DmlUpdateResultsIterator(UpdatePlan.enlistOperation(plan.mode()), plan, plan.createRows(fieldsQry.getArgs()));
-                    else {
-                        // TODO IGNITE-8865 if there is no ORDER BY statement it's no use to retain entries order on locking (sequential = false).
-                        SqlFieldsQuery newFieldsQry = new SqlFieldsQuery(plan.selectQuery(), fieldsQry.isCollocated())
-                            .setArgs(fieldsQry.getArgs())
-                            .setDistributedJoins(fieldsQry.isDistributedJoins())
-                            .setEnforceJoinOrder(fieldsQry.isEnforceJoinOrder())
-                            .setLocal(fieldsQry.isLocal())
-                            .setPageSize(fieldsQry.getPageSize())
-                            .setTimeout((int)timeout, TimeUnit.MILLISECONDS)
-                            .setDataPageScanEnabled(fieldsQry.isDataPageScanEnabled());
-
-                        FieldsQueryCursor<List<?>> cur = querySqlFields(schemaName, newFieldsQry, null,
-                            true, true, MvccUtils.mvccTracker(cctx, tx), cancel, false).get(0);
-
-                        it = plan.iteratorForTransaction(connMgr, cur);
-                    }
-
-                    IgniteInternalFuture<Long> fut = tx.updateAsync(cctx, it,
-                        fieldsQry.getPageSize(), timeout, sequential);
-
-                    UpdateResult res = new UpdateResult(fut.get(), X.EMPTY_OBJECT_ARRAY);
-
-                    if (commit)
-                        toCommit.commit();
-
-                    return res;
-                }
-
-                int[] ids = U.toIntArray(distributedPlan.getCacheIds());
-
-                int flags = 0;
-
-                if (fieldsQry.isEnforceJoinOrder())
-                    flags |= GridH2QueryRequest.FLAG_ENFORCE_JOIN_ORDER;
-
-                if (distributedPlan.isReplicatedOnly())
-                    flags |= GridH2QueryRequest.FLAG_REPLICATED;
-
-                flags = GridH2QueryRequest.setDataPageScanEnabled(flags,
-                    fieldsQry.isDataPageScanEnabled());
-
-                int[] parts = PartitionResult.calculatePartitions(
-                    fieldsQry.getPartitions(),
-                    distributedPlan.derivedPartitions(),
-                    fieldsQry.getArgs());
-
-                if (parts != null && parts.length == 0)
-                    return new UpdateResult(0, X.EMPTY_OBJECT_ARRAY);
-                else {
-                    IgniteInternalFuture<Long> fut = tx.updateAsync(
-                        cctx,
-                        ids,
-                        parts,
-                        schemaName,
-                        fieldsQry.getSql(),
-                        fieldsQry.getArgs(),
-                        flags,
-                        fieldsQry.getPageSize(),
-                        timeout);
-
-                    UpdateResult res = new UpdateResult(fut.get(), X.EMPTY_OBJECT_ARRAY);
-
-                    if (commit)
-                        toCommit.commit();
-
-                    return res;
-                }
-            }
-            catch (ClusterTopologyServerNotFoundException e) {
-                throw new CacheServerNotFoundException(e.getMessage(), e);
-            }
-            catch (IgniteCheckedException e) {
-                IgniteSQLException sqlEx = X.cause(e, IgniteSQLException.class);
-
-                if(sqlEx != null)
-                    throw sqlEx;
-
-                Exception ex = IgniteUtils.convertExceptionNoWrap(e);
-
-                if (ex instanceof IgniteException)
-                    throw (IgniteException)ex;
-
-                U.error(log, "Error during update [localNodeId=" + ctx.localNodeId() + "]", ex);
-
-                throw new IgniteSQLException("Failed to run update. " + ex.getMessage(), ex);
-            }
-            finally {
-                if (commit)
-                    cctx.tm().resetContext();
-            }
-        }
-
-        UpdateResult fastUpdateRes = plan.processFast(fieldsQry.getArgs());
+        UpdateResult fastUpdateRes = plan.processFast(qryParams.arguments());
 
         if (fastUpdateRes != null)
             return fastUpdateRes;
 
+        DmlDistributedPlanInfo distributedPlan = loc ? null : plan.distributedPlan();
+
         if (distributedPlan != null) {
             if (cancel == null)
                 cancel = new GridQueryCancel();
 
             UpdateResult result = rdcQryExec.update(
-                schemaName,
+                qryDesc.schemaName(),
                 distributedPlan.getCacheIds(),
-                fieldsQry.getSql(),
-                fieldsQry.getArgs(),
-                fieldsQry.isEnforceJoinOrder(),
-                fieldsQry.getPageSize(),
-                fieldsQry.getTimeout(),
-                fieldsQry.getPartitions(),
+                qryDesc.sql(),
+                qryParams.arguments(),
+                qryDesc.enforceJoinOrder(),
+                qryParams.pageSize(),
+                qryParams.timeout(),
+                qryParams.partitions(),
                 distributedPlan.isReplicatedOnly(),
                 cancel
             );
 
-            // null is returned in case not all nodes support distributed DML.
+            // Null is returned in case not all nodes support distributed DML.
             if (result != null)
                 return result;
         }
 
+        SqlFieldsQuery selectFieldsQry = new SqlFieldsQuery(plan.selectQuery(), qryDesc.collocated())
+            .setArgs(qryParams.arguments())
+            .setDistributedJoins(qryDesc.distributedJoins())
+            .setEnforceJoinOrder(qryDesc.enforceJoinOrder())
+            .setLocal(qryDesc.local())
+            .setPageSize(qryParams.pageSize())
+            .setTimeout(qryParams.timeout(), TimeUnit.MILLISECONDS)
+            .setDataPageScanEnabled(qryParams.dataPageScanEnabled());
+
         Iterable<List<?>> cur;
 
         // Do a two-step query only if locality flag is not set AND if plan's SELECT corresponds to an actual
@@ -2613,32 +2527,28 @@
         if (!loc && !plan.isLocalSubquery()) {
             assert !F.isEmpty(plan.selectQuery());
 
-            SqlFieldsQuery newFieldsQry = new SqlFieldsQuery(plan.selectQuery(), fieldsQry.isCollocated())
-                .setArgs(fieldsQry.getArgs())
-                .setDistributedJoins(fieldsQry.isDistributedJoins())
-                .setEnforceJoinOrder(fieldsQry.isEnforceJoinOrder())
-                .setLocal(fieldsQry.isLocal())
-                .setPageSize(fieldsQry.getPageSize())
-                .setTimeout(fieldsQry.getTimeout(), TimeUnit.MILLISECONDS)
-                .setDataPageScanEnabled(fieldsQry.isDataPageScanEnabled());
-
-            cur = querySqlFields(schemaName, newFieldsQry, null, true, true, null, cancel, false).get(0);
+            cur = executeSelectForDml(
+                qryDesc.schemaName(),
+                selectFieldsQry,
+                null,
+                cancel
+            );
         }
         else if (plan.hasRows())
-            cur = plan.createRows(fieldsQry.getArgs());
+            cur = plan.createRows(qryParams.arguments());
         else {
-            final GridQueryFieldsResult res = executeQueryLocal0(
-                schemaName,
-                plan.selectQuery(),
-                F.asList(fieldsQry.getArgs()),
-                null,
+            selectFieldsQry.setLocal(true);
+
+            QueryParserResult selectParseRes = parser.parse(qryDesc.schemaName(), selectFieldsQry, false);
+
+            final GridQueryFieldsResult res = executeSelectLocal(
+                selectParseRes.queryDescriptor(),
+                selectParseRes.queryParameters(),
+                selectParseRes.select(),
                 filters,
-                fieldsQry.isEnforceJoinOrder(),
                 false,
-                fieldsQry.getTimeout(),
-                cancel,
                 null,
-                null
+                cancel
             );
 
             cur = new QueryCursorImpl<>(new Iterable<List<?>>() {
@@ -2654,8 +2564,176 @@
             }, cancel);
         }
 
-        int pageSize = loc ? 0 : fieldsQry.getPageSize();
+        int pageSize = loc ? 0 : qryParams.pageSize();
 
         return DmlUtils.processSelectResult(plan, cur, pageSize);
     }
+
+    /**
+     * Execute update in transactional mode.
+     *
+     * @param qryDesc Query descriptor.
+     * @param qryParams Query parameters.
+     * @param dml Plan.
+     * @param loc Local flag.
+     * @param cancel Cancel hook.
+     * @return Update result.
+     * @throws IgniteCheckedException If failed.
+     */
+    private UpdateResult executeUpdateTransactional(
+        QueryDescriptor qryDesc,
+        QueryParameters qryParams,
+        QueryParserResultDml dml,
+        boolean loc,
+        GridQueryCancel cancel
+    ) throws IgniteCheckedException {
+        UpdatePlan plan = dml.plan();
+
+        GridCacheContext cctx = plan.cacheContext();
+
+        assert cctx != null;
+        assert cctx.transactional();
+
+        GridNearTxLocal tx = tx(ctx);
+
+        boolean implicit = (tx == null);
+
+        boolean commit = implicit && qryParams.autoCommit();
+
+        if (implicit)
+            tx = txStart(cctx, qryParams.timeout());
+
+        requestSnapshot(tx);
+
+        try (GridNearTxLocal toCommit = commit ? tx : null) {
+            DmlDistributedPlanInfo distributedPlan = loc ? null : plan.distributedPlan();
+
+            long timeout = implicit
+                ? tx.remainingTime()
+                : operationTimeout(qryParams.timeout(), tx);
+
+            if (cctx.isReplicated() || distributedPlan == null || ((plan.mode() == UpdateMode.INSERT
+                || plan.mode() == UpdateMode.MERGE) && !plan.isLocalSubquery())) {
+
+                boolean sequential = true;
+
+                UpdateSourceIterator<?> it;
+
+                if (plan.fastResult()) {
+                    IgniteBiTuple row = plan.getFastRow(qryParams.arguments());
+
+                    assert row != null;
+
+                    EnlistOperation op = UpdatePlan.enlistOperation(plan.mode());
+
+                    it = new DmlUpdateSingleEntryIterator<>(op, op.isDeleteOrLock() ? row.getKey() : row);
+                }
+                else if (plan.hasRows()) {
+                    it = new DmlUpdateResultsIterator(
+                        UpdatePlan.enlistOperation(plan.mode()),
+                        plan,
+                        plan.createRows(qryParams.arguments())
+                    );
+                }
+                else {
+                    SqlFieldsQuery selectFieldsQry = new SqlFieldsQuery(plan.selectQuery(), qryDesc.collocated())
+                        .setArgs(qryParams.arguments())
+                        .setDistributedJoins(qryDesc.distributedJoins())
+                        .setEnforceJoinOrder(qryDesc.enforceJoinOrder())
+                        .setLocal(qryDesc.local())
+                        .setPageSize(qryParams.pageSize())
+                        .setTimeout((int)timeout, TimeUnit.MILLISECONDS)
+                        .setDataPageScanEnabled(qryParams.dataPageScanEnabled());
+
+                    FieldsQueryCursor<List<?>> cur = executeSelectForDml(
+                        qryDesc.schemaName(),
+                        selectFieldsQry,
+                        MvccUtils.mvccTracker(cctx, tx),
+                        cancel
+                    );
+
+                    it = plan.iteratorForTransaction(connMgr, cur);
+                }
+
+                IgniteInternalFuture<Long> fut = tx.updateAsync(
+                    cctx,
+                    it,
+                    qryParams.pageSize(),
+                    timeout,
+                    sequential
+                );
+
+                UpdateResult res = new UpdateResult(fut.get(), X.EMPTY_OBJECT_ARRAY);
+
+                if (commit)
+                    toCommit.commit();
+
+                return res;
+            }
+
+            int[] ids = U.toIntArray(distributedPlan.getCacheIds());
+
+            int flags = 0;
+
+            if (qryDesc.enforceJoinOrder())
+                flags |= GridH2QueryRequest.FLAG_ENFORCE_JOIN_ORDER;
+
+            if (distributedPlan.isReplicatedOnly())
+                flags |= GridH2QueryRequest.FLAG_REPLICATED;
+
+            flags = GridH2QueryRequest.setDataPageScanEnabled(flags,
+                qryParams.dataPageScanEnabled());
+
+            int[] parts = PartitionResult.calculatePartitions(
+                qryParams.partitions(),
+                distributedPlan.derivedPartitions(),
+                qryParams.arguments()
+            );
+
+            if (parts != null && parts.length == 0)
+                return new UpdateResult(0, X.EMPTY_OBJECT_ARRAY);
+            else {
+                IgniteInternalFuture<Long> fut = tx.updateAsync(
+                    cctx,
+                    ids,
+                    parts,
+                    qryDesc.schemaName(),
+                    qryDesc.sql(),
+                    qryParams.arguments(),
+                    flags,
+                    qryParams.pageSize(),
+                    timeout
+                );
+
+                UpdateResult res = new UpdateResult(fut.get(), X.EMPTY_OBJECT_ARRAY);
+
+                if (commit)
+                    toCommit.commit();
+
+                return res;
+            }
+        }
+        catch (ClusterTopologyServerNotFoundException e) {
+            throw new CacheServerNotFoundException(e.getMessage(), e);
+        }
+        catch (IgniteCheckedException e) {
+            IgniteSQLException sqlEx = X.cause(e, IgniteSQLException.class);
+
+            if(sqlEx != null)
+                throw sqlEx;
+
+            Exception ex = IgniteUtils.convertExceptionNoWrap(e);
+
+            if (ex instanceof IgniteException)
+                throw (IgniteException)ex;
+
+            U.error(log, "Error during update [localNodeId=" + ctx.localNodeId() + "]", ex);
+
+            throw new IgniteSQLException("Failed to run update. " + ex.getMessage(), ex);
+        }
+        finally {
+            if (commit)
+                cctx.tm().resetContext();
+        }
+    }
 }
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/QueryDescriptor.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/QueryDescriptor.java
new file mode 100644
index 0000000..2b1ceaf
--- /dev/null
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/QueryDescriptor.java
@@ -0,0 +1,181 @@
+/*
+ * 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;
+
+/**
+ * Key for cached two-step query.
+ */
+public class QueryDescriptor {
+    /** */
+    private final String schemaName;
+
+    /** */
+    private final String sql;
+
+    /** */
+    private final boolean collocated;
+
+    /** */
+    private final boolean distributedJoins;
+
+    /** */
+    private final boolean enforceJoinOrder;
+
+    /** */
+    private final boolean loc;
+
+    /** Skip reducer on update flag. */
+    private final boolean skipReducerOnUpdate;
+
+    /** Batched flag. */
+    private final boolean batched;
+
+    /**
+     * @param schemaName Schema name.
+     * @param sql Sql.
+     * @param collocated Collocated GROUP BY.
+     * @param distributedJoins Distributed joins enabled.
+     * @param enforceJoinOrder Enforce join order of tables.
+     * @param loc Query is local flag.
+     * @param skipReducerOnUpdate Skip reducer on update flag.
+     */
+    QueryDescriptor(
+        String schemaName,
+        String sql,
+        boolean collocated,
+        boolean distributedJoins,
+        boolean enforceJoinOrder,
+        boolean loc,
+        boolean skipReducerOnUpdate,
+        boolean batched
+    ) {
+        this.schemaName = schemaName;
+        this.sql = sql;
+        this.collocated = collocated;
+        this.distributedJoins = distributedJoins;
+        this.enforceJoinOrder = enforceJoinOrder;
+        this.loc = loc;
+        this.skipReducerOnUpdate = skipReducerOnUpdate;
+        this.batched = batched;
+    }
+
+    /**
+     * @return Schema name.
+     */
+    public String schemaName() {
+        return schemaName;
+    }
+
+    /**
+     * @return SQL.
+     */
+    public String sql() {
+        return sql;
+    }
+
+    /**
+     * @return Collocated GROUP BY flag.
+     */
+    public boolean collocated() {
+        return collocated;
+    }
+
+    /**
+     * @return Distributed joins flag.
+     */
+    public boolean distributedJoins() {
+        return distributedJoins;
+    }
+
+    /**
+     * @return Enforce join order flag.
+     */
+    public boolean enforceJoinOrder() {
+        return enforceJoinOrder;
+    }
+
+    /**
+     * @return Local flag.
+     */
+    public boolean local() {
+        return loc;
+    }
+
+    /**
+     * @return Skip reducer on update flag.
+     */
+    public boolean skipReducerOnUpdate() {
+        return skipReducerOnUpdate;
+    }
+
+    /**
+     * @return Batched flag.
+     */
+    public boolean batched() {
+        return batched;
+    }
+
+    /** {@inheritDoc} */
+    @SuppressWarnings("SimplifiableIfStatement")
+    @Override public boolean equals(Object o) {
+        if (this == o)
+            return true;
+
+        if (o == null || getClass() != o.getClass())
+            return false;
+
+        QueryDescriptor that = (QueryDescriptor)o;
+
+        if (collocated != that.collocated)
+            return false;
+
+        if (distributedJoins != that.distributedJoins)
+            return false;
+
+        if (enforceJoinOrder != that.enforceJoinOrder)
+            return false;
+
+        if (skipReducerOnUpdate != that.skipReducerOnUpdate)
+            return false;
+
+        if (batched != that.batched)
+            return false;
+
+        if (schemaName != null ? !schemaName.equals(that.schemaName) : that.schemaName != null)
+            return false;
+
+        return loc == that.loc && sql.equals(that.sql);
+    }
+
+    /** {@inheritDoc} */
+    @SuppressWarnings("AssignmentReplaceableWithOperatorAssignment")
+    @Override public int hashCode() {
+        int res = schemaName != null ? schemaName.hashCode() : 0;
+
+        res = 31 * res + sql.hashCode();
+        res = 31 * res + (collocated ? 1 : 0);
+
+        res = res + (distributedJoins ? 2 : 0);
+        res = res + (enforceJoinOrder ? 4 : 0);
+        res = res + (loc ? 8 : 0);
+        res = res + (skipReducerOnUpdate ? 16 : 0);
+        res = res + (batched ? 32 : 0);
+
+        return res;
+    }
+}
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/QueryParameters.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/QueryParameters.java
new file mode 100644
index 0000000..72c0626
--- /dev/null
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/QueryParameters.java
@@ -0,0 +1,215 @@
+/*
+ * 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;
+
+import org.apache.ignite.cache.query.SqlFieldsQuery;
+import org.apache.ignite.internal.processors.cache.query.SqlFieldsQueryEx;
+import org.apache.ignite.internal.processors.query.NestedTxMode;
+
+import java.util.List;
+
+/**
+ * Query parameters which vary between requests having the same execution plan. Essentially, these are the arguments
+ * of original {@link org.apache.ignite.cache.query.SqlFieldsQuery} which are not part of {@link QueryDescriptor}.
+ */
+public class QueryParameters {
+    /** Arguments. */
+    private final Object[] args;
+
+    /** Partitions. */
+    private final int[] parts;
+
+    /** Timeout. */
+    private final int timeout;
+
+    /** Lazy flag. */
+    private final boolean lazy;
+
+    /** Page size. */
+    private final int pageSize;
+
+    /** Data page scan enabled flag. */
+    private final Boolean dataPageScanEnabled;
+
+    /** Nexted transactional mode. */
+    private final NestedTxMode nestedTxMode;
+
+    /** Auto-commit flag. */
+    private final boolean autoCommit;
+
+    /** Batched arguments. */
+    private final List<Object[]> batchedArgs;
+
+    /**
+     * Create parameters from query.
+     *
+     * @param qry Query.
+     * @return Parameters.
+     */
+    public static QueryParameters fromQuery(SqlFieldsQuery qry) {
+        NestedTxMode nestedTxMode = NestedTxMode.DEFAULT;
+        boolean autoCommit = true;
+        List<Object[]> batchedArgs = null;
+
+        if (qry instanceof SqlFieldsQueryEx) {
+            SqlFieldsQueryEx qry0 = (SqlFieldsQueryEx)qry;
+
+            if (qry0.getNestedTxMode() != null)
+                nestedTxMode = qry0.getNestedTxMode();
+
+            autoCommit = qry0.isAutoCommit();
+
+            batchedArgs = qry0.batchedArguments();
+        }
+
+        return new QueryParameters(
+            qry.getArgs(),
+            qry.getPartitions(),
+            qry.getTimeout(),
+            qry.isLazy(),
+            qry.getPageSize(),
+            qry.isDataPageScanEnabled(),
+            nestedTxMode,
+            autoCommit,
+            batchedArgs
+        );
+    }
+
+    /**
+     * Constructor.
+     *
+     * @param args Arguments.
+     * @param parts Partitions.
+     * @param timeout Timeout.
+     * @param lazy Lazy flag.
+     * @param pageSize Page size.
+     * @param dataPageScanEnabled Data page scan enabled flag.
+     * @param nestedTxMode Nested TX mode.
+     * @param autoCommit Auto-commit flag.
+     * @param batchedArgs Batched arguments.
+     */
+    @SuppressWarnings("AssignmentOrReturnOfFieldWithMutableType")
+    private QueryParameters(
+        Object[] args,
+        int[] parts,
+        int timeout,
+        boolean lazy,
+        int pageSize,
+        Boolean dataPageScanEnabled,
+        NestedTxMode nestedTxMode,
+        boolean autoCommit,
+        List<Object[]> batchedArgs
+    ) {
+        this.args = args;
+        this.parts = parts;
+        this.timeout = timeout;
+        this.lazy = lazy;
+        this.pageSize = pageSize;
+        this.dataPageScanEnabled = dataPageScanEnabled;
+        this.nestedTxMode = nestedTxMode;
+        this.autoCommit = autoCommit;
+        this.batchedArgs = batchedArgs;
+    }
+
+    /**
+     * @return Arguments.
+     */
+    @SuppressWarnings("AssignmentOrReturnOfFieldWithMutableType")
+    public Object[] arguments() {
+        return args;
+    }
+
+    /**
+     * @return Partitions.
+     */
+    @SuppressWarnings("AssignmentOrReturnOfFieldWithMutableType")
+    public int[] partitions() {
+        return parts;
+    }
+
+    /**
+     * @return Timeout.
+     */
+    public int timeout() {
+        return timeout;
+    }
+
+    /**
+     * @return Lazy flag.
+     */
+    public boolean lazy() {
+        return lazy;
+    }
+
+    /**
+     * @return Page size.
+     */
+    public int pageSize() {
+        return pageSize;
+    }
+
+    /**
+     * @return Data page scan enabled flag.
+     */
+    public Boolean dataPageScanEnabled() {
+        return dataPageScanEnabled;
+    }
+
+    /**
+     * @return Nested TX mode.
+     */
+    public NestedTxMode nestedTxMode() {
+        return nestedTxMode;
+    }
+
+    /**
+     * @return Auto-commit flag.
+     */
+    public boolean autoCommit() {
+        return autoCommit;
+    }
+
+    /**
+     * @return Batched arguments.
+     */
+    @SuppressWarnings("AssignmentOrReturnOfFieldWithMutableType")
+    public List<Object[]> batchedArguments() {
+        return batchedArgs;
+    }
+
+    /**
+     * Convert current batched arguments to a form with single arguments.
+     *
+     * @param args Arguments.
+     * @return Result.
+     */
+    public QueryParameters toSingleBatchedArguments(Object[] args) {
+        return new QueryParameters(
+            args,
+            this.parts,
+            this.timeout,
+            this.lazy,
+            this.pageSize,
+            this.dataPageScanEnabled,
+            this.nestedTxMode,
+            this.autoCommit,
+            null
+        );
+    }
+}
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/QueryParser.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/QueryParser.java
index fcb6558..89c5e49 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/QueryParser.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/QueryParser.java
@@ -32,7 +32,6 @@
 import org.apache.ignite.internal.processors.query.IgniteSQLException;
 import org.apache.ignite.internal.processors.query.QueryUtils;
 import org.apache.ignite.internal.processors.query.h2.dml.DmlAstUtils;
-import org.apache.ignite.internal.processors.query.h2.dml.DmlUtils;
 import org.apache.ignite.internal.processors.query.h2.dml.UpdatePlan;
 import org.apache.ignite.internal.processors.query.h2.dml.UpdatePlanBuilder;
 import org.apache.ignite.internal.processors.query.h2.opt.GridH2Table;
@@ -94,7 +93,7 @@
     private final IgniteLogger log;
 
     /** */
-    private volatile GridBoundedConcurrentLinkedHashMap<QueryParserCacheKey, QueryParserCacheEntry> cache =
+    private volatile GridBoundedConcurrentLinkedHashMap<QueryDescriptor, QueryParserCacheEntry> cache =
         new GridBoundedConcurrentLinkedHashMap<>(CACHE_SIZE);
 
     /**
@@ -135,33 +134,32 @@
      * @return Parsing result that contains Parsed leading query and remaining sql script.
      */
     private QueryParserResult parse0(String schemaName, SqlFieldsQuery qry, boolean remainingAllowed) {
-        // First, let's check if we already have a two-step query for this statement...
-        QueryParserCacheKey cachedKey = new QueryParserCacheKey(
-            schemaName,
-            qry.getSql(),
-            qry.isCollocated(),
-            qry.isDistributedJoins(),
-            qry.isEnforceJoinOrder(),
-            qry.isLocal()
-        );
+        QueryDescriptor qryDesc = queryDescriptor(schemaName, qry);
 
-        QueryParserCacheEntry cached = cache.get(cachedKey);
+        QueryParserCacheEntry cached = cache.get(qryDesc);
 
         if (cached != null) 
-            return new QueryParserResult(qry, null, cached.select(), cached.dml(), cached.command());
+            return new QueryParserResult(
+                qryDesc,
+                QueryParameters.fromQuery(qry),
+                null,
+                cached.select(),
+                cached.dml(),
+                cached.command()
+            );
 
         // Try parting as native command.
         QueryParserResult parseRes = parseNative(schemaName, qry, remainingAllowed);
 
         // Otherwise parse with H2.
         if (parseRes == null)
-            parseRes = parseH2(schemaName, qry, remainingAllowed);
+            parseRes = parseH2(schemaName, qry, qryDesc.batched(), remainingAllowed);
 
         // Add to cache if not multi-statement.
         if (parseRes.remainingQuery() == null) {
             cached = new QueryParserCacheEntry(parseRes.select(), parseRes.dml(), parseRes.command());
 
-            cache.put(cachedKey, cached);
+            cache.put(qryDesc, cached);
         }
 
         // Done.
@@ -209,6 +207,8 @@
 
             SqlFieldsQuery newQry = cloneFieldsQuery(qry).setSql(parser.lastCommandSql());
 
+            QueryDescriptor newPlanKey = queryDescriptor(schemaName, newQry);
+
             SqlFieldsQuery remainingQry = null;
             
             if (!F.isEmpty(parser.remainingSql())) {
@@ -219,7 +219,14 @@
 
             QueryParserResultCommand cmd = new QueryParserResultCommand(nativeCmd, null, false);
 
-            return new QueryParserResult(newQry, remainingQry, null, null, cmd);
+            return new QueryParserResult(
+                newPlanKey,
+                QueryParameters.fromQuery(newQry),
+                remainingQry,
+                null,
+                null,
+                cmd
+            );
         }
         catch (SqlStrictParseException e) {
             throw new IgniteSQLException(e.getMessage(), IgniteQueryErrorCode.PARSING, e);
@@ -246,11 +253,13 @@
      *
      * @param schemaName Schema name.
      * @param qry Query.
+     * @param batched Batched flag.
      * @param remainingAllowed Whether multiple statements are allowed.              
      * @return Parsing result.
      */
     @SuppressWarnings("IfMayBeConditional")
-    private QueryParserResult parseH2(String schemaName, SqlFieldsQuery qry, boolean remainingAllowed) {
+    private QueryParserResult parseH2(String schemaName, SqlFieldsQuery qry, boolean batched,
+        boolean remainingAllowed) {
         Connection c = connMgr.connectionForThread().connection(schemaName);
 
         // For queries that are explicitly local, we rely on the flag specified in the query
@@ -303,7 +312,7 @@
             Object[] args = null;
             Object[] remainingArgs = null;
 
-            if (!DmlUtils.isBatched(qry) && paramsCnt > 0) {
+            if (!batched && paramsCnt > 0) {
                 if (argsOrig == null || argsOrig.length < paramsCnt)
                     // Not enough parameters, but we will handle this later on execution phase.
                     args = argsOrig;
@@ -319,6 +328,8 @@
 
             newQry.setArgs(args);
 
+            QueryDescriptor newQryDesc = queryDescriptor(schemaName, newQry);
+
             if (remainingQry != null)
                 remainingQry.setArgs(remainingArgs);
 
@@ -328,17 +339,38 @@
 
                 QueryParserResultCommand cmd = new QueryParserResultCommand(null, cmdH2, false);
 
-                return new QueryParserResult(newQry, remainingQry, null, null, cmd);
+                return new QueryParserResult(
+                    newQryDesc,
+                    QueryParameters.fromQuery(newQry),
+                    remainingQry,
+                    null,
+                    null,
+                    cmd
+                );
             }
             else if (CommandProcessor.isCommandNoOp(prepared)) {
                 QueryParserResultCommand cmd = new QueryParserResultCommand(null, null, true);
 
-                return new QueryParserResult(newQry, remainingQry, null, null, cmd);
+                return new QueryParserResult(
+                    newQryDesc,
+                    QueryParameters.fromQuery(newQry),
+                    remainingQry,
+                    null,
+                    null,
+                    cmd
+                );
             }
             else if (GridSqlQueryParser.isDml(prepared)) {
-                QueryParserResultDml dml = prepareDmlStatement(schemaName, qry, prepared);
+                QueryParserResultDml dml = prepareDmlStatement(newQryDesc, prepared);
 
-                return new QueryParserResult(newQry, remainingQry, null, dml, null);
+                return new QueryParserResult(
+                    newQryDesc,
+                    QueryParameters.fromQuery(newQry),
+                    remainingQry,
+                    null,
+                    dml,
+                    null
+                );
             }
             else if (!prepared.isQuery()) {
                 throw new IgniteSQLException("Unsupported statement: " + newQry.getSql(),
@@ -405,7 +437,14 @@
                     forUpdate
                 );
 
-                return new QueryParserResult(newQry, remainingQry, select, null, null);
+                return new QueryParserResult(
+                    newQryDesc,
+                    QueryParameters.fromQuery(newQry),
+                    remainingQry,
+                    select,
+                    null,
+                    null
+                );
             }
             catch (IgniteCheckedException e) {
                 throw new IgniteSQLException("Failed to parse query: " + newQry.getSql(), IgniteQueryErrorCode.PARSING,
@@ -478,14 +517,13 @@
     /**
      * Prepare DML statement.
      *
-     * @param schemaName Schema name.
-     * @param qry Query.
+     * @param planKey Plan key.
      * @param prepared Prepared.
      * @return Statement.
      */
-    private QueryParserResultDml prepareDmlStatement(String schemaName, SqlFieldsQuery qry, Prepared prepared) {
-        if (F.eq(QueryUtils.SCHEMA_SYS, schemaName))
-            throw new IgniteSQLException("DML statements are not supported on " + schemaName + " schema",
+    private QueryParserResultDml prepareDmlStatement(QueryDescriptor planKey, Prepared prepared) {
+        if (F.eq(QueryUtils.SCHEMA_SYS, planKey.schemaName()))
+            throw new IgniteSQLException("DML statements are not supported on " + planKey.schemaName() + " schema",
                 IgniteQueryErrorCode.UNSUPPORTED_OPERATION);
 
         // Prepare AST.
@@ -532,11 +570,10 @@
 
         try {
             plan = UpdatePlanBuilder.planForStatement(
-                schemaName,
+                planKey,
                 stmt,
                 mvccEnabled,
-                idx,
-                qry
+                idx
             );
         }
         catch (Exception e) {
@@ -585,4 +622,34 @@
     private static SqlFieldsQuery cloneFieldsQuery(SqlFieldsQuery oldQry) {
         return oldQry.copy().setLocal(oldQry.isLocal()).setPageSize(oldQry.getPageSize());
     }
+
+    /**
+     * Prepare plan key.
+     *
+     * @param schemaName Schema name.
+     * @param qry Query.
+     * @return Plan key.
+     */
+    private static QueryDescriptor queryDescriptor(String schemaName, SqlFieldsQuery qry) {
+        boolean skipReducerOnUpdate = false;
+        boolean batched = false;
+
+        if (qry instanceof SqlFieldsQueryEx) {
+            SqlFieldsQueryEx qry0 = (SqlFieldsQueryEx)qry;
+
+            skipReducerOnUpdate = !qry.isLocal() && qry0.isSkipReducerOnUpdate();
+            batched = qry0.isBatched();
+        }
+
+        return new QueryDescriptor(
+            schemaName,
+            qry.getSql(),
+            qry.isCollocated(),
+            qry.isDistributedJoins(),
+            qry.isEnforceJoinOrder(),
+            qry.isLocal(),
+            skipReducerOnUpdate,
+            batched
+        );
+    }
 }
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/QueryParserCacheKey.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/QueryParserCacheKey.java
deleted file mode 100644
index 21bf405..0000000
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/QueryParserCacheKey.java
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * 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;
-
-/**
- * Key for cached two-step query.
- */
-public class QueryParserCacheKey {
-    /** */
-    private final String schemaName;
-
-    /** */
-    private final String sql;
-
-    /** */
-    private final boolean grpByCollocated;
-
-    /** */
-    private final boolean distributedJoins;
-
-    /** */
-    private final boolean enforceJoinOrder;
-
-    /** */
-    private final boolean isLocal;
-
-    /**
-     * @param schemaName Schema name.
-     * @param sql Sql.
-     * @param grpByCollocated Collocated GROUP BY.
-     * @param distributedJoins Distributed joins enabled.
-     * @param enforceJoinOrder Enforce join order of tables.
-     * @param isLocal Query is local flag.
-     */
-    QueryParserCacheKey(String schemaName,
-        String sql,
-        boolean grpByCollocated,
-        boolean distributedJoins,
-        boolean enforceJoinOrder,
-        boolean isLocal) {
-        this.schemaName = schemaName;
-        this.sql = sql;
-        this.grpByCollocated = grpByCollocated;
-        this.distributedJoins = distributedJoins;
-        this.enforceJoinOrder = enforceJoinOrder;
-        this.isLocal = isLocal;
-    }
-
-    /** {@inheritDoc} */
-    @SuppressWarnings("SimplifiableIfStatement")
-    @Override public boolean equals(Object o) {
-        if (this == o)
-            return true;
-
-        if (o == null || getClass() != o.getClass())
-            return false;
-
-        QueryParserCacheKey that = (QueryParserCacheKey)o;
-
-        if (grpByCollocated != that.grpByCollocated)
-            return false;
-
-        if (distributedJoins != that.distributedJoins)
-            return false;
-
-        if (enforceJoinOrder != that.enforceJoinOrder)
-            return false;
-
-        if (schemaName != null ? !schemaName.equals(that.schemaName) : that.schemaName != null)
-            return false;
-
-        return isLocal == that.isLocal && sql.equals(that.sql);
-    }
-
-    /** {@inheritDoc} */
-    @Override public int hashCode() {
-        int res = schemaName != null ? schemaName.hashCode() : 0;
-        res = 31 * res + sql.hashCode();
-        res = 31 * res + (grpByCollocated ? 1 : 0);
-        res = res + (distributedJoins ? 2 : 0);
-        res = res + (enforceJoinOrder ? 4 : 0);
-        res = res + (isLocal ? 8 : 0);
-
-        return res;
-    }
-}
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/QueryParserResult.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/QueryParserResult.java
index 75caff9..e7c66e7 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/QueryParserResult.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/QueryParserResult.java
@@ -24,8 +24,11 @@
  * Result of parsing and splitting SQL from {@link SqlFieldsQuery}.
  */
 public class QueryParserResult {
-    /** New fields query that may be executed right away. */
-    private final SqlFieldsQuery qry;
+    /** Query descriptor. */
+    private final QueryDescriptor qryDesc;
+
+    /** Query parameters. */
+    private final QueryParameters qryParams;
 
     /** Remaining query. */
     private final SqlFieldsQuery remainingQry;
@@ -42,20 +45,23 @@
     /**
      * Constructor.
      *
-     * @param qry New query.
+     * @param qryDesc Query descriptor.
+     * @param qryParams Query parameters.
      * @param remainingQry Remaining query.
      * @param select Select.
      * @param dml DML.
      * @param cmd Command.
      */
     public QueryParserResult(
-        SqlFieldsQuery qry,
+        QueryDescriptor qryDesc,
+        QueryParameters qryParams,
         SqlFieldsQuery remainingQry,
         @Nullable QueryParserResultSelect select,
         @Nullable QueryParserResultDml dml,
         @Nullable QueryParserResultCommand cmd
     ) {
-        this.qry = qry;
+        this.qryDesc = qryDesc;
+        this.qryParams = qryParams;
         this.remainingQry = remainingQry;
         this.select = select;
         this.dml = dml;
@@ -63,10 +69,17 @@
     }
 
     /**
-     * @return New fields query that may be executed right away.
+     * @return Query descriptor.
      */
-    public SqlFieldsQuery query() {
-        return qry;
+    public QueryDescriptor queryDescriptor() {
+        return qryDesc;
+    }
+
+    /**
+     * @return Query parameters.
+     */
+    public QueryParameters queryParameters() {
+        return qryParams;
     }
 
     /**
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/SchemaManager.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/SchemaManager.java
index accd9ea..8f3620d 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/SchemaManager.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/SchemaManager.java
@@ -57,6 +57,7 @@
 import org.apache.ignite.internal.processors.query.h2.sys.view.SqlSystemViewNodeAttributes;
 import org.apache.ignite.internal.processors.query.h2.sys.view.SqlSystemViewNodeMetrics;
 import org.apache.ignite.internal.processors.query.h2.sys.view.SqlSystemViewNodes;
+import org.apache.ignite.internal.processors.query.h2.sys.view.SqlSystemViewQueryHistoryMetrics;
 import org.apache.ignite.internal.processors.query.h2.sys.view.SqlSystemViewRunningQueries;
 import org.apache.ignite.internal.processors.query.h2.sys.view.SqlSystemViewTables;
 import org.apache.ignite.internal.processors.query.schema.SchemaIndexCacheVisitor;
@@ -170,6 +171,7 @@
         views.add(new SqlSystemViewCacheGroups(ctx));
         views.add(new SqlSystemViewCacheGroupsIOStatistics(ctx));
         views.add(new SqlSystemViewRunningQueries(ctx));
+        views.add(new SqlSystemViewQueryHistoryMetrics(ctx));
         views.add(new SqlSystemViewTables(ctx, this));
         views.add(new SqlSystemViewIndexes(ctx, this));
 
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/dml/DmlUtils.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/dml/DmlUtils.java
index fab9869..93cf1aa 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/dml/DmlUtils.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/dml/DmlUtils.java
@@ -71,7 +71,8 @@
      * @return Converted object.
      */
     @SuppressWarnings({"ConstantConditions", "SuspiciousSystemArraycopy"})
-    public static Object convert(Object val, GridH2RowDescriptor desc, Class<?> expCls, int type) {
+    public static Object convert(Object val, GridH2RowDescriptor desc, Class<?> expCls,
+        int type, String columnName) {
         if (val == null)
             return null;
 
@@ -131,7 +132,7 @@
             return res;
         }
         catch (Exception e) {
-            throw new IgniteSQLException("Value conversion failed [from=" + currCls.getName() + ", to=" +
+            throw new IgniteSQLException("Value conversion failed [column=" + columnName + ", from=" + currCls.getName() + ", to=" +
                 expCls.getName() +']', IgniteQueryErrorCode.CONVERSION_FAILED, e);
         }
     }
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/dml/UpdatePlan.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/dml/UpdatePlan.java
index 9877e9f..e245c07 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/dml/UpdatePlan.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/dml/UpdatePlan.java
@@ -204,7 +204,7 @@
         if (QueryUtils.isSqlType(desc.keyClass())) {
             assert keyColIdx != -1;
 
-            key = DmlUtils.convert(key, rowDesc, desc.keyClass(), colTypes[keyColIdx]);
+            key = DmlUtils.convert(key, rowDesc, desc.keyClass(), colTypes[keyColIdx], colNames[keyColIdx]);
         }
 
         Object val = valSupplier.apply(row);
@@ -212,7 +212,7 @@
         if (QueryUtils.isSqlType(desc.valueClass())) {
             assert valColIdx != -1;
 
-            val = DmlUtils.convert(val, rowDesc, desc.valueClass(), colTypes[valColIdx]);
+            val = DmlUtils.convert(val, rowDesc, desc.valueClass(), colTypes[valColIdx], colNames[valColIdx]);
         }
 
         if (key == null) {
@@ -249,7 +249,7 @@
 
             Class<?> expCls = prop.type();
 
-            newColVals.put(colName, DmlUtils.convert(row.get(i), rowDesc, expCls, colTypes[i]));
+            newColVals.put(colName, DmlUtils.convert(row.get(i), rowDesc, expCls, colTypes[i], colNames[i]));
         }
 
         desc.setDefaults(key, val);
@@ -322,7 +322,7 @@
 
             assert prop != null : "Unknown property: " + colNames[i];
 
-            newColVals.put(colNames[i], DmlUtils.convert(row.get(i + 2), rowDesc, prop.type(), colTypes[i]));
+            newColVals.put(colNames[i], DmlUtils.convert(row.get(i + 2), rowDesc, prop.type(), colTypes[i], colNames[i]));
         }
 
         newVal = valSupplier.apply(row);
@@ -471,7 +471,7 @@
                 if (j == keyColIdx || j == valColIdx) {
                     Class<?> colCls = j == keyColIdx ? desc.type().keyClass() : desc.type().valueClass();
 
-                    colVal = DmlUtils.convert(colVal, desc, colCls, colTypes[j]);
+                    colVal = DmlUtils.convert(colVal, desc, colCls, colTypes[j], colNames[j]);
                 }
 
                 resRow.add(colVal);
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/dml/UpdatePlanBuilder.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/dml/UpdatePlanBuilder.java
index b95a49b..ffb3012 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/dml/UpdatePlanBuilder.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/dml/UpdatePlanBuilder.java
@@ -28,13 +28,12 @@
 import java.util.List;
 import java.util.Set;
 import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.IgniteSystemProperties;
 import org.apache.ignite.binary.BinaryObject;
 import org.apache.ignite.binary.BinaryObjectBuilder;
-import org.apache.ignite.cache.query.SqlFieldsQuery;
 import org.apache.ignite.internal.processors.cache.GridCacheContext;
 import org.apache.ignite.internal.processors.cache.query.indexing.GridCacheTwoStepQuery;
 import org.apache.ignite.internal.processors.cache.query.IgniteQueryErrorCode;
-import org.apache.ignite.internal.processors.cache.query.SqlFieldsQueryEx;
 import org.apache.ignite.internal.processors.query.GridQueryProperty;
 import org.apache.ignite.internal.processors.query.GridQueryTypeDescriptor;
 import org.apache.ignite.internal.processors.query.IgniteSQLException;
@@ -42,6 +41,7 @@
 import org.apache.ignite.internal.processors.query.h2.DmlStatementsProcessor;
 import org.apache.ignite.internal.processors.query.h2.H2Utils;
 import org.apache.ignite.internal.processors.query.h2.IgniteH2Indexing;
+import org.apache.ignite.internal.processors.query.h2.QueryDescriptor;
 import org.apache.ignite.internal.processors.query.h2.opt.GridH2RowDescriptor;
 import org.apache.ignite.internal.processors.query.h2.opt.GridH2Table;
 import org.apache.ignite.internal.processors.query.h2.sql.GridSqlColumn;
@@ -67,7 +67,6 @@
 import org.apache.ignite.internal.util.typedef.internal.U;
 import org.apache.ignite.lang.IgniteClosure;
 import org.h2.table.Column;
-import org.jetbrains.annotations.Nullable;
 
 /**
  * Logic for building update plans performed by {@link DmlStatementsProcessor}.
@@ -77,6 +76,10 @@
     private static final IgniteClosure<GridSqlColumn, Column> TO_H2_COL =
         (IgniteClosure<GridSqlColumn, Column>)GridSqlColumn::column;
 
+    /** Allow hidden key value columns at the INSERT/UPDATE/MERGE statements (not final for tests). */
+    private static boolean ALLOW_KEY_VAL_UPDATES = IgniteSystemProperties.getBoolean(
+        IgniteSystemProperties.IGNITE_SQL_ALLOW_KEY_VAL_UPDATES, false);
+
     /**
      * Constructor.
      */
@@ -88,25 +91,23 @@
      * Generate SELECT statements to retrieve data for modifications from and find fast UPDATE or DELETE args,
      * if available.
      *
-     * @param schemaName Schema name.
+     * @param planKey Plan key.
      * @param stmt Statement.
      * @param mvccEnabled MVCC enabled flag.
      * @param idx Indexing.
-     * @param fieldsQry Original query.
      * @return Update plan.
      */
     @SuppressWarnings("ConstantConditions")
     public static UpdatePlan planForStatement(
-        String schemaName,
+        QueryDescriptor planKey,
         GridSqlStatement stmt,
         boolean mvccEnabled,
-        IgniteH2Indexing idx,
-        @Nullable SqlFieldsQuery fieldsQry
+        IgniteH2Indexing idx
     ) throws IgniteCheckedException {
         if (stmt instanceof GridSqlMerge || stmt instanceof GridSqlInsert)
-            return planForInsert(schemaName, stmt, idx, mvccEnabled, fieldsQry);
+            return planForInsert(planKey, stmt, idx, mvccEnabled);
         else if (stmt instanceof GridSqlUpdate || stmt instanceof GridSqlDelete)
-            return planForUpdate(schemaName, stmt, idx, mvccEnabled, fieldsQry);
+            return planForUpdate(planKey, stmt, idx, mvccEnabled);
         else
             throw new IgniteSQLException("Unsupported operation: " + stmt.getSQL(),
                 IgniteQueryErrorCode.UNSUPPORTED_OPERATION);
@@ -115,21 +116,19 @@
     /**
      * Prepare update plan for INSERT or MERGE.
      *
-     * @param schemaName Schema name.
+     * @param planKey Plan key.
      * @param stmt INSERT or MERGE statement.
      * @param idx Indexing.
      * @param mvccEnabled Mvcc flag.
-     * @param fieldsQuery Original query.
      * @return Update plan.
      * @throws IgniteCheckedException if failed.
      */
     @SuppressWarnings("ConstantConditions")
     private static UpdatePlan planForInsert(
-        String schemaName,
+        QueryDescriptor planKey,
         GridSqlStatement stmt,
         IgniteH2Indexing idx,
-        boolean mvccEnabled,
-        @Nullable SqlFieldsQuery fieldsQuery
+        boolean mvccEnabled
     ) throws IgniteCheckedException {
         GridSqlQuery sel = null;
 
@@ -258,8 +257,7 @@
             distributed = checkPlanCanBeDistributed(
                 idx,
                 mvccEnabled,
-                schemaName,
-                fieldsQuery,
+                planKey,
                 selectSql,
                 tbl.dataTable().cacheName()
             );
@@ -333,20 +331,18 @@
     /**
      * Prepare update plan for UPDATE or DELETE.
      *
-     * @param schemaName Schema name.
+     * @param planKey Plan key.
      * @param stmt UPDATE or DELETE statement.
      * @param idx Indexing.
      * @param mvccEnabled MVCC flag.
-     * @param fieldsQuery Original query.
      * @return Update plan.
      * @throws IgniteCheckedException if failed.
      */
     private static UpdatePlan planForUpdate(
-        String schemaName,
+        QueryDescriptor planKey,
         GridSqlStatement stmt,
         IgniteH2Indexing idx,
-        boolean mvccEnabled,
-        @Nullable SqlFieldsQuery fieldsQuery
+        boolean mvccEnabled
     ) throws IgniteCheckedException {
         GridSqlElement target;
 
@@ -442,8 +438,7 @@
                     distributed = checkPlanCanBeDistributed(
                         idx,
                         mvccEnabled,
-                        schemaName,
-                        fieldsQuery,
+                        planKey,
                         selectSql,
                         tbl.dataTable().cacheName()
                     );
@@ -477,8 +472,7 @@
                     distributed = checkPlanCanBeDistributed(
                         idx,
                         mvccEnabled,
-                        schemaName,
-                        fieldsQuery,
+                        planKey,
                         selectSql,
                         tbl.dataTable().cacheName()
                     );
@@ -854,6 +848,22 @@
                 throw new IgniteSQLException("Column " + valColName + " refers to entire value cache object. " +
                     "It must not be mixed with other columns that refer to parts of value.",
                     IgniteQueryErrorCode.PARSING);
+
+            if (!ALLOW_KEY_VAL_UPDATES) {
+                if (desc.isKeyColumn(colId) && !QueryUtils.isSqlType(desc.type().keyClass())) {
+                    throw new IgniteSQLException(
+                        "Update of composite key column is not supported",
+                        IgniteQueryErrorCode.UNSUPPORTED_OPERATION
+                    );
+                }
+
+                if (desc.isValueColumn(colId) && !QueryUtils.isSqlType(desc.type().valueClass())) {
+                    throw new IgniteSQLException(
+                        "Update of composite value column is not supported",
+                        IgniteQueryErrorCode.UNSUPPORTED_OPERATION
+                    );
+                }
+            }
         }
     }
 
@@ -862,8 +872,7 @@
      *
      * @param idx Indexing.
      * @param mvccEnabled Mvcc flag.
-     * @param schemaName Schema name.
-     * @param fieldsQry Initial update query.
+     * @param planKey Plan key.
      * @param selectQry Derived select query.
      * @param cacheName Cache name.
      * @return distributed update plan info, or {@code null} if cannot be distributed.
@@ -872,24 +881,23 @@
     private static DmlDistributedPlanInfo checkPlanCanBeDistributed(
         IgniteH2Indexing idx,
         boolean mvccEnabled,
-        String schemaName,
-        SqlFieldsQuery fieldsQry,
+        QueryDescriptor planKey,
         String selectQry,
         String cacheName
     )
         throws IgniteCheckedException {
-        if ((!mvccEnabled && !isSkipReducerOnUpdateQuery(fieldsQry)) || DmlUtils.isBatched(fieldsQry))
+        if ((!mvccEnabled && !planKey.skipReducerOnUpdate()) || planKey.batched())
             return null;
 
-        try (Connection conn = idx.connections().connectionNoCache(schemaName)) {
+        try (Connection conn = idx.connections().connectionNoCache(planKey.schemaName())) {
             // Get a new prepared statement for derived select query.
             try (PreparedStatement stmt = conn.prepareStatement(selectQry)) {
                 GridCacheTwoStepQuery qry = GridSqlQuerySplitter.split(
                     conn,
                     GridSqlQueryParser.prepared(stmt),
-                    fieldsQry.isCollocated(),
-                    fieldsQry.isDistributedJoins(),
-                    fieldsQry.isEnforceJoinOrder(),
+                    planKey.collocated(),
+                    planKey.distributedJoins(),
+                    planKey.enforceJoinOrder(),
                     false,
                     idx
                 );
@@ -917,17 +925,6 @@
     }
 
     /**
-     * Checks whether query flags are compatible with server side update.
-     *
-     * @param qry Query.
-     * @return {@code true} if update can be distributed.
-     */
-    private static boolean isSkipReducerOnUpdateQuery(SqlFieldsQuery qry) {
-        return qry != null && !qry.isLocal() &&
-            qry instanceof SqlFieldsQueryEx && ((SqlFieldsQueryEx)qry).isSkipReducerOnUpdate();
-    }
-
-    /**
      * Simple supplier that just takes specified element of a given row.
      */
     private static final class PlainValueSupplier implements KeyValueSupplier {
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sys/view/SqlAbstractLocalSystemView.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sys/view/SqlAbstractLocalSystemView.java
index 1446f91..01102da 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sys/view/SqlAbstractLocalSystemView.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sys/view/SqlAbstractLocalSystemView.java
@@ -17,28 +17,22 @@
 
 package org.apache.ignite.internal.processors.query.h2.sys.view;
 
-import java.util.TimeZone;
 import java.util.UUID;
 import org.apache.ignite.internal.GridKernalContext;
 import org.h2.engine.Session;
 import org.h2.result.Row;
 import org.h2.result.SearchRow;
 import org.h2.table.Column;
-import org.h2.util.DateTimeUtils;
 import org.h2.value.Value;
 import org.h2.value.ValueNull;
 import org.h2.value.ValueString;
 import org.h2.value.ValueTimestamp;
-import org.h2.value.ValueTimestampTimeZone;
 
 /**
  * Local system view base class (which uses only local node data).
  */
 @SuppressWarnings("IfMayBeConditional")
 public abstract class SqlAbstractLocalSystemView extends SqlAbstractSystemView {
-
-    public static final int MILLIS_IN_MIN = 60_000;
-
     /**
      * @param tblName Table name.
      * @param desc Description.
@@ -153,20 +147,4 @@
         else
             return ValueTimestamp.fromMillis(millis);
     }
-
-    /**
-     * Converts millis to H2 ValueTimestamp in default time zone.
-     *
-     * @param millis Millis.
-     */
-    protected static Value valueTimestampZoneFromMillis(long millis) {
-        long dateVal = DateTimeUtils.dateValueFromDate(millis);
-        long nanos = DateTimeUtils.nanosFromDate(millis);
-        int tzOff = TimeZone.getDefault().getRawOffset();
-
-        if(tzOff % MILLIS_IN_MIN == 0)
-            return ValueTimestampTimeZone.fromDateValueAndNanos(dateVal, nanos, (short)(tzOff / MILLIS_IN_MIN));
-        else
-            return DateTimeUtils.timestampTimeZoneFromLocalDateValueAndNanos(dateVal, nanos);
-    }
 }
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sys/view/SqlSystemViewCacheGroupsIOStatistics.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sys/view/SqlSystemViewCacheGroupsIOStatistics.java
index 5dfe957..a2e0cfb 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sys/view/SqlSystemViewCacheGroupsIOStatistics.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sys/view/SqlSystemViewCacheGroupsIOStatistics.java
@@ -40,7 +40,7 @@
      * @param ctx Grid context.
      */
     public SqlSystemViewCacheGroupsIOStatistics(GridKernalContext ctx) {
-        super("CACHE_GROUPS_IO", "IO statistics for cache groups", ctx, "GROUP_NAME",
+        super("LOCAL_CACHE_GROUPS_IO", "Local node IO statistics for cache groups", ctx, "GROUP_NAME",
             newColumn("GROUP_ID", Value.INT),
             newColumn("GROUP_NAME"),
             newColumn("PHYSICAL_READS", Value.LONG),
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sys/view/SqlSystemViewQueryHistoryMetrics.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sys/view/SqlSystemViewQueryHistoryMetrics.java
new file mode 100644
index 0000000..98d84f4
--- /dev/null
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sys/view/SqlSystemViewQueryHistoryMetrics.java
@@ -0,0 +1,92 @@
+/*
+ * 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.sys.view;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import org.apache.ignite.internal.GridKernalContext;
+import org.apache.ignite.internal.processors.query.QueryHistoryMetrics;
+import org.apache.ignite.internal.processors.query.QueryHistoryMetricsKey;
+import org.apache.ignite.internal.processors.query.h2.IgniteH2Indexing;
+import org.h2.engine.Session;
+import org.h2.result.Row;
+import org.h2.result.SearchRow;
+import org.h2.value.Value;
+
+/**
+ * View that contains query history statistics on local node.
+ */
+public class SqlSystemViewQueryHistoryMetrics extends SqlAbstractLocalSystemView {
+
+   /**
+     * Creates view with columns.
+     *
+     * @param ctx kernal context.
+     */
+    public SqlSystemViewQueryHistoryMetrics(GridKernalContext ctx) {
+        super("LOCAL_SQL_QUERY_HISTORY", "Ignite SQL query history metrics", ctx,
+            newColumn("SCHEMA_NAME"),
+            newColumn("SQL"),
+            newColumn("LOCAL", Value.BOOLEAN),
+            newColumn("EXECUTIONS", Value.LONG),
+            newColumn("FAILURES", Value.LONG),
+            newColumn("DURATION_MIN", Value.LONG),
+            newColumn("DURATION_MAX", Value.LONG),
+            newColumn("LAST_START_TIME", Value.TIMESTAMP)
+        );
+
+    }
+
+    /** {@inheritDoc} */
+    @Override public Iterator<Row> getRows(Session ses, SearchRow first, SearchRow last) {
+        Map<QueryHistoryMetricsKey, QueryHistoryMetrics> qryHistMetrics =
+            ((IgniteH2Indexing)ctx.query().getIndexing()).runningQueryManager().queryHistoryMetrics();
+
+        List<Row> rows = new ArrayList<>();
+
+        qryHistMetrics.values().forEach(m -> {
+            Object[] data = new Object[] {
+                m.schema(),
+                m.query(),
+                m.local(),
+                m.executions(),
+                m.failures(),
+                m.minimumTime(),
+                m.maximumTime(),
+                valueTimestampFromMillis(m.lastStartTime()),
+            };
+
+            rows.add(createRow(ses, data));
+        });
+
+        return rows.iterator();
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean canGetRowCount() {
+        return true;
+    }
+
+    /** {@inheritDoc} */
+    @Override public long getRowCount() {
+        return ((IgniteH2Indexing)ctx.query().getIndexing()).runningQueryManager().queryHistoryMetrics().size();
+    }
+}
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sys/view/SqlSystemViewRunningQueries.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sys/view/SqlSystemViewRunningQueries.java
index d53056e..d692be9 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sys/view/SqlSystemViewRunningQueries.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sys/view/SqlSystemViewRunningQueries.java
@@ -43,7 +43,7 @@
             newColumn("SQL"),
             newColumn("SCHEMA_NAME"),
             newColumn("LOCAL", Value.BOOLEAN),
-            newColumn("START_TIME", Value.TIMESTAMP_TZ),
+            newColumn("START_TIME", Value.TIMESTAMP),
             newColumn("DURATION", Value.LONG)
         );
     }
@@ -80,7 +80,7 @@
                     info.query(),
                     info.schemaName(),
                     info.local(),
-                    valueTimestampZoneFromMillis(info.startTime()),
+                    valueTimestampFromMillis(info.startTime()),
                     duration
                 )
             );
diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheInsertSqlQuerySelfTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheInsertSqlQuerySelfTest.java
index 1938628..482616f 100644
--- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheInsertSqlQuerySelfTest.java
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheInsertSqlQuerySelfTest.java
@@ -25,6 +25,7 @@
 import org.apache.ignite.IgniteCache;
 import org.apache.ignite.cache.query.SqlFieldsQuery;
 import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.internal.processors.query.h2.dml.UpdatePlanBuilder;
 import org.apache.ignite.testframework.GridTestUtils;
 import org.junit.Test;
 
@@ -49,14 +50,24 @@
      */
     @Test
     public void testInsertWithExplicitKey() {
-        IgniteCache<String, Person> p = ignite(0).cache("S2P").withKeepBinary();
+        boolean oldAllowColumnsVal = GridTestUtils.getFieldValue(UpdatePlanBuilder.class, UpdatePlanBuilder.class,
+            "ALLOW_KEY_VAL_UPDATES");
 
-        p.query(new SqlFieldsQuery("insert into Person (_key, id, firstName) values ('s', ?, ?), " +
-            "('a', 2, 'Alex')").setArgs(1, "Sergi"));
+        GridTestUtils.setFieldValue(UpdatePlanBuilder.class, "ALLOW_KEY_VAL_UPDATES", true);
 
-        assertEquals(createPerson(1, "Sergi"), p.get("s"));
+        try {
+            IgniteCache<String, Person> p = ignite(0).cache("S2P").withKeepBinary();
 
-        assertEquals(createPerson(2, "Alex"), p.get("a"));
+            p.query(new SqlFieldsQuery("insert into Person (_key, id, firstName) values ('s', ?, ?), " +
+                "('a', 2, 'Alex')").setArgs(1, "Sergi"));
+
+            assertEquals(createPerson(1, "Sergi"), p.get("s"));
+
+            assertEquals(createPerson(2, "Alex"), p.get("a"));
+        }
+        finally {
+            GridTestUtils.setFieldValue(UpdatePlanBuilder.class, "ALLOW_KEY_VAL_UPDATES", oldAllowColumnsVal);
+        }
     }
 
     /**
@@ -205,33 +216,43 @@
      */
     @Test
     public void testNestedFieldsHandling1() {
-        IgniteCache<Integer, AllTypes> p = ignite(0).cache("I2AT");
+        boolean oldAllowColumnsVal = GridTestUtils.getFieldValue(UpdatePlanBuilder.class, UpdatePlanBuilder.class,
+            "ALLOW_KEY_VAL_UPDATES");
 
-        final int ROOT_KEY = 1;
+        GridTestUtils.setFieldValue(UpdatePlanBuilder.class, "ALLOW_KEY_VAL_UPDATES", true);
 
-        // Create 1st level value
-        AllTypes rootVal = new AllTypes(1L);
+        try {
+            IgniteCache<Integer, AllTypes> p = ignite(0).cache("I2AT");
 
-        // With random inner field
-        rootVal.innerTypeCol = new AllTypes.InnerType(42L);
+            final int ROOT_KEY = 1;
+
+            // Create 1st level value
+            AllTypes rootVal = new AllTypes(1L);
+
+            // With random inner field
+            rootVal.innerTypeCol = new AllTypes.InnerType(42L);
 
 
-        p.query(new SqlFieldsQuery(
-            "INSERT INTO AllTypes(_key,_val) VALUES (?, ?)").setArgs(ROOT_KEY, rootVal)
-        ).getAll();
+            p.query(new SqlFieldsQuery(
+                "INSERT INTO AllTypes(_key,_val) VALUES (?, ?)").setArgs(ROOT_KEY, rootVal)
+            ).getAll();
 
-        // Update inner fields just by their names
-        p.query(new SqlFieldsQuery("UPDATE AllTypes SET innerLongCol = ?, innerStrCol = ?, arrListCol = ?;")
-            .setArgs(50L, "sss", new ArrayList<>(Arrays.asList(3L, 2L, 1L)))).getAll();
+            // Update inner fields just by their names
+            p.query(new SqlFieldsQuery("UPDATE AllTypes SET innerLongCol = ?, innerStrCol = ?, arrListCol = ?;")
+                .setArgs(50L, "sss", new ArrayList<>(Arrays.asList(3L, 2L, 1L)))).getAll();
 
-        AllTypes res = p.get(ROOT_KEY);
+            AllTypes res = p.get(ROOT_KEY);
 
-        AllTypes.InnerType resInner = new AllTypes.InnerType(50L);
+            AllTypes.InnerType resInner = new AllTypes.InnerType(50L);
 
-        resInner.innerStrCol = "sss";
-        resInner.arrListCol = new ArrayList<>(Arrays.asList(3L, 2L, 1L));
+            resInner.innerStrCol = "sss";
+            resInner.arrListCol = new ArrayList<>(Arrays.asList(3L, 2L, 1L));
 
-        assertEquals(resInner, res.innerTypeCol);
+            assertEquals(resInner, res.innerTypeCol);
+        }
+        finally {
+            GridTestUtils.setFieldValue(UpdatePlanBuilder.class, "ALLOW_KEY_VAL_UPDATES", oldAllowColumnsVal);
+        }
     }
 
     /**
@@ -239,17 +260,27 @@
      */
     @Test
     public void testCacheRestartHandling() {
-        for (int i = 0; i < 4; i++) {
-            IgniteCache<Integer, AllTypes> p =
-                ignite(0).getOrCreateCache(cacheConfig("I2AT", true, false, Integer.class,
-                    AllTypes.class));
+        boolean oldAllowColumnsVal = GridTestUtils.getFieldValue(UpdatePlanBuilder.class, UpdatePlanBuilder.class,
+            "ALLOW_KEY_VAL_UPDATES");
 
-            p.query(new SqlFieldsQuery("INSERT INTO AllTypes(_key, _val) VALUES (1, ?)")
-                .setArgs(new AllTypes(1L))).getAll();
+        GridTestUtils.setFieldValue(UpdatePlanBuilder.class, "ALLOW_KEY_VAL_UPDATES", true);
 
-            p.query(new SqlFieldsQuery("UPDATE AllTypes SET dateCol = null;")).getAll();
+        try {
+            for (int i = 0; i < 4; i++) {
+                IgniteCache<Integer, AllTypes> p =
+                    ignite(0).getOrCreateCache(cacheConfig("I2AT", true, false, Integer.class,
+                        AllTypes.class));
 
-            p.destroy();
+                p.query(new SqlFieldsQuery("INSERT INTO AllTypes(_key, _val) VALUES (1, ?)")
+                    .setArgs(new AllTypes(1L))).getAll();
+
+                p.query(new SqlFieldsQuery("UPDATE AllTypes SET dateCol = null;")).getAll();
+
+                p.destroy();
+            }
+        }
+        finally {
+            GridTestUtils.setFieldValue(UpdatePlanBuilder.class, "ALLOW_KEY_VAL_UPDATES", oldAllowColumnsVal);
         }
     }
 }
diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheSqlDmlErrorSelfTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheSqlDmlErrorSelfTest.java
index 2812c9e..00ea790 100644
--- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheSqlDmlErrorSelfTest.java
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheSqlDmlErrorSelfTest.java
@@ -23,7 +23,9 @@
 import java.util.concurrent.ThreadLocalRandom;
 import org.apache.ignite.IgniteCache;
 import org.apache.ignite.cache.query.SqlFieldsQuery;
+import org.apache.ignite.internal.processors.cache.index.AbstractIndexingCommonTest;
 import org.apache.ignite.internal.processors.query.IgniteSQLException;
+import org.apache.ignite.internal.processors.query.h2.dml.UpdatePlanBuilder;
 import org.apache.ignite.internal.util.typedef.F;
 import org.apache.ignite.testframework.GridTestUtils;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
@@ -33,17 +35,34 @@
 /**
  * Negative java API tests for dml queries (insert, merge, update).
  */
-public class IgniteCacheSqlDmlErrorSelfTest extends GridCommonAbstractTest {
+public class IgniteCacheSqlDmlErrorSelfTest extends AbstractIndexingCommonTest {
     /** Dummy cache, just cache api entry point. */
     private static IgniteCache<?, ?> cache;
 
+    /** Old allow value. */
+    private static boolean oldAllowColumnsVal;
+
     /** {@inheritDoc} */
     @Override public void beforeTestsStarted() throws Exception {
+        super.beforeTestsStarted();
+
+        oldAllowColumnsVal = GridTestUtils.getFieldValue(UpdatePlanBuilder.class, UpdatePlanBuilder.class,
+            "ALLOW_KEY_VAL_UPDATES");
+
+        GridTestUtils.setFieldValue(UpdatePlanBuilder.class, "ALLOW_KEY_VAL_UPDATES", true);
+
         startGrids(1);
 
         cache = grid(0).createCache(DEFAULT_CACHE_NAME);
     }
 
+    /** {@inheritDoc} */
+    @Override protected void afterTestsStopped() throws Exception {
+        GridTestUtils.setFieldValue(UpdatePlanBuilder.class, "ALLOW_KEY_VAL_UPDATES", oldAllowColumnsVal);
+
+        super.afterTestsStopped();
+    }
+
     /**
      * Create test tables.
      */
diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheSqlInsertValidationSelfTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheSqlInsertValidationSelfTest.java
index 678747a..9e58f80 100644
--- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheSqlInsertValidationSelfTest.java
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheSqlInsertValidationSelfTest.java
@@ -30,7 +30,9 @@
 import org.apache.ignite.cache.query.SqlFieldsQuery;
 import org.apache.ignite.cache.query.annotations.QuerySqlField;
 import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.internal.processors.cache.index.AbstractIndexingCommonTest;
 import org.apache.ignite.internal.processors.query.IgniteSQLException;
+import org.apache.ignite.internal.processors.query.h2.dml.UpdatePlanBuilder;
 import org.apache.ignite.testframework.GridTestUtils;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
 import org.apache.ignite.transactions.TransactionDuplicateKeyException;
@@ -41,7 +43,7 @@
 /**
  * Tests for validation of inserts sql queries.
  */
-public class IgniteCacheSqlInsertValidationSelfTest extends GridCommonAbstractTest {
+public class IgniteCacheSqlInsertValidationSelfTest extends AbstractIndexingCommonTest {
     /** Entry point for sql api. Contains table configurations too. */
     private static IgniteCache<Object, Object> cache;
 
@@ -51,14 +53,29 @@
     /** Default value for fk2 field of WITH_KEY_FLDS table. */
     private static final Long DEFAULT_FK1_VAL = null;
 
+    /** Old allow value. */
+    private static boolean oldAllowColumnsVal;
+
     /** {@inheritDoc} */
     @Override protected void beforeTestsStarted() throws Exception {
         super.beforeTestsStarted();
 
+        oldAllowColumnsVal = GridTestUtils.getFieldValue(UpdatePlanBuilder.class, UpdatePlanBuilder.class,
+            "ALLOW_KEY_VAL_UPDATES");
+
+        GridTestUtils.setFieldValue(UpdatePlanBuilder.class, "ALLOW_KEY_VAL_UPDATES", true);
+
         startGrid(0);
     }
 
     /** {@inheritDoc} */
+    @Override protected void afterTestsStopped() throws Exception {
+        GridTestUtils.setFieldValue(UpdatePlanBuilder.class, "ALLOW_KEY_VAL_UPDATES", oldAllowColumnsVal);
+
+        super.afterTestsStopped();
+    }
+
+    /** {@inheritDoc} */
     @Override protected void beforeTest() throws Exception {
         super.beforeTest();
 
diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheUpdateSqlQuerySelfTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheUpdateSqlQuerySelfTest.java
index 3095372..d404d98 100644
--- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheUpdateSqlQuerySelfTest.java
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheUpdateSqlQuerySelfTest.java
@@ -31,6 +31,8 @@
 import org.apache.ignite.cache.query.SqlFieldsQuery;
 import org.apache.ignite.cache.query.annotations.QuerySqlField;
 import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.internal.processors.query.h2.dml.UpdatePlanBuilder;
+import org.apache.ignite.testframework.GridTestUtils;
 import org.junit.Test;
 
 /**
@@ -98,30 +100,40 @@
      */
     @Test
     public void testUpdateSingle() {
-        IgniteCache p = cache();
+        boolean oldAllowColumnsVal = GridTestUtils.getFieldValue(UpdatePlanBuilder.class, UpdatePlanBuilder.class,
+            "ALLOW_KEY_VAL_UPDATES");
 
-        QueryCursor<List<?>> c = p.query(new SqlFieldsQuery("update Person p set _val = ? where _key = ?")
-            .setArgs(createPerson(2, "Jo", "White"), "FirstKey"));
+        GridTestUtils.setFieldValue(UpdatePlanBuilder.class, "ALLOW_KEY_VAL_UPDATES", true);
 
-        c.iterator();
+        try {
+            IgniteCache p = cache();
 
-        c = p.query(new SqlFieldsQuery("select _key, _val, * from Person order by id, _key"));
+            QueryCursor<List<?>> c = p.query(new SqlFieldsQuery("update Person p set _val = ? where _key = ?")
+                .setArgs(createPerson(2, "Jo", "White"), "FirstKey"));
 
-        List<List<?>> leftovers = c.getAll();
+            c.iterator();
 
-        assertEquals(4, leftovers.size());
+            c = p.query(new SqlFieldsQuery("select _key, _val, * from Person order by id, _key"));
 
-        assertEqualsCollections(Arrays.asList("FirstKey", createPerson(2, "Jo", "White"), 2, "Jo", "White"),
-            leftovers.get(0));
+            List<List<?>> leftovers = c.getAll();
 
-        assertEqualsCollections(Arrays.asList("SecondKey", createPerson(2, "Joe", "Black"), 2, "Joe", "Black"),
-            leftovers.get(1));
+            assertEquals(4, leftovers.size());
 
-        assertEqualsCollections(Arrays.asList("k3", createPerson(3, "Sylvia", "Green"), 3, "Sylvia", "Green"),
-            leftovers.get(2));
+            assertEqualsCollections(Arrays.asList("FirstKey", createPerson(2, "Jo", "White"), 2, "Jo", "White"),
+                leftovers.get(0));
 
-        assertEqualsCollections(Arrays.asList("f0u4thk3y", createPerson(4, "Jane", "Silver"), 4, "Jane", "Silver"),
-            leftovers.get(3));
+            assertEqualsCollections(Arrays.asList("SecondKey", createPerson(2, "Joe", "Black"), 2, "Joe", "Black"),
+                leftovers.get(1));
+
+            assertEqualsCollections(Arrays.asList("k3", createPerson(3, "Sylvia", "Green"), 3, "Sylvia", "Green"),
+                leftovers.get(2));
+
+            assertEqualsCollections(Arrays.asList("f0u4thk3y", createPerson(4, "Jane", "Silver"), 4, "Jane", "Silver"),
+                leftovers.get(3));
+        }
+        finally {
+            GridTestUtils.setFieldValue(UpdatePlanBuilder.class, "ALLOW_KEY_VAL_UPDATES", oldAllowColumnsVal);
+        }
     }
 
     /**
@@ -129,33 +141,43 @@
      */
     @Test
     public void testNestedFieldsUpdate() {
-        IgniteCache<Long, AllTypes> p = ignite(0).cache("L2AT");
+        boolean oldAllowColumnsVal = GridTestUtils.getFieldValue(UpdatePlanBuilder.class, UpdatePlanBuilder.class,
+            "ALLOW_KEY_VAL_UPDATES");
 
-        final long ROOT_KEY = 1;
+        GridTestUtils.setFieldValue(UpdatePlanBuilder.class, "ALLOW_KEY_VAL_UPDATES", true);
 
-        // Create 1st level value
-        AllTypes rootVal = new AllTypes(1L);
+        try {
+            IgniteCache<Long, AllTypes> p = ignite(0).cache("L2AT");
 
-        // With random inner field
-        rootVal.innerTypeCol = new AllTypes.InnerType(42L);
+            final long ROOT_KEY = 1;
 
-        p.query(new SqlFieldsQuery(
-            "INSERT INTO \"AllTypes\"(_key,_val) VALUES (?, ?)").setArgs(ROOT_KEY, rootVal)
-        ).getAll();
+            // Create 1st level value
+            AllTypes rootVal = new AllTypes(1L);
 
-        // Update inner fields just by their names
-        p.query(new SqlFieldsQuery("UPDATE \"AllTypes\" " +
-            "SET \"innerLongCol\" = ?, \"innerStrCol\" = ?, \"arrListCol\" = ?;"
-        ).setArgs(50L, "sss", new ArrayList<>(Arrays.asList(3L, 2L, 1L)))).getAll();
+            // With random inner field
+            rootVal.innerTypeCol = new AllTypes.InnerType(42L);
 
-        AllTypes res = p.get(ROOT_KEY);
+            p.query(new SqlFieldsQuery(
+                "INSERT INTO \"AllTypes\"(_key,_val) VALUES (?, ?)").setArgs(ROOT_KEY, rootVal)
+            ).getAll();
 
-        AllTypes.InnerType resInner = new AllTypes.InnerType(50L);
+            // Update inner fields just by their names
+            p.query(new SqlFieldsQuery("UPDATE \"AllTypes\" " +
+                "SET \"innerLongCol\" = ?, \"innerStrCol\" = ?, \"arrListCol\" = ?;"
+            ).setArgs(50L, "sss", new ArrayList<>(Arrays.asList(3L, 2L, 1L)))).getAll();
 
-        resInner.innerStrCol = "sss";
-        resInner.arrListCol = new ArrayList<>(Arrays.asList(3L, 2L, 1L));
+            AllTypes res = p.get(ROOT_KEY);
 
-        assertEquals(resInner, res.innerTypeCol);
+            AllTypes.InnerType resInner = new AllTypes.InnerType(50L);
+
+            resInner.innerStrCol = "sss";
+            resInner.arrListCol = new ArrayList<>(Arrays.asList(3L, 2L, 1L));
+
+            assertEquals(resInner, res.innerTypeCol);
+        }
+        finally {
+            GridTestUtils.setFieldValue(UpdatePlanBuilder.class, "ALLOW_KEY_VAL_UPDATES", oldAllowColumnsVal);
+        }
     }
 
 
@@ -194,112 +216,132 @@
     /** */
     @Test
     public void testTypeConversions() throws ParseException {
-        IgniteCache cache = ignite(0).cache("L2AT");
+        boolean oldAllowColumnsVal = GridTestUtils.getFieldValue(UpdatePlanBuilder.class, UpdatePlanBuilder.class,
+            "ALLOW_KEY_VAL_UPDATES");
 
-        cache.query(new SqlFieldsQuery("INSERT INTO \"AllTypes\" (_key, _val) VALUES(2, ?)")
-            .setArgs(new AllTypes(2L))).getAll();
+        GridTestUtils.setFieldValue(UpdatePlanBuilder.class, "ALLOW_KEY_VAL_UPDATES", true);
 
-        cache.query (new SqlFieldsQuery(
-            "UPDATE \"AllTypes\" " +
-                "SET " +
-                "\"dateCol\" = '2016-11-30 12:00:00', " +
-                "\"booleanCol\" = false, " +
-                "\"tsCol\" = DATE '2016-12-01' " +
-                "WHERE _key = 2")
-        );
+        try {
+            IgniteCache cache = ignite(0).cache("L2AT");
 
-        // Look ma, no hands: first we set value of inner object column (innerTypeCol), then update only one of its
-        // fields (innerLongCol), while leaving another inner property (innerStrCol) as specified by innerTypeCol.
-        cache.query(new SqlFieldsQuery(
+            cache.query(new SqlFieldsQuery("INSERT INTO \"AllTypes\" (_key, _val) VALUES(2, ?)")
+                .setArgs(new AllTypes(2L))).getAll();
+
+            cache.query (new SqlFieldsQuery(
                 "UPDATE \"AllTypes\" " +
                     "SET " +
-                    "\"innerLongCol\" = ?, " +  // (1)
-                    "\"doubleCol\" = CAST('50' as INT), " +
-                    "\"booleanCol\" = 80, " +
-                    "\"innerTypeCol\" = ?, " + // (2)
-                    "\"strCol\" = PI(), " +
-                    "\"shortCol\" = CAST(WEEK(PARSEDATETIME('2016-11-30', 'yyyy-MM-dd')) as VARCHAR), " +
-                    "\"sqlDateCol\"=TIMESTAMP '2016-12-02 13:47:00', " +
-                    "\"tsCol\"=TIMESTAMPADD('MI', 2, DATEADD('DAY', 2, \"tsCol\")), " +
-                    "\"primitiveIntsCol\" = ?, " +  //(3)
-                    "\"bytesCol\" = ?" // (4)
-            ).setArgs(5, new AllTypes.InnerType(80L), new int[] {2, 3}, new Byte[] {4, 5, 6})
-        ).getAll();
+                    "\"dateCol\" = '2016-11-30 12:00:00', " +
+                    "\"booleanCol\" = false, " +
+                    "\"tsCol\" = DATE '2016-12-01' " +
+                    "WHERE _key = 2")
+            );
 
-        AllTypes res = (AllTypes) cache.get(2L);
+            // Look ma, no hands: first we set value of inner object column (innerTypeCol), then update only one of its
+            // fields (innerLongCol), while leaving another inner property (innerStrCol) as specified by innerTypeCol.
+            cache.query(new SqlFieldsQuery(
+                    "UPDATE \"AllTypes\" " +
+                        "SET " +
+                        "\"innerLongCol\" = ?, " +  // (1)
+                        "\"doubleCol\" = CAST('50' as INT), " +
+                        "\"booleanCol\" = 80, " +
+                        "\"innerTypeCol\" = ?, " + // (2)
+                        "\"strCol\" = PI(), " +
+                        "\"shortCol\" = CAST(WEEK(PARSEDATETIME('2016-11-30', 'yyyy-MM-dd')) as VARCHAR), " +
+                        "\"sqlDateCol\"=TIMESTAMP '2016-12-02 13:47:00', " +
+                        "\"tsCol\"=TIMESTAMPADD('MI', 2, DATEADD('DAY', 2, \"tsCol\")), " +
+                        "\"primitiveIntsCol\" = ?, " +  //(3)
+                        "\"bytesCol\" = ?" // (4)
+                ).setArgs(5, new AllTypes.InnerType(80L), new int[] {2, 3}, new Byte[] {4, 5, 6})
+            ).getAll();
 
-        assertNotNull(res);
+            AllTypes res = (AllTypes) cache.get(2L);
 
-        assertEquals(new BigDecimal(301.0).doubleValue(), res.bigDecimalCol.doubleValue());
-        assertEquals(50.0, res.doubleCol);
-        assertEquals(2L, (long) res.longCol);
-        assertTrue(res.booleanCol);
-        assertEquals("3.141592653589793", res.strCol);
-        assertTrue(Arrays.equals(new byte[] {0, 1}, res.primitiveBytesCol));
-        assertTrue(Arrays.equals(new Byte[] {4, 5, 6}, res.bytesCol));
-        assertTrue(Arrays.deepEquals(new Integer[] {0, 1}, res.intsCol));
-        assertTrue(Arrays.equals(new int[] {2, 3}, res.primitiveIntsCol));
+            assertNotNull(res);
 
-        AllTypes.InnerType expInnerType = new AllTypes.InnerType(80L);
-        expInnerType.innerLongCol = 5L;
+            assertEquals(new BigDecimal(301.0).doubleValue(), res.bigDecimalCol.doubleValue());
+            assertEquals(50.0, res.doubleCol);
+            assertEquals(2L, (long) res.longCol);
+            assertTrue(res.booleanCol);
+            assertEquals("3.141592653589793", res.strCol);
+            assertTrue(Arrays.equals(new byte[] {0, 1}, res.primitiveBytesCol));
+            assertTrue(Arrays.equals(new Byte[] {4, 5, 6}, res.bytesCol));
+            assertTrue(Arrays.deepEquals(new Integer[] {0, 1}, res.intsCol));
+            assertTrue(Arrays.equals(new int[] {2, 3}, res.primitiveIntsCol));
 
-        assertEquals(expInnerType, res.innerTypeCol);
-        assertEquals(new SimpleDateFormat("yyyy-MM-dd HH:mm:SS").parse("2016-11-30 12:00:00"), res.dateCol);
-        assertEquals(new SimpleDateFormat("yyyy-MM-dd HH:mm:SS").parse("2016-12-03 00:02:00"), res.tsCol);
-        assertEquals(2, res.intCol);
-        assertEquals(AllTypes.EnumType.ENUMTRUE, res.enumCol);
-        assertEquals(new java.sql.Date(new SimpleDateFormat("yyyy-MM-dd").parse("2016-12-02").getTime()), res.sqlDateCol);
+            AllTypes.InnerType expInnerType = new AllTypes.InnerType(80L);
+            expInnerType.innerLongCol = 5L;
 
-        // 49th week, right?
-        assertEquals(49, res.shortCol);
+            assertEquals(expInnerType, res.innerTypeCol);
+            assertEquals(new SimpleDateFormat("yyyy-MM-dd HH:mm:SS").parse("2016-11-30 12:00:00"), res.dateCol);
+            assertEquals(new SimpleDateFormat("yyyy-MM-dd HH:mm:SS").parse("2016-12-03 00:02:00"), res.tsCol);
+            assertEquals(2, res.intCol);
+            assertEquals(AllTypes.EnumType.ENUMTRUE, res.enumCol);
+            assertEquals(new java.sql.Date(new SimpleDateFormat("yyyy-MM-dd").parse("2016-12-02").getTime()), res.sqlDateCol);
+
+            // 49th week, right?
+            assertEquals(49, res.shortCol);
+        }
+        finally {
+            GridTestUtils.setFieldValue(UpdatePlanBuilder.class, "ALLOW_KEY_VAL_UPDATES", oldAllowColumnsVal);
+        }
     }
 
     /** */
     @Test
     public void testSingleInnerFieldUpdate() throws ParseException {
-        IgniteCache cache = ignite(0).cache("L2AT");
+        boolean oldAllowColumnsVal = GridTestUtils.getFieldValue(UpdatePlanBuilder.class, UpdatePlanBuilder.class,
+            "ALLOW_KEY_VAL_UPDATES");
 
-        cache.query(new SqlFieldsQuery("insert into \"AllTypes\" (_key, _val) values(2, ?)")
-            .setArgs(new AllTypes(2L))).getAll();
+        GridTestUtils.setFieldValue(UpdatePlanBuilder.class, "ALLOW_KEY_VAL_UPDATES", true);
 
-        cache.query(new SqlFieldsQuery(
-            "UPDATE \"AllTypes\" " +
-                "SET " +
-                "\"dateCol\" = '2016-11-30 12:00:00', " +
-                "\"booleanCol\" = false " +
-                "WHERE _key = 2")
-        ).getAll();
+        try {
+            IgniteCache cache = ignite(0).cache("L2AT");
 
-        assertFalse(cache.query(new SqlFieldsQuery("select * from \"AllTypes\"")).getAll().isEmpty());
+            cache.query(new SqlFieldsQuery("insert into \"AllTypes\" (_key, _val) values(2, ?)")
+                .setArgs(new AllTypes(2L))).getAll();
 
-        cache.query(new SqlFieldsQuery("update \"AllTypes\" set \"innerLongCol\" = 5"));
+            cache.query(new SqlFieldsQuery(
+                "UPDATE \"AllTypes\" " +
+                    "SET " +
+                    "\"dateCol\" = '2016-11-30 12:00:00', " +
+                    "\"booleanCol\" = false " +
+                    "WHERE _key = 2")
+            ).getAll();
 
-        AllTypes res = (AllTypes) cache.get(2L);
+            assertFalse(cache.query(new SqlFieldsQuery("select * from \"AllTypes\"")).getAll().isEmpty());
 
-        assertNotNull(res);
+            cache.query(new SqlFieldsQuery("update \"AllTypes\" set \"innerLongCol\" = 5"));
 
-        assertEquals(new BigDecimal(301.0).doubleValue(), res.bigDecimalCol.doubleValue());
-        assertEquals(3.01, res.doubleCol);
-        assertEquals(2L, (long) res.longCol);
-        assertFalse(res.booleanCol);
+            AllTypes res = (AllTypes) cache.get(2L);
 
-        assertEquals("2", res.strCol);
-        assertTrue(Arrays.equals(new byte[] {0, 1}, res.primitiveBytesCol));
-        assertTrue(Arrays.deepEquals(new Byte[] {0, 1}, res.bytesCol));
-        assertTrue(Arrays.deepEquals(new Integer[] {0, 1}, res.intsCol));
-        assertTrue(Arrays.equals(new int[] {0, 1}, res.primitiveIntsCol));
+            assertNotNull(res);
 
-        AllTypes.InnerType expInnerType = new AllTypes.InnerType(2L);
-        expInnerType.innerLongCol = 5L;
+            assertEquals(new BigDecimal(301.0).doubleValue(), res.bigDecimalCol.doubleValue());
+            assertEquals(3.01, res.doubleCol);
+            assertEquals(2L, (long) res.longCol);
+            assertFalse(res.booleanCol);
 
-        assertEquals(expInnerType, res.innerTypeCol);
-        assertEquals(new SimpleDateFormat("yyyy-MM-dd HH:mm:SS").parse("2016-11-30 12:00:00"), res.dateCol);
-        assertNull(res.tsCol);
-        assertEquals(2, res.intCol);
-        assertEquals(AllTypes.EnumType.ENUMTRUE, res.enumCol);
-        assertNull(res.sqlDateCol);
+            assertEquals("2", res.strCol);
+            assertTrue(Arrays.equals(new byte[] {0, 1}, res.primitiveBytesCol));
+            assertTrue(Arrays.deepEquals(new Byte[] {0, 1}, res.bytesCol));
+            assertTrue(Arrays.deepEquals(new Integer[] {0, 1}, res.intsCol));
+            assertTrue(Arrays.equals(new int[] {0, 1}, res.primitiveIntsCol));
 
-        assertEquals(-23000, res.shortCol);
+            AllTypes.InnerType expInnerType = new AllTypes.InnerType(2L);
+            expInnerType.innerLongCol = 5L;
+
+            assertEquals(expInnerType, res.innerTypeCol);
+            assertEquals(new SimpleDateFormat("yyyy-MM-dd HH:mm:SS").parse("2016-11-30 12:00:00"), res.dateCol);
+            assertNull(res.tsCol);
+            assertEquals(2, res.intCol);
+            assertEquals(AllTypes.EnumType.ENUMTRUE, res.enumCol);
+            assertNull(res.sqlDateCol);
+
+            assertEquals(-23000, res.shortCol);
+        }
+        finally {
+            GridTestUtils.setFieldValue(UpdatePlanBuilder.class, "ALLOW_KEY_VAL_UPDATES", oldAllowColumnsVal);
+        }
     }
 
     /**
diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/StartCachesInParallelTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/StartCachesInParallelTest.java
index d63b30a..c882da7 100644
--- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/StartCachesInParallelTest.java
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/StartCachesInParallelTest.java
@@ -24,6 +24,7 @@
 import org.apache.ignite.failure.FailureContext;
 import org.apache.ignite.failure.StopNodeFailureHandler;
 import org.apache.ignite.internal.IgniteEx;
+import org.apache.ignite.testframework.junits.WithSystemProperty;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
 import org.junit.Test;
 
@@ -33,9 +34,6 @@
  * Tests, that cluster could start and activate with all possible values of IGNITE_ALLOW_START_CACHES_IN_PARALLEL.
  */
 public class StartCachesInParallelTest extends GridCommonAbstractTest {
-    /** IGNITE_ALLOW_START_CACHES_IN_PARALLEL option value before tests. */
-    private String allowParallel;
-
     /** Test failure handler. */
     private TestStopNodeFailureHandler failureHnd;
 
@@ -59,23 +57,6 @@
     }
 
     /** {@inheritDoc} */
-    @Override protected void beforeTestsStarted() throws Exception {
-        super.beforeTestsStarted();
-
-        allowParallel = System.getProperty(IGNITE_ALLOW_START_CACHES_IN_PARALLEL);
-    }
-
-    /** {@inheritDoc} */
-    @Override protected void afterTestsStopped() throws Exception {
-        super.afterTestsStopped();
-
-        if (allowParallel != null)
-            System.setProperty(IGNITE_ALLOW_START_CACHES_IN_PARALLEL, allowParallel);
-        else
-            System.clearProperty(IGNITE_ALLOW_START_CACHES_IN_PARALLEL);
-    }
-
-    /** {@inheritDoc} */
     @Override protected void beforeTest() throws Exception {
         super.beforeTest();
 
@@ -95,36 +76,34 @@
 
     /** */
     @Test
+    @WithSystemProperty(key = IGNITE_ALLOW_START_CACHES_IN_PARALLEL, value = "true")
     public void testWithEnabledOption() throws Exception {
-        doTest("true");
+        doTest();
     }
 
     /** */
     @Test
+    @WithSystemProperty(key = IGNITE_ALLOW_START_CACHES_IN_PARALLEL, value = "true")
     public void testWithDisabledOption() throws Exception {
-        doTest("false");
+        doTest();
     }
 
     /** */
     @Test
+    @WithSystemProperty(key = IGNITE_ALLOW_START_CACHES_IN_PARALLEL, value = "")
     public void testWithoutOption() throws Exception {
-        doTest(null);
+        System.clearProperty(IGNITE_ALLOW_START_CACHES_IN_PARALLEL);
+
+        doTest();
     }
 
     /**
      * Test routine.
      *
-     * @param optionVal IGNITE_ALLOW_START_CACHES_IN_PARALLEL value.
      * @throws Exception If failed.
      */
-    private void doTest(String optionVal) throws Exception {
-        if (optionVal == null)
-            System.clearProperty(IGNITE_ALLOW_START_CACHES_IN_PARALLEL);
-        else {
-            Boolean.parseBoolean(optionVal);
-
-            System.setProperty(IGNITE_ALLOW_START_CACHES_IN_PARALLEL, optionVal);
-        }
+    private void doTest() throws Exception {
+        String optionVal = System.getProperty(IGNITE_ALLOW_START_CACHES_IN_PARALLEL);
 
         assertEquals("Property wasn't set", optionVal, System.getProperty(IGNITE_ALLOW_START_CACHES_IN_PARALLEL));
 
diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/distributed/near/IgniteCacheDistributedPartitionQueryNodeRestartsSelfTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/distributed/near/IgniteCacheDistributedPartitionQueryNodeRestartsSelfTest.java
index 7e2f8b6..7c584ac 100644
--- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/distributed/near/IgniteCacheDistributedPartitionQueryNodeRestartsSelfTest.java
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/distributed/near/IgniteCacheDistributedPartitionQueryNodeRestartsSelfTest.java
@@ -21,34 +21,20 @@
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicIntegerArray;
-
 import org.apache.ignite.Ignite;
-import org.apache.ignite.IgniteSystemProperties;
 import org.apache.ignite.internal.IgniteInternalFuture;
-import org.apache.ignite.internal.processors.query.h2.twostep.GridReduceQueryExecutor;
 import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.testframework.junits.WithSystemProperty;
 import org.junit.Test;
 
+import static org.apache.ignite.IgniteSystemProperties.IGNITE_SQL_RETRY_TIMEOUT;
+
 /**
  * Tests distributed queries over set of partitions on unstable topology.
  */
+@WithSystemProperty(key = IGNITE_SQL_RETRY_TIMEOUT, value = "1000000")
 public class IgniteCacheDistributedPartitionQueryNodeRestartsSelfTest extends
     IgniteCacheDistributedPartitionQueryAbstractSelfTest {
-    /** {@inheritDoc} */
-    @Override protected void beforeTestsStarted() throws Exception {
-        super.beforeTestsStarted();
-
-        System.setProperty(IgniteSystemProperties.IGNITE_SQL_RETRY_TIMEOUT, Long.toString(1000_000L));
-    }
-
-    /** {@inheritDoc} */
-    @Override protected void afterTestsStopped() throws Exception {
-        System.setProperty(IgniteSystemProperties.IGNITE_SQL_RETRY_TIMEOUT,
-            Long.toString(GridReduceQueryExecutor.DFLT_RETRY_TIMEOUT));
-
-        super.afterTestsStopped();
-    }
-
     /**
      * Tests join query within region on unstable topology.
      */
diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/distributed/near/IgniteCacheQueryNodeRestartDistributedJoinSelfTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/distributed/near/IgniteCacheQueryNodeRestartDistributedJoinSelfTest.java
index 406eaa5..eb5b3d9 100644
--- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/distributed/near/IgniteCacheQueryNodeRestartDistributedJoinSelfTest.java
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/distributed/near/IgniteCacheQueryNodeRestartDistributedJoinSelfTest.java
@@ -17,36 +17,35 @@
 
 package org.apache.ignite.internal.processors.cache.distributed.near;
 
-import org.apache.ignite.IgniteCache;
-import org.apache.ignite.IgniteCheckedException;
-import org.apache.ignite.IgniteSystemProperties;
-import org.apache.ignite.cache.query.SqlFieldsQuery;
-import org.apache.ignite.internal.IgniteInternalFuture;
-import org.apache.ignite.internal.processors.query.h2.twostep.GridReduceQueryExecutor;
-import org.apache.ignite.internal.util.GridRandom;
-import org.apache.ignite.internal.util.typedef.CAX;
-import org.apache.ignite.internal.util.typedef.X;
-
-import javax.cache.CacheException;
 import java.util.List;
 import java.util.concurrent.Callable;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicIntegerArray;
+import javax.cache.CacheException;
+import org.apache.ignite.IgniteCache;
+import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.cache.query.SqlFieldsQuery;
+import org.apache.ignite.internal.IgniteInternalFuture;
+import org.apache.ignite.internal.util.GridRandom;
+import org.apache.ignite.internal.util.typedef.CAX;
+import org.apache.ignite.internal.util.typedef.X;
 import org.apache.ignite.testframework.GridTestUtils;
+import org.apache.ignite.testframework.junits.WithSystemProperty;
 import org.junit.Test;
 
+import static org.apache.ignite.IgniteSystemProperties.IGNITE_SQL_RETRY_TIMEOUT;
+
 /**
  * Test for distributed queries with node restarts.
  */
+@WithSystemProperty(key = IGNITE_SQL_RETRY_TIMEOUT, value = "1000000")
 public class IgniteCacheQueryNodeRestartDistributedJoinSelfTest extends IgniteCacheQueryAbstractDistributedJoinSelfTest {
     /** Total nodes. */
     private int totalNodes = 6;
 
     /** {@inheritDoc} */
     @Override protected void beforeTestsStarted() throws Exception {
-        System.setProperty(IgniteSystemProperties.IGNITE_SQL_RETRY_TIMEOUT, Long.toString(1000_000L));
-
         super.beforeTestsStarted();
 
         if (totalNodes > GRID_CNT) {
@@ -57,12 +56,6 @@
             totalNodes = GRID_CNT;
     }
 
-    /** {@inheritDoc} */
-    @Override protected void afterTestsStopped() throws Exception {
-        System.setProperty(IgniteSystemProperties.IGNITE_SQL_RETRY_TIMEOUT,
-            Long.toString(GridReduceQueryExecutor.DFLT_RETRY_TIMEOUT));
-    }
-
     /**
      * @throws Exception If failed.
      */
diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/DynamicIndexAbstractBasicSelfTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/DynamicIndexAbstractBasicSelfTest.java
index 68f233b..ff02d4a 100644
--- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/DynamicIndexAbstractBasicSelfTest.java
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/DynamicIndexAbstractBasicSelfTest.java
@@ -23,7 +23,6 @@
 import java.util.concurrent.Callable;
 import javax.cache.CacheException;
 import org.apache.ignite.Ignite;
-import org.apache.ignite.IgniteSystemProperties;
 import org.apache.ignite.Ignition;
 import org.apache.ignite.cache.CacheAtomicityMode;
 import org.apache.ignite.cache.CacheMode;
@@ -38,8 +37,10 @@
 import org.apache.ignite.internal.processors.query.schema.SchemaOperationException;
 import org.apache.ignite.internal.util.typedef.F;
 import org.apache.ignite.testframework.GridTestUtils;
+import org.apache.ignite.testframework.junits.WithSystemProperty;
 import org.junit.Test;
 
+import static org.apache.ignite.IgniteSystemProperties.IGNITE_SQL_PARSER_DISABLE_H2_FALLBACK;
 import static org.apache.ignite.cache.CacheAtomicityMode.ATOMIC;
 import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL;
 import static org.apache.ignite.cache.CacheMode.PARTITIONED;
@@ -658,6 +659,7 @@
      * @throws Exception If failed.
      */
     @Test
+    @WithSystemProperty(key = IGNITE_SQL_PARSER_DISABLE_H2_FALLBACK, value = "true")
     public void testCreateIndexWithInlineSizePartitionedAtomic() throws Exception {
         checkCreateIndexWithInlineSize(PARTITIONED, ATOMIC, false);
     }
@@ -668,6 +670,7 @@
      * @throws Exception If failed.
      */
     @Test
+    @WithSystemProperty(key = IGNITE_SQL_PARSER_DISABLE_H2_FALLBACK, value = "true")
     public void testCreateIndexWithInlineSizePartitionedAtomicNear() throws Exception {
         checkCreateIndexWithInlineSize(PARTITIONED, ATOMIC, true);
     }
@@ -678,6 +681,7 @@
      * @throws Exception If failed.
      */
     @Test
+    @WithSystemProperty(key = IGNITE_SQL_PARSER_DISABLE_H2_FALLBACK, value = "true")
     public void testCreateIndexWithInlineSizePartitionedTransactional() throws Exception {
         checkCreateIndexWithInlineSize(PARTITIONED, TRANSACTIONAL, false);
     }
@@ -688,6 +692,7 @@
      * @throws Exception If failed.
      */
     @Test
+    @WithSystemProperty(key = IGNITE_SQL_PARSER_DISABLE_H2_FALLBACK, value = "true")
     public void testCreateIndexWithInlineSizePartitionedTransactionalNear() throws Exception {
         checkCreateIndexWithInlineSize(PARTITIONED, TRANSACTIONAL, true);
     }
@@ -698,6 +703,7 @@
      * @throws Exception If failed.
      */
     @Test
+    @WithSystemProperty(key = IGNITE_SQL_PARSER_DISABLE_H2_FALLBACK, value = "true")
     public void testCreateIndexWithInlineSizeReplicatedAtomic() throws Exception {
         checkCreateIndexWithInlineSize(REPLICATED, ATOMIC, false);
     }
@@ -708,6 +714,7 @@
      * @throws Exception If failed.
      */
     @Test
+    @WithSystemProperty(key = IGNITE_SQL_PARSER_DISABLE_H2_FALLBACK, value = "true")
     public void testCreateIndexWithInlineSizeReplicatedTransactional() throws Exception {
         checkCreateIndexWithInlineSize(REPLICATED, TRANSACTIONAL, false);
     }
@@ -725,26 +732,14 @@
 
         initialize(mode, atomicityMode, near);
 
-        String prevFallbackPropVal = System.getProperty(IgniteSystemProperties.IGNITE_SQL_PARSER_DISABLE_H2_FALLBACK);
+        checkNoIndexIsCreatedForInlineSize(-2, IgniteQueryErrorCode.PARSING);
+        checkNoIndexIsCreatedForInlineSize(Integer.MIN_VALUE, IgniteQueryErrorCode.PARSING);
 
-        try {
-            System.setProperty(IgniteSystemProperties.IGNITE_SQL_PARSER_DISABLE_H2_FALLBACK, "true");
-
-            checkNoIndexIsCreatedForInlineSize(-2, IgniteQueryErrorCode.PARSING);
-            checkNoIndexIsCreatedForInlineSize(Integer.MIN_VALUE, IgniteQueryErrorCode.PARSING);
-
-            checkIndexCreatedForInlineSize(0);
-            loadInitialData();
-            checkIndexCreatedForInlineSize(1);
-            loadInitialData();
-            checkIndexCreatedForInlineSize(Integer.MAX_VALUE);
-        }
-        finally {
-            if (prevFallbackPropVal != null)
-                System.setProperty(IgniteSystemProperties.IGNITE_SQL_PARSER_DISABLE_H2_FALLBACK, prevFallbackPropVal);
-            else
-                System.clearProperty(IgniteSystemProperties.IGNITE_SQL_PARSER_DISABLE_H2_FALLBACK);
-        }
+        checkIndexCreatedForInlineSize(0);
+        loadInitialData();
+        checkIndexCreatedForInlineSize(1);
+        loadInitialData();
+        checkIndexCreatedForInlineSize(Integer.MAX_VALUE);
     }
 
     /**
@@ -794,6 +789,7 @@
      * @throws Exception If failed.
      */
     @Test
+    @WithSystemProperty(key = IGNITE_SQL_PARSER_DISABLE_H2_FALLBACK, value = "true")
     public void testCreateIndexWithParallelismPartitionedAtomic() throws Exception {
         checkCreateIndexWithParallelism(PARTITIONED, ATOMIC, false);
     }
@@ -804,6 +800,7 @@
      * @throws Exception If failed.
      */
     @Test
+    @WithSystemProperty(key = IGNITE_SQL_PARSER_DISABLE_H2_FALLBACK, value = "true")
     public void testCreateIndexWithParallelismPartitionedAtomicNear() throws Exception {
         checkCreateIndexWithParallelism(PARTITIONED, ATOMIC, true);
     }
@@ -814,6 +811,7 @@
      * @throws Exception If failed.
      */
     @Test
+    @WithSystemProperty(key = IGNITE_SQL_PARSER_DISABLE_H2_FALLBACK, value = "true")
     public void testCreateIndexWithParallelismPartitionedTransactional() throws Exception {
         checkCreateIndexWithParallelism(PARTITIONED, TRANSACTIONAL, false);
     }
@@ -824,6 +822,7 @@
      * @throws Exception If failed.
      */
     @Test
+    @WithSystemProperty(key = IGNITE_SQL_PARSER_DISABLE_H2_FALLBACK, value = "true")
     public void testCreateIndexWithParallelismPartitionedTransactionalNear() throws Exception {
         checkCreateIndexWithParallelism(PARTITIONED, TRANSACTIONAL, true);
     }
@@ -834,6 +833,7 @@
      * @throws Exception If failed.
      */
     @Test
+    @WithSystemProperty(key = IGNITE_SQL_PARSER_DISABLE_H2_FALLBACK, value = "true")
     public void testCreateIndexWithParallelismReplicatedAtomic() throws Exception {
         checkCreateIndexWithParallelism(REPLICATED, ATOMIC, false);
     }
@@ -844,6 +844,7 @@
      * @throws Exception If failed.
      */
     @Test
+    @WithSystemProperty(key = IGNITE_SQL_PARSER_DISABLE_H2_FALLBACK, value = "true")
     public void testCreateIndexWithParallelismReplicatedTransactional() throws Exception {
         checkCreateIndexWithParallelism(REPLICATED, TRANSACTIONAL, false);
     }
@@ -861,26 +862,14 @@
 
         initialize(mode, atomicityMode, near);
 
-        String prevFallbackPropVal = System.getProperty(IgniteSystemProperties.IGNITE_SQL_PARSER_DISABLE_H2_FALLBACK);
+        checkNoIndexIsCreatedForParallelism(-2, IgniteQueryErrorCode.PARSING);
+        checkNoIndexIsCreatedForParallelism(Integer.MIN_VALUE, IgniteQueryErrorCode.PARSING);
 
-        try {
-            System.setProperty(IgniteSystemProperties.IGNITE_SQL_PARSER_DISABLE_H2_FALLBACK, "true");
-
-            checkNoIndexIsCreatedForParallelism(-2, IgniteQueryErrorCode.PARSING);
-            checkNoIndexIsCreatedForParallelism(Integer.MIN_VALUE, IgniteQueryErrorCode.PARSING);
-
-            checkIndexCreatedForParallelism(0);
-            loadInitialData();
-            checkIndexCreatedForParallelism(1);
-            loadInitialData();
-            checkIndexCreatedForParallelism(5);
-        }
-        finally {
-            if (prevFallbackPropVal != null)
-                System.setProperty(IgniteSystemProperties.IGNITE_SQL_PARSER_DISABLE_H2_FALLBACK, prevFallbackPropVal);
-            else
-                System.clearProperty(IgniteSystemProperties.IGNITE_SQL_PARSER_DISABLE_H2_FALLBACK);
-        }
+        checkIndexCreatedForParallelism(0);
+        loadInitialData();
+        checkIndexCreatedForParallelism(1);
+        loadInitialData();
+        checkIndexCreatedForParallelism(5);
     }
 
     /**
diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/H2DynamicTableSelfTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/H2DynamicTableSelfTest.java
index b2774d8..701ceda 100644
--- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/H2DynamicTableSelfTest.java
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/H2DynamicTableSelfTest.java
@@ -35,6 +35,7 @@
 import java.util.concurrent.Callable;
 import java.util.function.Consumer;
 import org.apache.ignite.Ignite;
+import org.apache.ignite.IgniteCache;
 import org.apache.ignite.IgniteException;
 import org.apache.ignite.Ignition;
 import org.apache.ignite.binary.BinaryObject;
@@ -131,7 +132,7 @@
         execute("DROP TABLE IF EXISTS PUBLIC.\"City\"");
         execute("DROP TABLE IF EXISTS PUBLIC.\"NameTest\"");
         execute("DROP TABLE IF EXISTS PUBLIC.\"BackupTest\"");
-        
+
         execute("DROP TABLE IF EXISTS PUBLIC.QP_CUSTOM");
         execute("DROP TABLE IF EXISTS PUBLIC.QP_DEFAULT");
         execute("DROP TABLE IF EXISTS PUBLIC.QP_DEFAULT_EXPLICIT");
@@ -802,6 +803,39 @@
     }
 
     /**
+     * Regression test for "if not exists" in case custom schema is used. Creates the same "schema.table" specifying sql
+     * schema implicitly and explicitly.
+     */
+    @Test
+    public void testCreateTableIfNotExistsCustomSchema() {
+        Ignite ignite = grid(0);
+
+        IgniteCache<Object, Object> cache = ignite.getOrCreateCache("test");
+
+        String createTblNoSchema = "CREATE TABLE IF NOT EXISTS City(id LONG PRIMARY KEY, name VARCHAR)";
+
+        String createTblExplicitSchema = "CREATE TABLE IF NOT EXISTS \"test\".City(id LONG PRIMARY KEY, name1 VARCHAR);";
+
+        // Schema is "test" due to cache name implicitly:
+        cache.query(new SqlFieldsQuery(createTblNoSchema));
+        cache.query(new SqlFieldsQuery(createTblNoSchema));
+
+        // Schema is "test" because it is specified in the text of the sql query.
+        cache.query(new SqlFieldsQuery(createTblExplicitSchema));
+        cache.query(new SqlFieldsQuery(createTblExplicitSchema));
+
+        // Schema is "test", because it is specified in SqlFieldsQuery field.
+        cache.query(new SqlFieldsQuery(createTblNoSchema).setSchema("test"));
+        cache.query(new SqlFieldsQuery(createTblNoSchema).setSchema("test"));
+
+        //only one City table should be created.
+        List<List<?>> cityTabs = cache.query(new SqlFieldsQuery(
+            "SELECT SCHEMA_NAME, TABLE_NAME FROM IGNITE.TABLES WHERE TABLE_NAME = 'CITY';")).getAll();
+
+        assertEqualsCollections(Collections.singletonList(Arrays.asList("test", "CITY")), cityTabs);
+    }
+
+    /**
      * Test that attempting to {@code CREATE TABLE} that already exists yields an error.
      * @throws Exception if failed.
      */
diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/SqlTransactionsCommandsWithMvccEnabledSelfTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/SqlTransactionsCommandsWithMvccEnabledSelfTest.java
index 5253f83..95ed2eb 100644
--- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/SqlTransactionsCommandsWithMvccEnabledSelfTest.java
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/SqlTransactionsCommandsWithMvccEnabledSelfTest.java
@@ -128,7 +128,7 @@
     /**
      * Test that attempting to perform various SQL operations within non SQL transaction yields an exception.
      */
-    @Ignore("https://issues.apache.org/jira/browse/IGNITE-9470")
+    @Ignore("https://issues.apache.org/jira/browse/IGNITE-11357")
     @Test
     public void testSqlOperationsWithinNonSqlTransaction() {
         assertSqlOperationWithinNonSqlTransactionThrows("COMMIT");
diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/mvcc/CacheMvccBasicContinuousQueryTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/mvcc/CacheMvccBasicContinuousQueryTest.java
index 7f345ff..e0d4971 100644
--- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/mvcc/CacheMvccBasicContinuousQueryTest.java
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/mvcc/CacheMvccBasicContinuousQueryTest.java
@@ -54,7 +54,6 @@
 import org.apache.ignite.plugin.extensions.communication.Message;
 import org.apache.ignite.testframework.GridTestUtils;
 import org.apache.ignite.transactions.Transaction;
-import org.junit.Ignore;
 import org.junit.Test;
 
 import static java.util.concurrent.TimeUnit.MILLISECONDS;
@@ -255,7 +254,6 @@
     /**
      * @throws Exception  If failed.
      */
-    @Ignore("https://issues.apache.org/jira/browse/IGNITE-10768")
     @Test
     public void testUpdateCountersGapClosedSimplePartitioned() throws Exception {
         checkUpdateCountersGapIsProcessedSimple(CacheMode.PARTITIONED);
@@ -275,7 +273,9 @@
     private void checkUpdateCountersGapIsProcessedSimple(CacheMode cacheMode) throws Exception {
         testSpi = true;
 
-        int srvCnt = 4;
+        final int srvCnt = 4;
+
+        final int backups = srvCnt - 1;
 
         startGridsMultiThreaded(srvCnt);
 
@@ -284,7 +284,7 @@
         IgniteEx nearNode = startGrid(srvCnt);
 
         IgniteCache<Object, Object> cache = nearNode.createCache(
-            cacheConfiguration(cacheMode, FULL_SYNC, srvCnt - 1, srvCnt)
+            cacheConfiguration(cacheMode, FULL_SYNC, backups, srvCnt)
                 .setIndexedTypes(Integer.class, Integer.class));
 
         IgniteEx primary = grid(0);
@@ -312,17 +312,15 @@
         // Initial value.
         cache.query(new SqlFieldsQuery("insert into Integer(_key, _val) values(?, 42)").setArgs(keys.get(0))).getAll();
 
-        Transaction txA = nearNode.transactions().txStart(PESSIMISTIC, REPEATABLE_READ);
-
         // prevent first transaction prepare on backups
         TestRecordingCommunicationSpi spi = TestRecordingCommunicationSpi.spi(primary);
 
-        spi.blockMessages(new IgniteBiPredicate<ClusterNode, Message>() {
-                private final AtomicInteger limiter = new AtomicInteger();
+        final AtomicInteger dhtPrepMsgLimiter = new AtomicInteger();
 
+        spi.blockMessages(new IgniteBiPredicate<ClusterNode, Message>() {
                 @Override public boolean apply(ClusterNode node, Message msg) {
                     if (msg instanceof GridDhtTxPrepareRequest)
-                        return limiter.getAndIncrement() < srvCnt - 1;
+                        return dhtPrepMsgLimiter.getAndIncrement() < backups;
 
                     if (msg instanceof GridContinuousMessage)
                         return true;
@@ -331,16 +329,32 @@
                 }
             });
 
+        // First tx. Expect it will be prepared only on the primary node and GridDhtTxPrepareRequests to remotes
+        // will be swallowed.
+        Transaction txA = nearNode.transactions().txStart(PESSIMISTIC, REPEATABLE_READ);
+
         cache.query(new SqlFieldsQuery("insert into Integer(_key, _val) values(?, 42)").setArgs(keys.get(1))).getAll();
 
         txA.commitAsync();
 
+        // Wait until first tx changes it's status to PREPARING.
         GridTestUtils.waitForCondition(new GridAbsPredicate() {
             @Override public boolean apply() {
-                return nearNode.context().cache().context().tm().activeTransactions().stream().allMatch(tx -> tx.state() == PREPARING);
+                boolean preparing = nearNode.context()
+                    .cache()
+                    .context()
+                    .tm()
+                    .activeTransactions()
+                    .stream()
+                    .allMatch(tx -> tx.state() == PREPARING);
+
+                boolean allPrepsSwallowed = dhtPrepMsgLimiter.get() == backups;
+
+                return preparing && allPrepsSwallowed;
             }
         }, 3_000);
 
+        // Second tx.
         GridTestUtils.runAsync(() -> {
             try (Transaction txB = nearNode.transactions().txStart(PESSIMISTIC, REPEATABLE_READ)) {
                 cache.query(new SqlFieldsQuery("insert into Integer(_key, _val) values(?, 42)").setArgs(keys.get(2)));
@@ -351,7 +365,7 @@
 
         long primaryUpdCntr = getUpdateCounter(primary, keys.get(0));
 
-        assertEquals(3, primaryUpdCntr); // There were three updates.
+        assertEquals(3, primaryUpdCntr); // There were three updates: init, first and second.
 
         // drop primary
         stopGrid(primary.name());
diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/mvcc/CacheMvccPartitionedSqlQueriesTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/mvcc/CacheMvccPartitionedSqlQueriesTest.java
index e0b4a24..6bca3c2 100644
--- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/mvcc/CacheMvccPartitionedSqlQueriesTest.java
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/mvcc/CacheMvccPartitionedSqlQueriesTest.java
@@ -24,7 +24,7 @@
 /** */
 public class CacheMvccPartitionedSqlQueriesTest extends CacheMvccSqlQueriesAbstractTest {
     /** {@inheritDoc} */
-    protected CacheMode cacheMode() {
+    @Override protected CacheMode cacheMode() {
         return PARTITIONED;
     }
 }
diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/mvcc/CacheMvccReplicatedSqlQueriesTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/mvcc/CacheMvccReplicatedSqlQueriesTest.java
index ba8a5c3..3522879 100644
--- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/mvcc/CacheMvccReplicatedSqlQueriesTest.java
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/mvcc/CacheMvccReplicatedSqlQueriesTest.java
@@ -24,7 +24,7 @@
 /** */
 public class CacheMvccReplicatedSqlQueriesTest extends CacheMvccSqlQueriesAbstractTest {
     /** {@inheritDoc} */
-    protected CacheMode cacheMode() {
+    @Override protected CacheMode cacheMode() {
         return REPLICATED;
     }
 }
diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/mvcc/CacheMvccSqlQueriesAbstractTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/mvcc/CacheMvccSqlQueriesAbstractTest.java
index e9937b2..6d89cfb 100644
--- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/mvcc/CacheMvccSqlQueriesAbstractTest.java
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/mvcc/CacheMvccSqlQueriesAbstractTest.java
@@ -28,6 +28,7 @@
 import java.util.TreeMap;
 import java.util.concurrent.ThreadLocalRandom;
 import java.util.concurrent.atomic.AtomicBoolean;
+import javax.cache.CacheException;
 import javax.cache.processor.MutableEntry;
 import org.apache.ignite.Ignite;
 import org.apache.ignite.IgniteCache;
@@ -41,8 +42,8 @@
 import org.apache.ignite.internal.util.typedef.G;
 import org.apache.ignite.internal.util.typedef.internal.S;
 import org.apache.ignite.lang.IgniteInClosure;
+import org.apache.ignite.testframework.MvccFeatureChecker;
 import org.apache.ignite.transactions.Transaction;
-import org.junit.Ignore;
 import org.junit.Test;
 
 import static org.apache.ignite.cache.CacheWriteSynchronizationMode.FULL_SYNC;
@@ -53,10 +54,7 @@
 import static org.apache.ignite.transactions.TransactionIsolation.REPEATABLE_READ;
 
 /**
- * TODO IGNITE-6739: text/spatial indexes with mvcc.
- * TODO IGNITE-6739: indexingSpi with mvcc.
- * TODO IGNITE-6739: setQueryParallelism with mvcc.
- * TODO IGNITE-6739: dynamic index create.
+ *
  */
 @SuppressWarnings("unchecked")
 public abstract class CacheMvccSqlQueriesAbstractTest extends CacheMvccAbstractTest {
@@ -137,7 +135,6 @@
     /**
      * @throws Exception If failed.
      */
-    @Ignore("https://issues.apache.org/jira/browse/IGNITE-9470")
     @Test
     public void testUpdateSingleValue_SingleNode() throws Exception {
         updateSingleValue(true, false);
@@ -146,7 +143,6 @@
     /**
      * @throws Exception If failed.
      */
-    @Ignore("https://issues.apache.org/jira/browse/IGNITE-9470")
     @Test
     public void testUpdateSingleValue_LocalQuery_SingleNode() throws Exception {
         updateSingleValue(true, true);
@@ -155,7 +151,6 @@
     /**
      * @throws Exception If failed.
      */
-    @Ignore("https://issues.apache.org/jira/browse/IGNITE-9470")
     @Test
     public void testUpdateSingleValue_ClientServer() throws Exception {
         updateSingleValue(false, false);
@@ -167,8 +162,6 @@
      * @throws Exception If failed.
      */
     private void updateSingleValue(boolean singleNode, final boolean locQry) throws Exception {
-        fail("https://issues.apache.org/jira/browse/IGNITE-9470");
-
         final int VALS = 100;
 
         final int writers = 4;
@@ -201,30 +194,40 @@
                         try {
                             Integer key = rnd.nextInt(VALS);
 
-                            cache.cache.invoke(key, new CacheEntryProcessor<Integer, MvccTestSqlIndexValue, Object>() {
-                                @Override public Object process(MutableEntry<Integer, MvccTestSqlIndexValue> e, Object... args) {
-                                    Integer key = e.getKey();
+                            while (true) {
+                                try {
+                                    cache.cache.invoke(key, new CacheEntryProcessor<Integer, MvccTestSqlIndexValue, Object>() {
+                                        @Override public Object process(MutableEntry<Integer, MvccTestSqlIndexValue> e,
+                                            Object... args) {
+                                            Integer key = e.getKey();
 
-                                    MvccTestSqlIndexValue val = e.getValue();
+                                            MvccTestSqlIndexValue val = e.getValue();
 
-                                    int newIdxVal;
+                                            int newIdxVal;
 
-                                    if (val.idxVal1 < INC_BY) {
-                                        assertEquals(key.intValue(), val.idxVal1);
+                                            if (val.idxVal1 < INC_BY) {
+                                                assertEquals(key.intValue(), val.idxVal1);
 
-                                        newIdxVal = val.idxVal1 + INC_BY;
-                                    }
-                                    else {
-                                        assertEquals(INC_BY + key, val.idxVal1);
+                                                newIdxVal = val.idxVal1 + INC_BY;
+                                            }
+                                            else {
+                                                assertEquals(INC_BY + key, val.idxVal1);
 
-                                        newIdxVal = key;
-                                    }
+                                                newIdxVal = key;
+                                            }
 
-                                    e.setValue(new MvccTestSqlIndexValue(newIdxVal));
+                                            e.setValue(new MvccTestSqlIndexValue(newIdxVal));
 
-                                    return null;
+                                            return null;
+                                        }
+                                    });
+
+                                    break;
                                 }
-                            });
+                                catch (CacheException e) {
+                                    MvccFeatureChecker.assertMvccWriteConflict(e);
+                                }
+                            }
                         }
                         finally {
                             cache.readUnlock();
@@ -371,7 +374,6 @@
     /**
      * @throws Exception If failed.
      */
-    @Ignore("https://issues.apache.org/jira/browse/IGNITE-9470")
     @Test
     public void testJoinTransactional_SingleNode() throws Exception {
         joinTransactional(true, false);
@@ -380,7 +382,6 @@
     /**
      * @throws Exception If failed.
      */
-    @Ignore("https://issues.apache.org/jira/browse/IGNITE-9470")
     @Test
     public void testJoinTransactional_ClientServer() throws Exception {
         joinTransactional(false, false);
@@ -389,7 +390,6 @@
     /**
      * @throws Exception If failed.
      */
-    @Ignore("https://issues.apache.org/jira/browse/IGNITE-9470")
     @Test
     public void testJoinTransactional_DistributedJoins_ClientServer() throws Exception {
         joinTransactional(false, true);
@@ -401,8 +401,6 @@
      * @throws Exception If failed.
      */
     private void joinTransactional(boolean singleNode, final boolean distributedJoin) throws Exception {
-        fail("https://issues.apache.org/jira/browse/IGNITE-9470");
-
         final int KEYS = 100;
 
         final int writers = 4;
@@ -422,31 +420,38 @@
                         IgniteTransactions txs = cache.cache.unwrap(Ignite.class).transactions();
 
                         try {
-                            try (Transaction tx = txs.txStart(PESSIMISTIC, REPEATABLE_READ)) {
-                                Integer key = rnd.nextInt(KEYS);
+                            while (true) {
+                                try (Transaction tx = txs.txStart(PESSIMISTIC, REPEATABLE_READ)) {
+                                    Integer key = rnd.nextInt(KEYS);
 
-                                JoinTestChildKey childKey = new JoinTestChildKey(key);
+                                    JoinTestChildKey childKey = new JoinTestChildKey(key);
 
-                                JoinTestChild child = (JoinTestChild)cache.cache.get(childKey);
+                                    JoinTestChild child = (JoinTestChild)cache.cache.get(childKey);
 
-                                if (child == null) {
-                                    Integer parentKey = distributedJoin ? key + 100 : key;
+                                    if (child == null) {
+                                        int parentKey = distributedJoin ? key + 100 : key;
 
-                                    child = new JoinTestChild(parentKey);
+                                        child = new JoinTestChild(parentKey);
 
-                                    cache.cache.put(childKey, child);
+                                        cache.cache.put(childKey, child);
 
-                                    JoinTestParent parent = new JoinTestParent(parentKey);
+                                        JoinTestParent parent = new JoinTestParent(parentKey);
 
-                                    cache.cache.put(new JoinTestParentKey(parentKey), parent);
+                                        cache.cache.put(new JoinTestParentKey(parentKey), parent);
+                                    }
+                                    else {
+                                        cache.cache.remove(childKey);
+
+                                        cache.cache.remove(new JoinTestParentKey(child.parentId));
+                                    }
+
+                                    tx.commit();
+
+                                    break;
                                 }
-                                else {
-                                    cache.cache.remove(childKey);
-
-                                    cache.cache.remove(new JoinTestParentKey(child.parentId));
+                                catch (CacheException e) {
+                                    MvccFeatureChecker.assertMvccWriteConflict(e);
                                 }
-
-                                tx.commit();
                             }
 
                             cnt++;
diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/mvcc/CacheMvccSqlTxQueriesAbstractTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/mvcc/CacheMvccSqlTxQueriesAbstractTest.java
index d4b4620..2047d1c 100644
--- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/mvcc/CacheMvccSqlTxQueriesAbstractTest.java
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/mvcc/CacheMvccSqlTxQueriesAbstractTest.java
@@ -68,7 +68,7 @@
 import org.apache.ignite.testframework.MvccFeatureChecker;
 import org.apache.ignite.transactions.Transaction;
 import org.apache.ignite.transactions.TransactionDuplicateKeyException;
-import org.junit.Ignore;
+import org.apache.ignite.transactions.TransactionSerializationException;
 import org.junit.Test;
 
 import static org.apache.ignite.cache.CacheWriteSynchronizationMode.FULL_SYNC;
@@ -1219,7 +1219,6 @@
     /**
      * @throws Exception If failed.
      */
-    @Ignore("https://issues.apache.org/jira/browse/IGNITE-9470")
     @Test
     public void testQueryInsertUpdateMultithread() throws Exception {
         ccfg = cacheConfiguration(cacheMode(), FULL_SYNC, 2, DFLT_PARTITION_COUNT)
@@ -1237,26 +1236,33 @@
                 IgniteEx node = grid(0);
 
                 try {
-                    try (Transaction tx = node.transactions().txStart(PESSIMISTIC, REPEATABLE_READ)) {
-                        tx.timeout(TX_TIMEOUT);
+                    while (true) {
+                        try (Transaction tx = node.transactions().txStart(PESSIMISTIC, REPEATABLE_READ)) {
+                            tx.timeout(TX_TIMEOUT);
 
-                        IgniteCache<Object, Object> cache0 = node.cache(DEFAULT_CACHE_NAME);
+                            IgniteCache<Object, Object> cache0 = node.cache(DEFAULT_CACHE_NAME);
 
-                        SqlFieldsQuery qry = new SqlFieldsQuery("INSERT INTO Integer (_key, _val) values (1,1),(2,2),(3,3)");
+                            SqlFieldsQuery qry = new SqlFieldsQuery("INSERT INTO Integer (_key, _val) values (1,1),(2,2),(3,3)");
 
-                        try (FieldsQueryCursor<List<?>> cur = cache0.query(qry)) {
-                            cur.getAll();
+                            try (FieldsQueryCursor<List<?>> cur = cache0.query(qry)) {
+                                cur.getAll();
+                            }
+
+                            awaitPhase(phaser, 2);
+
+                            qry = new SqlFieldsQuery("INSERT INTO Integer (_key, _val) values (4,4),(5,5),(6,6)");
+
+                            try (FieldsQueryCursor<List<?>> cur = cache0.query(qry)) {
+                                cur.getAll();
+                            }
+
+                            tx.commit();
+
+                            break;
                         }
-
-                        awaitPhase(phaser, 2);
-
-                        qry = new SqlFieldsQuery("INSERT INTO Integer (_key, _val) values (4,4),(5,5),(6,6)");
-
-                        try (FieldsQueryCursor<List<?>> cur = cache0.query(qry)) {
-                            cur.getAll();
+                        catch (CacheException e) {
+                            MvccFeatureChecker.assertMvccWriteConflict(e);
                         }
-
-                        tx.commit();
                     }
                 }
                 catch (Exception e) {
@@ -1272,24 +1278,30 @@
                 try {
                     phaser.arriveAndAwaitAdvance();
 
-                    try (Transaction tx = node.transactions().txStart(PESSIMISTIC, REPEATABLE_READ)) {
-                        tx.timeout(TX_TIMEOUT);
+                    while (true) {
+                        try (Transaction tx = node.transactions().txStart(PESSIMISTIC, REPEATABLE_READ)) {
+                            tx.timeout(TX_TIMEOUT);
 
-                        IgniteCache<Integer, Integer> cache0 = node.cache(DEFAULT_CACHE_NAME);
+                            IgniteCache<Integer, Integer> cache0 = node.cache(DEFAULT_CACHE_NAME);
 
-                        cache0.invokeAllAsync(F.asSet(1, 2, 3, 4, 5, 6), new EntryProcessor<Integer, Integer, Void>() {
-                            @Override
-                            public Void process(MutableEntry<Integer, Integer> entry,
-                                Object... arguments) throws EntryProcessorException {
-                                entry.setValue(entry.getValue() * 10);
+                            cache0.invokeAllAsync(F.asSet(1, 2, 3, 4, 5, 6), new EntryProcessor<Integer, Integer, Void>() {
+                                @Override public Void process(MutableEntry<Integer, Integer> entry,
+                                    Object... arguments) throws EntryProcessorException {
+                                    entry.setValue(entry.getValue() * 10);
 
-                                return null;
-                            }
-                        });
+                                    return null;
+                                }
+                            });
 
-                        phaser.arrive();
+                            phaser.arrive();
 
-                        tx.commit();
+                            tx.commit();
+
+                            break;
+                        }
+                        catch (Exception e) {
+                            assertTrue(e instanceof TransactionSerializationException);
+                        }
                     }
                 }
                 catch (Exception e) {
diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/mvcc/MvccDeadlockDetectionTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/mvcc/MvccDeadlockDetectionTest.java
index 409e501..ee9470d 100644
--- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/mvcc/MvccDeadlockDetectionTest.java
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/mvcc/MvccDeadlockDetectionTest.java
@@ -43,6 +43,7 @@
 import org.apache.ignite.testframework.GridTestUtils.SF;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
 import org.apache.ignite.transactions.Transaction;
+import org.apache.ignite.transactions.TransactionRollbackException;
 import org.junit.After;
 import org.junit.Test;
 
@@ -608,8 +609,7 @@
                 fut.get(10, TimeUnit.SECONDS);
             }
             catch (IgniteCheckedException e) {
-                // TODO check expected exceptions once https://issues.apache.org/jira/browse/IGNITE-9470 is resolved
-                if (X.hasCause(e, IgniteTxRollbackCheckedException.class))
+                if (X.hasCause(e, TransactionRollbackException.class))
                     aborted++;
                 else
                     throw e;
diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/wal/IgniteWalRecoveryTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/wal/IgniteWalRecoveryTest.java
index 3904b6a..7db5664 100644
--- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/wal/IgniteWalRecoveryTest.java
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/wal/IgniteWalRecoveryTest.java
@@ -101,6 +101,7 @@
 import org.apache.ignite.lang.IgniteRunnable;
 import org.apache.ignite.resources.IgniteInstanceResource;
 import org.apache.ignite.testframework.GridTestUtils;
+import org.apache.ignite.testframework.junits.WithSystemProperty;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
 import org.apache.ignite.testframework.junits.multijvm.IgniteProcessProxy;
 import org.apache.ignite.transactions.Transaction;
@@ -109,6 +110,7 @@
 import org.junit.Assert;
 import org.junit.Test;
 
+import static org.apache.ignite.IgniteSystemProperties.IGNITE_WAL_LOG_TX_RECORDS;
 import static org.apache.ignite.configuration.DataStorageConfiguration.DFLT_CHECKPOINT_FREQ;
 import static org.apache.ignite.internal.IgniteNodeAttributes.ATTR_IGNITE_INSTANCE_NAME;
 import static org.apache.ignite.internal.processors.cache.persistence.file.FilePageStoreManager.CACHE_DATA_FILENAME;
@@ -1520,113 +1522,107 @@
      * @throws Exception If any fail.
      */
     @Test
+    @WithSystemProperty(key = IGNITE_WAL_LOG_TX_RECORDS, value = "true")
     public void testTxRecordsConsistency() throws Exception {
-        System.setProperty(IgniteSystemProperties.IGNITE_WAL_LOG_TX_RECORDS, "true");
-
         IgniteEx ignite = (IgniteEx)startGrids(3);
         ignite.cluster().active(true);
 
-        try {
-            final String cacheName = "transactional";
+        final String cacheName = "transactional";
 
-            CacheConfiguration<Object, Object> cacheConfiguration = new CacheConfiguration<>(cacheName)
-                .setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL)
-                .setAffinity(new RendezvousAffinityFunction(false, 32))
-                .setCacheMode(CacheMode.PARTITIONED)
-                .setRebalanceMode(CacheRebalanceMode.SYNC)
-                .setWriteSynchronizationMode(CacheWriteSynchronizationMode.FULL_SYNC)
-                .setBackups(0);
+        CacheConfiguration<Object, Object> cacheConfiguration = new CacheConfiguration<>(cacheName)
+            .setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL)
+            .setAffinity(new RendezvousAffinityFunction(false, 32))
+            .setCacheMode(CacheMode.PARTITIONED)
+            .setRebalanceMode(CacheRebalanceMode.SYNC)
+            .setWriteSynchronizationMode(CacheWriteSynchronizationMode.FULL_SYNC)
+            .setBackups(0);
 
-            ignite.createCache(cacheConfiguration);
+        ignite.createCache(cacheConfiguration);
 
-            IgniteCache<Object, Object> cache = ignite.cache(cacheName);
+        IgniteCache<Object, Object> cache = ignite.cache(cacheName);
 
-            GridCacheSharedContext<Object, Object> sharedCtx = ignite.context().cache().context();
+        GridCacheSharedContext<Object, Object> sharedCtx = ignite.context().cache().context();
 
-            GridCacheDatabaseSharedManager db = (GridCacheDatabaseSharedManager)sharedCtx.database();
+        GridCacheDatabaseSharedManager db = (GridCacheDatabaseSharedManager)sharedCtx.database();
 
-            db.waitForCheckpoint("test");
-            db.enableCheckpoints(false).get();
+        db.waitForCheckpoint("test");
+        db.enableCheckpoints(false).get();
 
-            // Log something to know where to start.
-            WALPointer startPtr = sharedCtx.wal().log(new MemoryRecoveryRecord(U.currentTimeMillis()));
+        // Log something to know where to start.
+        WALPointer startPtr = sharedCtx.wal().log(new MemoryRecoveryRecord(U.currentTimeMillis()));
 
-            final int transactions = 100;
-            final int operationsPerTransaction = 40;
+        final int transactions = 100;
+        final int operationsPerTransaction = 40;
 
-            Random random = new Random();
+        Random random = new Random();
 
-            for (int t = 1; t <= transactions; t++) {
-                Transaction tx = ignite.transactions().txStart(
-                    TransactionConcurrency.OPTIMISTIC, TransactionIsolation.READ_COMMITTED);
+        for (int t = 1; t <= transactions; t++) {
+            Transaction tx = ignite.transactions().txStart(
+                TransactionConcurrency.OPTIMISTIC, TransactionIsolation.READ_COMMITTED);
 
-                for (int op = 0; op < operationsPerTransaction; op++) {
-                    int key = random.nextInt(1000) + 1;
+            for (int op = 0; op < operationsPerTransaction; op++) {
+                int key = random.nextInt(1000) + 1;
 
-                    Object value = random.nextBoolean() ? randomString(random) + key : new BigObject(key);
+                Object value = random.nextBoolean() ? randomString(random) + key : new BigObject(key);
 
-                    cache.put(key, value);
-                }
-
-                if (random.nextBoolean()) {
-                    tx.commit();
-                }
-                else {
-                    tx.rollback();
-                }
-
-                if (t % 50 == 0)
-                    log.info("Finished transaction " + t);
+                cache.put(key, value);
             }
 
-            Set<GridCacheVersion> activeTransactions = new HashSet<>();
-
-            // Check that all DataRecords are within PREPARED and COMMITTED tx records.
-            try (WALIterator it = sharedCtx.wal().replay(startPtr)) {
-                while (it.hasNext()) {
-                    IgniteBiTuple<WALPointer, WALRecord> tup = it.next();
-
-                    WALRecord rec = tup.get2();
-
-                    if (rec instanceof TxRecord) {
-                        TxRecord txRecord = (TxRecord)rec;
-                        GridCacheVersion txId = txRecord.nearXidVersion();
-
-                        switch (txRecord.state()) {
-                            case PREPARED:
-                                assert !activeTransactions.contains(txId) : "Transaction is already present " + txRecord;
-
-                                activeTransactions.add(txId);
-
-                                break;
-                            case COMMITTED:
-                                assert activeTransactions.contains(txId) : "No PREPARE marker for transaction " + txRecord;
-
-                                activeTransactions.remove(txId);
-
-                                break;
-                            case ROLLED_BACK:
-                                activeTransactions.remove(txId);
-                                break;
-
-                            default:
-                                throw new IllegalStateException("Unknown Tx state of record " + txRecord);
-                        }
-                    }
-                    else if (rec instanceof DataRecord) {
-                        DataRecord dataRecord = (DataRecord)rec;
-
-                        for (DataEntry entry : dataRecord.writeEntries()) {
-                            GridCacheVersion txId = entry.nearXidVersion();
-
-                            assert activeTransactions.contains(txId) : "No transaction for entry " + entry;
-                        }
-                    }
-                }
+            if (random.nextBoolean()) {
+                tx.commit();
             }
+            else {
+                tx.rollback();
+            }
+
+            if (t % 50 == 0)
+                log.info("Finished transaction " + t);
         }
-        finally {
-            System.clearProperty(IgniteSystemProperties.IGNITE_WAL_LOG_TX_RECORDS);
+
+        Set<GridCacheVersion> activeTransactions = new HashSet<>();
+
+        // Check that all DataRecords are within PREPARED and COMMITTED tx records.
+        try (WALIterator it = sharedCtx.wal().replay(startPtr)) {
+            while (it.hasNext()) {
+                IgniteBiTuple<WALPointer, WALRecord> tup = it.next();
+
+                WALRecord rec = tup.get2();
+
+                if (rec instanceof TxRecord) {
+                    TxRecord txRecord = (TxRecord)rec;
+                    GridCacheVersion txId = txRecord.nearXidVersion();
+
+                    switch (txRecord.state()) {
+                        case PREPARED:
+                            assert !activeTransactions.contains(txId) : "Transaction is already present " + txRecord;
+
+                            activeTransactions.add(txId);
+
+                            break;
+                        case COMMITTED:
+                            assert activeTransactions.contains(txId) : "No PREPARE marker for transaction " + txRecord;
+
+                            activeTransactions.remove(txId);
+
+                            break;
+                        case ROLLED_BACK:
+                            activeTransactions.remove(txId);
+                            break;
+
+                        default:
+                            throw new IllegalStateException("Unknown Tx state of record " + txRecord);
+                    }
+                }
+                else if (rec instanceof DataRecord) {
+                    DataRecord dataRecord = (DataRecord)rec;
+
+                    for (DataEntry entry : dataRecord.writeEntries()) {
+                        GridCacheVersion txId = entry.nearXidVersion();
+
+                        assert activeTransactions.contains(txId) : "No transaction for entry " + entry;
+                    }
+                }
+            }
         }
     }
 
diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/transaction/DmlInsideTransactionTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/transaction/DmlInsideTransactionTest.java
index 60b57a5..d49bdb9 100644
--- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/transaction/DmlInsideTransactionTest.java
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/transaction/DmlInsideTransactionTest.java
@@ -19,7 +19,6 @@
 
 import javax.cache.CacheException;
 import org.apache.ignite.IgniteCache;
-import org.apache.ignite.IgniteSystemProperties;
 import org.apache.ignite.cache.CacheAtomicityMode;
 import org.apache.ignite.cache.query.Query;
 import org.apache.ignite.cache.query.SqlFieldsQuery;
@@ -27,11 +26,12 @@
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.internal.IgniteEx;
 import org.apache.ignite.internal.util.typedef.F;
-import org.apache.ignite.testframework.GridTestUtils.SystemProperty;
+import org.apache.ignite.testframework.junits.WithSystemProperty;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
 import org.apache.ignite.transactions.Transaction;
 import org.junit.Test;
 
+import static org.apache.ignite.IgniteSystemProperties.IGNITE_ALLOW_DML_INSIDE_TRANSACTION;
 import static org.apache.ignite.testframework.GridTestUtils.assertThrows;
 
 /**
@@ -79,15 +79,14 @@
      * @throws Exception In case failure.
      */
     @Test
+    @WithSystemProperty(key = IGNITE_ALLOW_DML_INSIDE_TRANSACTION, value = "false")
     public void testDmlInTransactionInDisabledCompatibilityMode() throws Exception {
-        try (SystemProperty ignored = new SystemProperty(IgniteSystemProperties.IGNITE_ALLOW_DML_INSIDE_TRANSACTION, "false")) {
-            prepareIgnite();
+        prepareIgnite();
 
-            for (String dmlQuery : DML_QUERIES) {
-                runDmlSqlFieldsQueryInTransactionTest(dmlQuery, false, false);
+        for (String dmlQuery : DML_QUERIES) {
+            runDmlSqlFieldsQueryInTransactionTest(dmlQuery, false, false);
 
-                runDmlSqlFieldsQueryInTransactionTest(dmlQuery, true, false);
-            }
+            runDmlSqlFieldsQueryInTransactionTest(dmlQuery, true, false);
         }
     }
 
@@ -97,15 +96,14 @@
      * @throws Exception In case failure.
      */
     @Test
+    @WithSystemProperty(key = IGNITE_ALLOW_DML_INSIDE_TRANSACTION, value = "true")
     public void testDmlInTransactionInCompatibilityMode() throws Exception {
-        try (SystemProperty ignored = new SystemProperty(IgniteSystemProperties.IGNITE_ALLOW_DML_INSIDE_TRANSACTION, "true")) {
-            prepareIgnite();
+        prepareIgnite();
 
-            for (String dmlQuery : DML_QUERIES) {
-                runDmlSqlFieldsQueryInTransactionTest(dmlQuery, false, true);
+        for (String dmlQuery : DML_QUERIES) {
+            runDmlSqlFieldsQueryInTransactionTest(dmlQuery, false, true);
 
-                runDmlSqlFieldsQueryInTransactionTest(dmlQuery, true, true);
-            }
+            runDmlSqlFieldsQueryInTransactionTest(dmlQuery, true, true);
         }
     }
 
diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/database/IgnitePersistentStoreQueryWithMultipleClassesPerCacheTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/database/IgnitePersistentStoreQueryWithMultipleClassesPerCacheTest.java
index 0cdc629..0874a4e 100644
--- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/database/IgnitePersistentStoreQueryWithMultipleClassesPerCacheTest.java
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/database/IgnitePersistentStoreQueryWithMultipleClassesPerCacheTest.java
@@ -25,9 +25,10 @@
 import org.apache.ignite.cache.query.SqlFieldsQuery;
 import org.apache.ignite.cache.query.annotations.QuerySqlField;
 import org.apache.ignite.configuration.CacheConfiguration;
-import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.configuration.DataStorageConfiguration;
+import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.internal.IgniteEx;
+import org.apache.ignite.testframework.junits.WithSystemProperty;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
 import org.junit.Test;
 
@@ -36,6 +37,7 @@
 /**
  *
  */
+@WithSystemProperty(key = IGNITE_SKIP_CONFIGURATION_CONSISTENCY_CHECK, value = "true")
 public class IgnitePersistentStoreQueryWithMultipleClassesPerCacheTest extends GridCommonAbstractTest {
     /** Cache name. */
     private static final String CACHE_NAME = "test_cache";
@@ -78,8 +80,6 @@
 
     /** {@inheritDoc} */
     @Override protected void beforeTest() throws Exception {
-        System.setProperty(IGNITE_SKIP_CONFIGURATION_CONSISTENCY_CHECK, "true");
-
         stopAllGrids();
 
         cleanPersistenceDir();
@@ -90,8 +90,6 @@
         stopAllGrids();
 
         cleanPersistenceDir();
-
-        System.clearProperty(IGNITE_SKIP_CONFIGURATION_CONSISTENCY_CHECK);
     }
 
     /**
diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/database/IgnitePersistentStoreSchemaLoadTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/database/IgnitePersistentStoreSchemaLoadTest.java
index 64ceae7..2a62f15 100644
--- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/database/IgnitePersistentStoreSchemaLoadTest.java
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/database/IgnitePersistentStoreSchemaLoadTest.java
@@ -36,6 +36,7 @@
 import org.apache.ignite.internal.processors.cache.persistence.GridCacheDatabaseSharedManager;
 import org.apache.ignite.internal.processors.query.QuerySchema;
 import org.apache.ignite.internal.processors.query.QueryUtils;
+import org.apache.ignite.testframework.junits.WithSystemProperty;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
 import org.junit.Test;
 
@@ -44,6 +45,7 @@
 /**
  *
  */
+@WithSystemProperty(key = IGNITE_SKIP_CONFIGURATION_CONSISTENCY_CHECK, value = "true")
 public class IgnitePersistentStoreSchemaLoadTest extends GridCommonAbstractTest {
     /** Cache name. */
     private static final String TMPL_NAME = "test_cache*";
@@ -111,8 +113,6 @@
 
     /** {@inheritDoc} */
     @Override protected void beforeTest() throws Exception {
-        System.setProperty(IGNITE_SKIP_CONFIGURATION_CONSISTENCY_CHECK, "true");
-
         stopAllGrids();
 
         cleanPersistenceDir();
@@ -123,8 +123,6 @@
         stopAllGrids();
 
         cleanPersistenceDir();
-
-        System.clearProperty(IGNITE_SKIP_CONFIGURATION_CONSISTENCY_CHECK);
     }
 
     /** */
diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/IgniteSqlKeyValueFieldsTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/IgniteSqlKeyValueFieldsTest.java
index 99dea6d..0d0093f 100644
--- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/IgniteSqlKeyValueFieldsTest.java
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/IgniteSqlKeyValueFieldsTest.java
@@ -33,6 +33,7 @@
 import org.apache.ignite.internal.binary.BinaryMarshaller;
 import org.apache.ignite.internal.processors.cache.index.AbstractIndexingCommonTest;
 import org.apache.ignite.internal.processors.cache.version.GridCacheVersion;
+import org.apache.ignite.internal.processors.query.h2.dml.UpdatePlanBuilder;
 import org.apache.ignite.internal.util.typedef.F;
 import org.apache.ignite.testframework.GridTestUtils;
 import org.junit.Test;
@@ -62,6 +63,8 @@
     /** */
     private static String CACHE_JOB = "Job";
 
+    /** */
+    private boolean oldAllowKeyValCol;
 
     /** {@inheritDoc} */
     @Override protected IgniteConfiguration getConfiguration(String gridName) throws Exception {
@@ -90,15 +93,22 @@
     @Override protected void beforeTest() throws Exception {
         super.beforeTest();
 
+        oldAllowKeyValCol = GridTestUtils.getFieldValue(UpdatePlanBuilder.class,
+            UpdatePlanBuilder.class, "ALLOW_KEY_VAL_UPDATES");
+
+        GridTestUtils.setFieldValue(UpdatePlanBuilder.class, "ALLOW_KEY_VAL_UPDATES", true);
+
         startGrid(0);
         startGrid(NODE_CLIENT);
     }
 
     /** {@inheritDoc} */
     @Override protected void afterTest() throws Exception {
-        super.afterTest();
-
         stopAllGrids();
+
+        GridTestUtils.setFieldValue(UpdatePlanBuilder.class, "ALLOW_KEY_VAL_UPDATES", oldAllowKeyValCol);
+
+        super.afterTest();
     }
 
     private CacheConfiguration buildCacheConfiguration(String name) {
diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/LocalQueryLazyTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/LocalQueryLazyTest.java
new file mode 100644
index 0000000..1818d9e
--- /dev/null
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/LocalQueryLazyTest.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;
+
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import org.apache.ignite.IgniteCache;
+import org.apache.ignite.cache.QueryEntity;
+import org.apache.ignite.cache.affinity.rendezvous.RendezvousAffinityFunction;
+import org.apache.ignite.cache.query.FieldsQueryCursor;
+import org.apache.ignite.cache.query.SqlFieldsQuery;
+import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.internal.processors.cache.index.AbstractIndexingCommonTest;
+import org.apache.ignite.testframework.GridTestUtils;
+import org.h2.result.LazyResult;
+import org.h2.result.ResultInterface;
+import org.junit.Test;
+
+/**
+ * Tests for local query execution in lazy mode.
+ */
+public class LocalQueryLazyTest extends AbstractIndexingCommonTest {
+    /** Keys count. */
+    private static final int KEY_CNT = 10;
+
+    /** Queries count. */
+    private static final int QRY_CNT = 10;
+
+    /** {@inheritDoc} */
+    @Override protected void beforeTest() throws Exception {
+        super.beforeTest();
+
+        startGrid();
+
+        IgniteCache<Long, Long> c = grid().createCache(new CacheConfiguration<Long, Long>()
+            .setName("test")
+            .setSqlSchema("TEST")
+            .setQueryEntities(Collections.singleton(new QueryEntity(Long.class, Long.class)
+                .setTableName("test")
+                .addQueryField("id", Long.class.getName(), null)
+                .addQueryField("val", Long.class.getName(), null)
+                .setKeyFieldName("id")
+                .setValueFieldName("val")
+            ))
+            .setAffinity(new RendezvousAffinityFunction(false, 10)));
+
+        for (long i = 0; i < KEY_CNT; ++i)
+            c.put(i, i);
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void afterTest() throws Exception {
+        stopAllGrids();
+
+        super.afterTest();
+    }
+
+    /**
+     * Test local query execution.
+     */
+    @Test
+    public void testLocalLazyQuery() {
+        Iterator[] iters = new Iterator[QRY_CNT];
+
+        for (int i = 0; i < QRY_CNT; ++i) {
+            iters[i] = sql("SELECT * FROM test").iterator();
+
+            ResultInterface res = GridTestUtils.getFieldValueHierarchy(iters[i], "iter", "iter", "res");
+
+            assertTrue("Unexpected result type " + res.getClass(), res instanceof LazyResult);
+        }
+
+        // Scan and close iterator in reverse order.
+        for (int i = QRY_CNT - 1; i >= 0; --i) {
+            while (iters[i].hasNext())
+                iters[i].next();
+        }
+    }
+
+    /**
+     * @param sql SQL query.
+     * @param args Query parameters.
+     * @return Results cursor.
+     */
+    private FieldsQueryCursor<List<?>> sql(String sql, Object ... args) {
+        return grid().context().query().querySqlFields(new SqlFieldsQuery(sql)
+            .setLocal(true)
+            .setLazy(true)
+            .setSchema("TEST")
+            .setArgs(args), false);
+    }
+}
diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/RunningQueriesTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/RunningQueriesTest.java
index e7f3b8c..ff8fd11 100644
--- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/RunningQueriesTest.java
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/RunningQueriesTest.java
@@ -53,7 +53,6 @@
 import org.apache.ignite.internal.processors.cache.distributed.dht.atomic.GridNearAtomicFullUpdateRequest;
 import org.apache.ignite.internal.processors.cache.distributed.dht.atomic.GridNearAtomicSingleUpdateFilterRequest;
 import org.apache.ignite.internal.processors.cache.index.AbstractIndexingCommonTest;
-import org.apache.ignite.internal.processors.cache.mvcc.MvccQueryTracker;
 import org.apache.ignite.internal.processors.query.h2.IgniteH2Indexing;
 import org.apache.ignite.internal.processors.query.schema.message.SchemaProposeDiscoveryMessage;
 import org.apache.ignite.internal.util.typedef.G;
@@ -65,7 +64,11 @@
 import org.apache.ignite.testframework.GridTestUtils;
 import org.jetbrains.annotations.Nullable;
 import org.junit.Assert;
+import org.junit.Rule;
+import org.junit.Ignore;
 import org.junit.Test;
+import org.junit.rules.TestWatcher;
+import org.junit.runner.Description;
 
 import static org.apache.ignite.internal.util.IgniteUtils.resolveIgnitePath;
 
@@ -80,7 +83,7 @@
     private static final long TIMEOUT_IN_MS = TIMEOUT_IN_SEC * 1000;
 
     /** Barrier. */
-    private static CyclicBarrier barrier;
+    private static volatile CyclicBarrier barrier;
 
     /** Ignite. */
     private static IgniteEx ignite;
@@ -88,6 +91,32 @@
     /** Node count. */
     private static final int NODE_CNT = 2;
 
+    /** Restarts the grid if if the last test failed. */
+    @Rule public final TestWatcher restarter = new TestWatcher() {
+        /** {@inheritDoc} */
+        @Override protected void failed(Throwable e, Description lastTest) {
+            try {
+                log().error("Last test failed [name=" + lastTest.getMethodName() +
+                    ", reason=" + e.getMessage() + "]. Restarting the grid.");
+
+                // Release the indexing.
+                if (barrier != null)
+                    barrier.reset();
+
+                stopAllGrids();
+
+                beforeTestsStarted();
+
+                log().error("Grid restarted.");
+            }
+            catch (Exception restartFailure) {
+                throw new RuntimeException("Failed to recover after test failure [test=" + lastTest.getMethodName() +
+                    ", reason=" + e.getMessage() + "]. Subsequent test results of this test class are incorrect.",
+                    restartFailure);
+            }
+        }
+    };
+
     /** {@inheritDoc} */
     @Override protected void beforeTestsStarted() throws Exception {
         super.beforeTestsStarted();
@@ -148,7 +177,7 @@
                             .findAny()
                             .ifPresent((c) -> {
                                 try {
-                                    awaitTimeouted();
+                                    awaitTimeout();
                                 }
                                 catch (Exception e) {
                                     e.printStackTrace();
@@ -157,7 +186,7 @@
                     }
                     else if (SchemaProposeDiscoveryMessage.class.isAssignableFrom(delegate.getClass())) {
                         try {
-                            awaitTimeouted();
+                            awaitTimeout();
                         }
                         catch (Exception e) {
                             e.printStackTrace();
@@ -179,7 +208,7 @@
                         || GridNearAtomicFullUpdateRequest.class.isAssignableFrom(gridMsg.getClass())
                     ) {
                         try {
-                            awaitTimeouted();
+                            awaitTimeout();
                         }
                         catch (Exception ignore) {
                         }
@@ -222,10 +251,9 @@
     }
 
     /**
-     * Check auto clenup running queries on fully readed iterator.
-     *
-     * @throws Exception Exception in case of failure.
+     * Check auto cleanup running queries on fully read iterator.
      */
+    @SuppressWarnings("CodeBlock2Expr")
     @Test
     public void testAutoCloseQueryAfterIteratorIsExhausted(){
         IgniteCache<Object, Object> cache = ignite.cache(DEFAULT_CACHE_NAME);
@@ -246,11 +274,9 @@
 
     /**
      * Check cluster wide query id generation.
-     *
-     * @throws Exception Exception in case of failure.
      */
     @Test
-    public void testClusterWideQueryIdGeneration() throws Exception {
+    public void testClusterWideQueryIdGeneration() {
         newBarrier(1);
 
         IgniteCache<Object, Object> cache = ignite.cache(DEFAULT_CACHE_NAME);
@@ -300,7 +326,7 @@
 
         assertNoRunningQueries(ignite);
 
-        awaitTimeouted();
+        awaitTimeout();
 
         fut1.get(TIMEOUT_IN_MS);
 
@@ -312,6 +338,7 @@
      *
      * @throws Exception Exception in case of failure.
      */
+    @Ignore("https://issues.apache.org/jira/browse/IGNITE-11510")
     @Test
     public void testQueryDmlDelete() throws Exception {
         testQueryDML("DELETE FROM /* comment */ Integer");
@@ -322,6 +349,7 @@
      *
      * @throws Exception Exception in case of failure.
      */
+    @Ignore("https://issues.apache.org/jira/browse/IGNITE-11510")
     @Test
     public void testQueryDmlInsert() throws Exception {
         testQueryDML("INSERT INTO Integer(_key, _val) VALUES(1,1)");
@@ -332,6 +360,7 @@
      *
      * @throws Exception Exception in case of failure.
      */
+    @Ignore("https://issues.apache.org/jira/browse/IGNITE-11510")
     @Test
     public void testQueryDmlUpdate() throws Exception {
         testQueryDML("UPDATE Integer set _val = 1 where 1=1");
@@ -364,7 +393,7 @@
 
         IgniteInternalFuture<Integer> fut1 = GridTestUtils.runAsync(() -> barrier.await());
 
-        awaitTimeouted();
+        awaitTimeout();
 
         fut1.get(TIMEOUT_IN_MS);
 
@@ -382,9 +411,9 @@
 
         ignite.cache(DEFAULT_CACHE_NAME).query(new SqlFieldsQuery("CREATE TABLE tst_idx_drop(id long PRIMARY KEY, cnt integer)"));
 
-        ignite.cache(DEFAULT_CACHE_NAME).query(new SqlFieldsQuery("CREATE INDEX tst_idx_drop_idx ON default.tst_idx_drop(cnt)"));
+        ignite.cache(DEFAULT_CACHE_NAME).query(new SqlFieldsQuery("CREATE INDEX tst_idx_drop_idx ON tst_idx_drop(cnt)"));
 
-        testQueryDDL("DROP INDEX default.tst_idx_drop_idx");
+        testQueryDDL("DROP INDEX tst_idx_drop_idx");
     }
 
     /**
@@ -398,7 +427,7 @@
 
         ignite.cache(DEFAULT_CACHE_NAME).query(new SqlFieldsQuery("CREATE TABLE tst_idx_create(id long PRIMARY KEY, cnt integer)"));
 
-        testQueryDDL("CREATE INDEX tst_idx_create_idx ON default.tst_idx_create(cnt)");
+        testQueryDDL("CREATE INDEX tst_idx_create_idx ON tst_idx_create(cnt)");
     }
 
     /**
@@ -412,7 +441,7 @@
 
         ignite.cache(DEFAULT_CACHE_NAME).query(new SqlFieldsQuery("CREATE TABLE tst_drop(id long PRIMARY KEY, cnt integer)"));
 
-        testQueryDDL("DROP TABLE default.tst_drop");
+        testQueryDDL("DROP TABLE tst_drop");
     }
 
     /**
@@ -449,9 +478,9 @@
 
         runningQueries.forEach((info) -> Assert.assertEquals(qry.getSql(), info.query()));
 
-        awaitTimeouted();
+        awaitTimeout();
 
-        awaitTimeouted();
+        awaitTimeout();
 
         fut.get(TIMEOUT_IN_MS);
     }
@@ -490,11 +519,11 @@
 
                 assertEquals(1, runningQueries.size());
 
-                awaitTimeouted();
+                awaitTimeout();
 
                 assertWaitingOnBarrier();
 
-                awaitTimeouted();
+                awaitTimeout();
             }
 
             fut.get(TIMEOUT_IN_MS);
@@ -502,7 +531,7 @@
     }
 
     /**
-     * Check tracking running queries for multistatements.
+     * Check tracking running queries for multi-statements.
      *
      * @throws Exception Exception in case of failure.
      */
@@ -545,7 +574,7 @@
 
                 assertEquals(query, runningQueries.get(0).query());
 
-                awaitTimeouted();
+                awaitTimeout();
             }
 
             fut.get(TIMEOUT_IN_MS);
@@ -586,7 +615,7 @@
 
             assertEquals(sql, runningQueries.get(0).query());
 
-            awaitTimeouted();
+            awaitTimeout();
 
             fut.get(TIMEOUT_IN_MS);
         }
@@ -605,7 +634,7 @@
     /**
      * Check all nodes except passed as parameter on no any running queries.
      *
-     * @param excludeNodes Nodes shich will be excluded from check.
+     * @param excludeNodes Nodes which will be excluded from check.
      */
     private void assertNoRunningQueries(IgniteEx... excludeNodes) {
         Set<UUID> excludeIds = Stream.of(excludeNodes).map((ignite) -> ignite.localNode().id()).collect(Collectors.toSet());
@@ -635,7 +664,7 @@
      * @throws TimeoutException In case of failure.
      * @throws BrokenBarrierException In case of failure.
      */
-    private static void awaitTimeouted() throws InterruptedException, TimeoutException, BrokenBarrierException {
+    private static void awaitTimeout() throws InterruptedException, TimeoutException, BrokenBarrierException {
         barrier.await(TIMEOUT_IN_MS, TimeUnit.SECONDS);
     }
 
@@ -644,13 +673,25 @@
      */
     private static class BlockingIndexing extends IgniteH2Indexing {
         /** {@inheritDoc} */
-        @Override public List<FieldsQueryCursor<List<?>>> querySqlFields(String schemaName, SqlFieldsQuery qry,
-            @Nullable SqlClientContext cliCtx, boolean keepBinary, boolean failOnMultipleStmts,
-            MvccQueryTracker tracker, GridQueryCancel cancel, boolean registerAsNewQry) {
-            List<FieldsQueryCursor<List<?>>> res = super.querySqlFields(schemaName, qry, cliCtx, keepBinary,
-                failOnMultipleStmts, tracker, cancel, registerAsNewQry);
+        @Override public List<FieldsQueryCursor<List<?>>> querySqlFields(
+            String schemaName,
+            SqlFieldsQuery qry,
+            @Nullable SqlClientContext cliCtx,
+            boolean keepBinary,
+            boolean failOnMultipleStmts,
+            GridQueryCancel cancel
+        ) {
+            List<FieldsQueryCursor<List<?>>> res = super.querySqlFields(
+                schemaName,
+                qry,
+                cliCtx,
+                keepBinary,
+                failOnMultipleStmts,
+                cancel
+            );
+
             try {
-                awaitTimeouted();
+                awaitTimeout();
             }
             catch (Exception e) {
                 throw new IgniteException(e);
diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/SqlIncompatibleDataTypeExceptionTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/SqlIncompatibleDataTypeExceptionTest.java
new file mode 100644
index 0000000..7401b19
--- /dev/null
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/SqlIncompatibleDataTypeExceptionTest.java
@@ -0,0 +1,199 @@
+/*
+ * 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;
+
+import java.util.List;
+import org.apache.ignite.Ignite;
+import org.apache.ignite.binary.BinaryObjectBuilder;
+import org.apache.ignite.cache.query.SqlFieldsQuery;
+import org.apache.ignite.internal.IgniteEx;
+import org.apache.ignite.internal.processors.cache.index.AbstractIndexingCommonTest;
+import org.apache.ignite.internal.processors.query.h2.dml.UpdatePlanBuilder;
+import org.apache.ignite.testframework.GridTestUtils;
+import org.junit.Test;
+
+/**
+ * Tests for use _key, _val columns at the INSERT/MERGE/UPDATE statements.
+ */
+public class SqlIncompatibleDataTypeExceptionTest extends AbstractIndexingCommonTest {
+    /** Old allow value. */
+    private boolean oldAllowColumnsVal;
+
+    /** {@inheritDoc} */
+    @Override protected void beforeTestsStarted() throws Exception {
+        startGrid();
+
+        super.beforeTestsStarted();
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void afterTestsStopped() throws Exception {
+        stopAllGrids();
+
+        super.afterTestsStopped();
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void beforeTest() throws Exception {
+        super.beforeTest();
+
+        oldAllowColumnsVal = GridTestUtils.getFieldValue(UpdatePlanBuilder.class, UpdatePlanBuilder.class,
+            "ALLOW_KEY_VAL_UPDATES");
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void afterTest() throws Exception {
+        grid().destroyCaches(grid().cacheNames());
+
+        GridTestUtils.setFieldValue(UpdatePlanBuilder.class, "ALLOW_KEY_VAL_UPDATES", oldAllowColumnsVal);
+
+        super.afterTest();
+    }
+
+    /**
+     * Test use _key field at INSERT statement.
+     */
+    @Test
+    public void testUseKeyField() {
+        // Unwrapped simple key.
+        execSql("CREATE TABLE test_0 (id integer primary key, val varchar)");
+        execSql("INSERT INTO test_0 (_key, val) VALUES (?, ?)", 0, "0");
+        execSql("MERGE INTO test_0 (_key, val) VALUES (?, ?)", 1, "1");
+
+        // Composite key.
+        execSql("CREATE TABLE test (id0 integer, id1 integer, val varchar, primary key (id0, id1))");
+
+        final BinaryObjectBuilder bob = grid().binary().builder("key");
+        bob.setField("id0", 0);
+        bob.setField("id1", 1);
+
+        GridTestUtils.assertThrows(log, ()-> {
+            execSql("INSERT INTO test (_key, val) VALUES (?, ?)", bob.build(), "asd");
+
+            return null;
+        }, IgniteSQLException.class, "Update of composite key column is not supported");
+
+        GridTestUtils.assertThrows(log, ()-> {
+            execSql("MERGE INTO test (_key, val) VALUES (?, ?)", bob.build(), "asd");
+
+            return null;
+        }, IgniteSQLException.class, "Update of composite key column is not supported");
+    }
+
+    /**
+     * Test use _val field at INSERT statement.
+     */
+    @Test
+    public void testUseValField() {
+        // Unwrapped simple value.
+        execSql("CREATE TABLE test_0 (id integer primary key, val varchar) WITH \"WRAP_VALUE=0\"");
+        execSql("INSERT INTO test_0 (id, _val) VALUES (?, ?)", 0, "0");
+        execSql("MERGE INTO test_0 (id, _val) VALUES (?, ?)", 1, "1");
+        execSql("UPDATE test_0 SET _val = ?", "upd");
+
+        // Composite value.
+        execSql("CREATE TABLE test (id integer primary key, val varchar)");
+
+        final BinaryObjectBuilder bob = grid().binary().builder("val");
+        bob.setField("val", "0");
+
+        GridTestUtils.assertThrows(log, ()-> {
+            execSql("INSERT INTO test (id, _val) VALUES (?, ?)", 0, bob.build());
+
+            return null;
+        }, IgniteSQLException.class, "Update of composite value column is not supported");
+
+        GridTestUtils.assertThrows(log, ()-> {
+            execSql("MERGE INTO test (id, _val) VALUES (?, ?)", 0, bob.build());
+
+            return null;
+        }, IgniteSQLException.class, "Update of composite value column is not supported");
+
+        GridTestUtils.assertThrows(log, ()-> {
+            execSql("UPDATE test SET _val=?", bob.build());
+
+            return null;
+        }, IgniteSQLException.class, "Update of composite value column is not supported");
+    }
+
+    /**
+     *
+     */
+    @Test
+    public void testUseKeyField_Allow() {
+        GridTestUtils.setFieldValue(UpdatePlanBuilder.class, "ALLOW_KEY_VAL_UPDATES", true);
+
+        execSql("CREATE TABLE test (id0 integer, id1 integer, val varchar, primary key (id0, id1))");
+
+        final BinaryObjectBuilder bob = grid().binary().builder("val");
+        bob.setField("id0", 0);
+        bob.setField("id1", 0);
+
+        // Invalid usage, but allowed for backward compatibility
+        // when ALLOW_KEY_VAL_COLUMNS set to true
+        execSql("INSERT INTO test (_key, val) VALUES (?, ?)", bob.build(), 0);
+
+        bob.setField("id0", 1);
+        bob.setField("id1", 1);
+        execSql("MERGE INTO test (_key, val) VALUES (?, ?)", bob.build(), 1);
+    }
+
+    /**
+     *
+     */
+    @Test
+    public void testUseValField_Allow() {
+        GridTestUtils.setFieldValue(UpdatePlanBuilder.class, "ALLOW_KEY_VAL_UPDATES", true);
+
+        execSql("CREATE TABLE test (id integer primary key, val varchar)");
+
+        final BinaryObjectBuilder bob = grid().binary().builder("val");
+        bob.setField("val", "0");
+
+        // Invalid usage, but allowed for backward compatibility
+        // when ALLOW_KEY_VAL_COLUMNS set to true
+        execSql("INSERT INTO test (id, _val) VALUES (?, ?)", 0, bob.build());
+        execSql("MERGE INTO test (id, _val) VALUES (?, ?)", 0, bob.build());
+        execSql("UPDATE test SET _val=?", bob.build());
+    }
+
+    /**
+     * @param ignite Ignite.
+     * @param sql Sql.
+     * @param args Args.
+     * @return Results.
+     */
+    @SuppressWarnings("unchecked")
+    private List<List<?>> execSql(Ignite ignite, String sql, Object... args) {
+        SqlFieldsQuery qry = new SqlFieldsQuery(sql);
+
+        if (args != null && args.length > 0)
+            qry.setArgs(args);
+
+        return ((IgniteEx)ignite).context().query().querySqlFields(qry, false).getAll();
+    }
+
+    /**
+     * @param sql Sql.
+     * @param args Args.
+     * @return Query results.
+     */
+    private List<List<?>> execSql(String sql, Object... args) {
+        return execSql(grid(), sql, args);
+    }
+}
diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/SqlQueryHistorySelfTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/SqlQueryHistorySelfTest.java
index 3695710..5c10d68 100644
--- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/SqlQueryHistorySelfTest.java
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/SqlQueryHistorySelfTest.java
@@ -555,7 +555,7 @@
             // No-op.
         }
 
-        checkMetrics(1, 0, 2, 2, true);
+        checkMetrics(1, 0, 2, 2, false);
     }
 
     /**
diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/SqlSystemViewsSelfTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/SqlSystemViewsSelfTest.java
index fb6d335..f21d43f 100644
--- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/SqlSystemViewsSelfTest.java
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/SqlSystemViewsSelfTest.java
@@ -19,19 +19,19 @@
 
 import java.lang.reflect.Field;
 import java.sql.Timestamp;
-import java.time.LocalDateTime;
+import java.time.Instant;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 import java.util.Random;
-import java.util.TimeZone;
 import java.util.UUID;
 import java.util.concurrent.Callable;
 import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
 import java.util.stream.LongStream;
 import javax.cache.Cache;
+import javax.cache.CacheException;
 import javax.cache.configuration.Factory;
 import org.apache.ignite.Ignite;
 import org.apache.ignite.IgniteCache;
@@ -47,6 +47,7 @@
 import org.apache.ignite.cache.query.QueryCursor;
 import org.apache.ignite.cache.query.SqlFieldsQuery;
 import org.apache.ignite.cache.query.SqlQuery;
+import org.apache.ignite.cache.query.annotations.QuerySqlFunction;
 import org.apache.ignite.cluster.ClusterMetrics;
 import org.apache.ignite.cluster.ClusterNode;
 import org.apache.ignite.configuration.CacheConfiguration;
@@ -71,7 +72,6 @@
 import org.apache.ignite.lang.IgniteRunnable;
 import org.apache.ignite.spi.discovery.tcp.internal.TcpDiscoveryNode;
 import org.apache.ignite.testframework.GridTestUtils;
-import org.h2.api.TimestampWithTimeZone;
 import org.junit.Assert;
 import org.junit.Test;
 
@@ -187,7 +187,7 @@
 
         execSql("CREATE TABLE CACHE_SQL (ID INT PRIMARY KEY, MY_VAL VARCHAR)");
 
-        execSql("CREATE INDEX IDX_2 ON DEFAULT.CACHE_SQL(ID DESC) INLINE_SIZE 13");
+        execSql("CREATE INDEX IDX_2 ON \"default\".CACHE_SQL(ID DESC) INLINE_SIZE 13");
 
         execSql("CREATE TABLE PUBLIC.DFLT_CACHE (ID1 INT, ID2 INT, MY_VAL VARCHAR, PRIMARY KEY (ID1 DESC, ID2))");
 
@@ -215,10 +215,10 @@
             {"PUBLIC", "AFF_CACHE", "_key_PK", "\"ID1\" ASC, \"ID2\" ASC", "BTREE", "true", "true", "-825022849", "SQL_PUBLIC_AFF_CACHE", "-825022849", "SQL_PUBLIC_AFF_CACHE", "10"},
             {"PUBLIC", "AFF_CACHE", "_key_PK_hash", "\"ID1\" ASC, \"ID2\" ASC, \"ID2\" ASC", "HASH", "false", "true", "-825022849", "SQL_PUBLIC_AFF_CACHE", "-825022849", "SQL_PUBLIC_AFF_CACHE", "null"},
 
-            {"DEFAULT", "CACHE_SQL", "IDX_2", "\"ID\" DESC, \"ID\" ASC", "BTREE", "false", "false", "683914882", "SQL_default_CACHE_SQL", "683914882", "SQL_default_CACHE_SQL", "13"},
-            {"DEFAULT", "CACHE_SQL", "__SCAN_", "null", "SCAN", "false", "false",  "683914882", "SQL_default_CACHE_SQL", "683914882", "SQL_default_CACHE_SQL", "null"},
-            {"DEFAULT", "CACHE_SQL", "_key_PK", "\"ID\" ASC", "BTREE", "true", "true", "683914882", "SQL_default_CACHE_SQL", "683914882", "SQL_default_CACHE_SQL", "5"},
-            {"DEFAULT", "CACHE_SQL", "_key_PK_hash", "\"ID\" ASC", "HASH", "false", "true", "683914882", "SQL_default_CACHE_SQL", "683914882", "SQL_default_CACHE_SQL", "null"},
+            {"default", "CACHE_SQL", "IDX_2", "\"ID\" DESC, \"ID\" ASC", "BTREE", "false", "false", "683914882", "SQL_default_CACHE_SQL", "683914882", "SQL_default_CACHE_SQL", "13"},
+            {"default", "CACHE_SQL", "__SCAN_", "null", "SCAN", "false", "false",  "683914882", "SQL_default_CACHE_SQL", "683914882", "SQL_default_CACHE_SQL", "null"},
+            {"default", "CACHE_SQL", "_key_PK", "\"ID\" ASC", "BTREE", "true", "true", "683914882", "SQL_default_CACHE_SQL", "683914882", "SQL_default_CACHE_SQL", "5"},
+            {"default", "CACHE_SQL", "_key_PK_hash", "\"ID\" ASC", "HASH", "false", "true", "683914882", "SQL_default_CACHE_SQL", "683914882", "SQL_default_CACHE_SQL", "null"},
 
             {"PUBLIC", "DFLT_AFF_CACHE", "AFFINITY_KEY", "\"ID1\" ASC, \"ID2\" ASC", "BTREE", "false", "false", "1374144180", "SQL_PUBLIC_DFLT_AFF_CACHE", "1374144180", "SQL_PUBLIC_DFLT_AFF_CACHE", "10"},
             {"PUBLIC", "DFLT_AFF_CACHE", "IDX_AFF_1", "\"ID2\" DESC, \"ID1\" ASC, \"MY_VAL\" DESC", "BTREE", "false", "false", "1374144180", "SQL_PUBLIC_DFLT_AFF_CACHE", "1374144180", "SQL_PUBLIC_DFLT_AFF_CACHE", "10"},
@@ -308,6 +308,94 @@
         assertEquals(nodeId, ((List<?>)cache.query(qry).getAll().get(0)).get(0));
     }
 
+    /**
+     * Test Query history system view.
+     */
+    @Test
+    @SuppressWarnings("unchecked")
+    public void testQueryHistoryMetricsModes() throws Exception {
+        IgniteEx ignite = startGrid(0);
+
+        final String SCHEMA_NAME = "TEST_SCHEMA";
+        final long MAX_SLEEP = 500;
+
+        long tsBeforeRun = System.currentTimeMillis();
+
+        IgniteCache cache = ignite.createCache(
+            new CacheConfiguration<>(DEFAULT_CACHE_NAME)
+                .setIndexedTypes(Integer.class, String.class)
+                .setSqlSchema(SCHEMA_NAME)
+                .setSqlFunctionClasses(GridTestUtils.SqlTestFunctions.class)
+        );
+
+        cache.put(100, "200");
+
+        String sql = "SELECT \"STRING\"._KEY, \"STRING\"._VAL FROM \"STRING\" WHERE _key=100 AND sleep()>0 AND can_fail()=0";
+
+        GridTestUtils.SqlTestFunctions.sleepMs = 50;
+        GridTestUtils.SqlTestFunctions.fail = false;
+
+        cache.query(new SqlFieldsQuery(sql).setSchema(SCHEMA_NAME)).getAll();
+
+        GridTestUtils.SqlTestFunctions.sleepMs = MAX_SLEEP;
+        GridTestUtils.SqlTestFunctions.fail = false;
+
+        cache.query(new SqlFieldsQuery(sql).setSchema(SCHEMA_NAME)).getAll();
+
+        GridTestUtils.SqlTestFunctions.fail = true;
+
+        GridTestUtils.assertThrows(log,
+            () ->
+                cache.query(new SqlFieldsQuery(sql).setSchema(SCHEMA_NAME)).getAll()
+            , CacheException.class,
+            "Exception calling user-defined function");
+
+        String sqlHist = "SELECT SCHEMA_NAME, SQL, LOCAL, EXECUTIONS, FAILURES, DURATION_MIN, DURATION_MAX, LAST_START_TIME " +
+            "FROM IGNITE.LOCAL_SQL_QUERY_HISTORY ORDER BY LAST_START_TIME";
+
+        cache.query(new SqlFieldsQuery(sqlHist).setLocal(true)).getAll();
+        cache.query(new SqlFieldsQuery(sqlHist).setLocal(true)).getAll();
+
+        List<List<?>> res = cache.query(new SqlFieldsQuery(sqlHist).setLocal(true)).getAll();
+
+        assertEquals(2, res.size());
+
+        long tsAfterRun = System.currentTimeMillis();
+
+        List<?> firstRow = res.get(0);
+        List<?> secondRow = res.get(1);
+
+        //SCHEMA_NAME
+        assertEquals(SCHEMA_NAME, firstRow.get(0));
+        assertEquals(SCHEMA_NAME, secondRow.get(0));
+
+        //SQL
+        assertEquals(sql, firstRow.get(1));
+        assertEquals(sqlHist, secondRow.get(1));
+
+        // LOCAL flag
+        assertEquals(false, firstRow.get(2));
+        assertEquals(true, secondRow.get(2));
+
+        // EXECUTIONS
+        assertEquals(3L, firstRow.get(3));
+        assertEquals(2L, secondRow.get(3));
+
+        //FAILURES
+        assertEquals(1L, firstRow.get(4));
+        assertEquals(0L, secondRow.get(4));
+
+        //DURATION_MIN
+        assertTrue((Long)firstRow.get(5) > 0);
+        assertTrue((Long)firstRow.get(5) < (Long)firstRow.get(6));
+
+        //DURATION_MAX
+        assertTrue((Long)firstRow.get(6) > MAX_SLEEP);
+
+        //LAST_START_TIME
+        assertFalse(((Timestamp)firstRow.get(7)).before(new Timestamp(tsBeforeRun)));
+        assertFalse(((Timestamp)firstRow.get(7)).after(new Timestamp(tsAfterRun)));
+    }
 
     /**
      * Test running queries system view.
@@ -333,17 +421,13 @@
         List<?> res0 = (List<?>)cur.get(0);
         List<?> res1 = (List<?>)cur.get(1);
 
-        TimestampWithTimeZone tsTz = (TimestampWithTimeZone)res0.get(4);
+        Timestamp ts = (Timestamp)res0.get(4);
 
-        LocalDateTime now = LocalDateTime.now();
+        Instant now = Instant.now();
 
-        int sysTZOff = TimeZone.getDefault().getOffset(System.currentTimeMillis()) / 60 / 1000;
+        long diffInMillis = now.minusMillis(ts.getTime()).toEpochMilli();
 
-        assertEquals(sysTZOff, tsTz.getTimeZoneOffsetMins());
-
-        long diffInMinutes = Math.abs((tsTz.getNanosSinceMidnight() / 1_000_000_000 / 60) - (now.getHour() * 60 + now.getMinute()));
-
-        assertTrue(diffInMinutes < 3);
+        assertTrue(diffInMillis < 3000);
 
         assertEquals(sql, res0.get(0));
 
@@ -763,9 +847,9 @@
         execSql("CREATE TABLE TST(id INTEGER PRIMARY KEY, name VARCHAR, age integer)");
 
         for (int i = 0; i < 500; i++)
-            execSql("INSERT INTO DEFAULT.TST(id, name, age) VALUES (" + i + ",'name-" + i + "'," + i + 1 + ")");
+            execSql("INSERT INTO \"default\".TST(id, name, age) VALUES (" + i + ",'name-" + i + "'," + i + 1 + ")");
 
-        String sql1 = "SELECT GROUP_ID, GROUP_NAME, PHYSICAL_READS, LOGICAL_READS FROM IGNITE.CACHE_GROUPS_IO";
+        String sql1 = "SELECT GROUP_ID, GROUP_NAME, PHYSICAL_READS, LOGICAL_READS FROM IGNITE.LOCAL_CACHE_GROUPS_IO";
 
         List<List<?>> res1 = execSql(sql1);
 
@@ -779,7 +863,7 @@
 
         assertTrue(map.containsKey(DEFAULT_CACHE_NAME));
 
-        sql1 = "SELECT GROUP_ID, GROUP_NAME, PHYSICAL_READS, LOGICAL_READS FROM IGNITE.CACHE_GROUPS_IO WHERE " +
+        sql1 = "SELECT GROUP_ID, GROUP_NAME, PHYSICAL_READS, LOGICAL_READS FROM IGNITE.LOCAL_CACHE_GROUPS_IO WHERE " +
             "GROUP_NAME='SQL_default_TST'";
 
         assertEquals(1, execSql(sql1).size());
@@ -806,7 +890,7 @@
         List<List<?>> cacheSqlInfos = execSql("SELECT * FROM IGNITE.TABLES WHERE TABLE_NAME = 'CACHE_SQL'");
 
         List<?> expRow = asList(
-            "DEFAULT",           // SCHEMA_NAME
+            "default",           // SCHEMA_NAME
             "CACHE_SQL",         // TABLE_NAME
             "cache_sql",         // CACHE_NAME
             cacheSqlId,          // CACHE_ID
diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/QueryDataPageScanTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/QueryDataPageScanTest.java
index 18ea78d..c536d79 100644
--- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/QueryDataPageScanTest.java
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/QueryDataPageScanTest.java
@@ -58,9 +58,9 @@
 import org.apache.ignite.internal.processors.query.GridQueryProcessor;
 import org.apache.ignite.internal.util.typedef.internal.U;
 import org.apache.ignite.lang.IgniteBiPredicate;
+import org.apache.ignite.testframework.MvccFeatureChecker;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
 import org.apache.ignite.transactions.Transaction;
-import org.apache.ignite.transactions.TransactionSerializationException;
 import org.jetbrains.annotations.Nullable;
 import org.junit.Test;
 
@@ -270,7 +270,8 @@
                     tx.commit();
                 }
                 catch (CacheException e) {
-                    assertTrue(e.getCause() instanceof TransactionSerializationException);
+                    MvccFeatureChecker.assertMvccWriteConflict(e);
+
                     if (!e.getMessage().contains(
                         "Cannot serialize transaction due to write conflict (transaction is marked for rollback)"))
                         throw new IllegalStateException(e);
diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/twostep/DisappearedCacheCauseRetryMessageSelfTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/twostep/DisappearedCacheCauseRetryMessageSelfTest.java
index 4e276b2..ef3d7c8 100644
--- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/twostep/DisappearedCacheCauseRetryMessageSelfTest.java
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/twostep/DisappearedCacheCauseRetryMessageSelfTest.java
@@ -32,6 +32,7 @@
 import org.apache.ignite.lang.IgniteInClosure;
 import org.apache.ignite.plugin.extensions.communication.Message;
 import org.apache.ignite.spi.communication.tcp.TcpCommunicationSpi;
+import org.apache.ignite.testframework.junits.WithSystemProperty;
 import org.junit.Test;
 
 import static org.apache.ignite.IgniteSystemProperties.IGNITE_SQL_RETRY_TIMEOUT;
@@ -41,6 +42,7 @@
 /**
  * Failed to reserve partitions for query (cache is not found on local node) Root cause test
  */
+@WithSystemProperty(key = IGNITE_SQL_RETRY_TIMEOUT, value = "5000")
 public class DisappearedCacheCauseRetryMessageSelfTest extends AbstractIndexingCommonTest {
     /** */
     private static final int NODES_COUNT = 2;
@@ -116,8 +118,6 @@
 
     /** {@inheritDoc} */
     @Override protected void beforeTest() throws Exception {
-        System.setProperty(IGNITE_SQL_RETRY_TIMEOUT, "5000");
-
         startGridsMultiThreaded(NODES_COUNT, false);
 
         personCache = ignite(0).getOrCreateCache(new CacheConfiguration<String, Person>("pers")
diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/twostep/DisappearedCacheWasNotFoundMessageSelfTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/twostep/DisappearedCacheWasNotFoundMessageSelfTest.java
index f1dcf8b..d5a3ef4 100644
--- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/twostep/DisappearedCacheWasNotFoundMessageSelfTest.java
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/twostep/DisappearedCacheWasNotFoundMessageSelfTest.java
@@ -32,6 +32,7 @@
 import org.apache.ignite.plugin.extensions.communication.Message;
 import org.apache.ignite.spi.communication.tcp.TcpCommunicationSpi;
 import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
+import org.apache.ignite.testframework.junits.WithSystemProperty;
 import org.junit.Test;
 
 import static org.apache.ignite.IgniteSystemProperties.IGNITE_SQL_RETRY_TIMEOUT;
@@ -41,6 +42,7 @@
 /**
  * Grid cache context is not registered for cache id root cause message test
  */
+@WithSystemProperty(key = IGNITE_SQL_RETRY_TIMEOUT, value = "5000")
 public class DisappearedCacheWasNotFoundMessageSelfTest extends AbstractIndexingCommonTest {
     /** */
     private static final int NODES_COUNT = 2;
@@ -103,8 +105,6 @@
 
     /** {@inheritDoc} */
     @Override protected void beforeTest() throws Exception {
-        System.setProperty(IGNITE_SQL_RETRY_TIMEOUT, "5000");
-
         startGridsMultiThreaded(NODES_COUNT, false);
 
         personCache = ignite(0).getOrCreateCache(new CacheConfiguration<String, Person>("pers")
diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/twostep/NonCollocatedRetryMessageSelfTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/twostep/NonCollocatedRetryMessageSelfTest.java
index a928c58..753cd28 100644
--- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/twostep/NonCollocatedRetryMessageSelfTest.java
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/twostep/NonCollocatedRetryMessageSelfTest.java
@@ -35,6 +35,7 @@
 import org.apache.ignite.plugin.extensions.communication.Message;
 import org.apache.ignite.spi.IgniteSpiException;
 import org.apache.ignite.spi.communication.tcp.TcpCommunicationSpi;
+import org.apache.ignite.testframework.junits.WithSystemProperty;
 import org.junit.Test;
 
 import static org.apache.ignite.IgniteSystemProperties.IGNITE_SQL_RETRY_TIMEOUT;
@@ -42,6 +43,7 @@
 /**
  * Failed to execute non-collocated query root cause message test
  */
+@WithSystemProperty(key = IGNITE_SQL_RETRY_TIMEOUT, value = "500")
 public class NonCollocatedRetryMessageSelfTest extends AbstractIndexingCommonTest {
     /** */
     private static final int NODES_COUNT = 2;
@@ -50,12 +52,6 @@
     private static final String ORG = "org";
 
     /** */
-    private static final int TEST_SQL_RETRY_TIMEOUT = 500;
-
-    /** */
-    private String sqlRetryTimeoutBackup;
-
-    /** */
     private IgniteCache<String, JoinSqlTestHelper.Person> personCache;
 
     /** */
@@ -87,10 +83,6 @@
 
     /** {@inheritDoc} */
     @Override protected void beforeTest() throws Exception {
-        sqlRetryTimeoutBackup = System.getProperty(IGNITE_SQL_RETRY_TIMEOUT);
-
-        System.setProperty(IGNITE_SQL_RETRY_TIMEOUT, String.valueOf(TEST_SQL_RETRY_TIMEOUT));
-
         startGridsMultiThreaded(NODES_COUNT, false);
 
         CacheConfiguration<String, JoinSqlTestHelper.Person> ccfg1 = new CacheConfiguration<>("pers");
@@ -116,9 +108,6 @@
 
     /** {@inheritDoc} */
     @Override protected void afterTest() {
-        if (sqlRetryTimeoutBackup != null)
-            System.setProperty(IGNITE_SQL_RETRY_TIMEOUT, sqlRetryTimeoutBackup);
-
         stopAllGrids();
     }
 
@@ -136,7 +125,7 @@
 
                 if (GridH2IndexRangeRequest.class.isAssignableFrom(gridMsg.message().getClass())) {
                     try {
-                        U.sleep(TEST_SQL_RETRY_TIMEOUT);
+                        U.sleep(Long.getLong(IGNITE_SQL_RETRY_TIMEOUT));
                     }
                     catch (IgniteInterruptedCheckedException e) {
                         fail("Test was interrupted.");
diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/twostep/RetryCauseMessageSelfTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/twostep/RetryCauseMessageSelfTest.java
index f09cc5b..e52c6d7 100644
--- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/twostep/RetryCauseMessageSelfTest.java
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/twostep/RetryCauseMessageSelfTest.java
@@ -43,6 +43,7 @@
 import org.apache.ignite.plugin.extensions.communication.Message;
 import org.apache.ignite.spi.communication.tcp.TcpCommunicationSpi;
 import org.apache.ignite.testframework.GridTestUtils;
+import org.apache.ignite.testframework.junits.WithSystemProperty;
 import org.junit.Ignore;
 import org.junit.Test;
 
@@ -55,6 +56,7 @@
 /**
  * Test for 6 retry cases
  */
+@WithSystemProperty(key = IGNITE_SQL_RETRY_TIMEOUT, value = "5000")
 public class RetryCauseMessageSelfTest extends AbstractIndexingCommonTest {
     /** */
     private static final int NODES_COUNT = 2;
@@ -335,8 +337,6 @@
 
     /** {@inheritDoc} */
     @Override protected void beforeTest() throws Exception {
-        System.setProperty(IGNITE_SQL_RETRY_TIMEOUT, "5000");
-
         Ignite ignite = startGridsMultiThreaded(NODES_COUNT, false);
 
         GridQueryProcessor qryProc = grid(ignite.name()).context().query();
diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/oom/AbstractQueryOOMTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/oom/AbstractQueryOOMTest.java
index 1d9b4a7..cfe2d3e 100644
--- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/oom/AbstractQueryOOMTest.java
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/oom/AbstractQueryOOMTest.java
@@ -23,10 +23,12 @@
 import java.sql.Statement;
 import java.util.Arrays;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.concurrent.atomic.AtomicBoolean;
 import org.apache.ignite.Ignite;
-import org.apache.ignite.IgniteDataStreamer;
+import org.apache.ignite.IgniteCache;
 import org.apache.ignite.cache.QueryEntity;
 import org.apache.ignite.cache.QueryIndex;
 import org.apache.ignite.cache.query.annotations.QuerySqlField;
@@ -54,7 +56,10 @@
 @RunWith(JUnit4.class)
 public abstract class AbstractQueryOOMTest extends GridCommonAbstractTest {
     /** */
-    private static final long KEY_CNT = 2_000_000L;
+    private static final long KEY_CNT = 1_000_000L;
+
+    /** */
+    private static final int BATCH_SIZE = 10_000;
 
     /** */
     private static final String CACHE_NAME = "test_cache";
@@ -75,7 +80,7 @@
 
     /** {@inheritDoc} */
     @Override protected List<String> additionalRemoteJvmArgs() {
-        return Arrays.asList("-Xmx128m");
+        return Arrays.asList("-Xmx64m", "-Xms64m");
     }
 
     /** {@inheritDoc} */
@@ -126,13 +131,27 @@
 
         local.cluster().active(true);
 
-        try (IgniteDataStreamer streamer = local.dataStreamer(CACHE_NAME)) {
-            for (long i = 0; i < KEY_CNT; ++i) {
-                streamer.addData(i, new Value(i));
+        IgniteCache c = local.cache(CACHE_NAME);
 
-                if (i % 100_000 == 0)
-                    log.info("Populate " + i + " values");
+        Map<Long, Value> batch = new HashMap<>(BATCH_SIZE);
+
+        for (long i = 0; i < KEY_CNT; ++i) {
+            batch.put(i, new Value(i));
+
+            if (batch.size() >= BATCH_SIZE) {
+                c.putAll(batch);
+
+                batch.clear();
             }
+
+            if (i % 100_000 == 0)
+                log.info("Populate " + i + " values");
+        }
+
+        if (!batch.isEmpty()) {
+            c.putAll(batch);
+
+            batch.clear();
         }
 
         awaitPartitionMapExchange(true, true, null);
@@ -140,6 +159,8 @@
         local.cluster().active(false);
 
         stopAllGrids(false);
+
+        IgniteProcessProxy.killAll();
     }
 
     /** {@inheritDoc} */
@@ -151,11 +172,10 @@
         stopAllGrids();
     }
 
-    /**
-     * beforeTest is not user to save the time fot muted tests.
-     * @throws Exception On error.
-     */
-    private void startTestGrid() throws Exception {
+    /** {@inheritDoc} */
+    @Override protected void beforeTest() throws Exception {
+        super.beforeTest();
+
         log.info("Restart cluster");
 
         Ignite loc = startGrid(0);
@@ -182,8 +202,6 @@
      */
     @Test
     public void testHeavyScanLazy() throws Exception {
-        startTestGrid();
-
         checkQuery("SELECT * from test", KEY_CNT, true);
     }
 
@@ -193,8 +211,6 @@
     @Ignore("https://issues.apache.org/jira/browse/IGNITE-9480")
     @Test
     public void testHeavyScanNonLazy() throws Exception {
-        startTestGrid();
-
         checkQueryExpectOOM("SELECT * from test", false);
     }
 
@@ -205,8 +221,6 @@
     @Ignore("https://issues.apache.org/jira/browse/IGNITE-9933")
     @Test
     public void testHeavySortByPkLazy() throws Exception {
-        startTestGrid();
-
         checkQueryExpectOOM("SELECT * from test ORDER BY id", true);
     }
 
@@ -216,8 +230,6 @@
     @Ignore("https://issues.apache.org/jira/browse/IGNITE-9480")
     @Test
     public void testHeavySortByPkNotLazy() throws Exception {
-        startTestGrid();
-
         checkQueryExpectOOM("SELECT * from test ORDER BY id", false);
     }
 
@@ -228,8 +240,6 @@
     @Ignore("https://issues.apache.org/jira/browse/IGNITE-9933")
     @Test
     public void testHeavySortByIndexLazy() throws Exception {
-        startTestGrid();
-
         checkQueryExpectOOM("SELECT * from test ORDER BY indexed", true);
     }
 
@@ -239,8 +249,6 @@
     @Ignore("https://issues.apache.org/jira/browse/IGNITE-9480")
     @Test
     public void testHeavySortByIndexNotLazy() throws Exception {
-        startTestGrid();
-
         checkQueryExpectOOM("SELECT * from test ORDER BY indexed", false);
     }
 
@@ -250,8 +258,6 @@
     @Ignore("https://issues.apache.org/jira/browse/IGNITE-9480")
     @Test
     public void testHeavySortByNotIndexLazy() throws Exception {
-        startTestGrid();
-
         checkQueryExpectOOM("SELECT * from test ORDER BY STR", true);
     }
 
@@ -261,8 +267,6 @@
     @Ignore("https://issues.apache.org/jira/browse/IGNITE-9480")
     @Test
     public void testHeavySortByNotIndexNotLazy() throws Exception {
-        startTestGrid();
-
         checkQueryExpectOOM("SELECT * from test ORDER BY str", false);
     }
 
@@ -271,8 +275,6 @@
      */
     @Test
     public void testHeavyGroupByPkLazy() throws Exception {
-        startTestGrid();
-
         checkQuery("SELECT id, sum(val) from test GROUP BY id", KEY_CNT, true, true);
     }
 
@@ -282,9 +284,6 @@
     @Ignore("https://issues.apache.org/jira/browse/IGNITE-9480")
     @Test
     public void testHeavyGroupByPkNotLazy() throws Exception {
-
-        startTestGrid();
-
         checkQueryExpectOOM("SELECT id, sum(val) from test GROUP BY id", false, true);
     }
 
@@ -333,6 +332,8 @@
 
         try {
             checkQuery(sql, 0, lazy, collocated);
+
+            fail("Query is not produce OOM");
         }
         catch (Exception e) {
             if (hangTimeout.get()) {
diff --git a/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteBinaryCacheQueryTestSuite.java b/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteBinaryCacheQueryTestSuite.java
index 85aa86c..437b886 100644
--- a/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteBinaryCacheQueryTestSuite.java
+++ b/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteBinaryCacheQueryTestSuite.java
@@ -199,6 +199,7 @@
 import org.apache.ignite.internal.processors.query.MultipleStatementsSqlQuerySelfTest;
 import org.apache.ignite.internal.processors.query.RunningQueriesTest;
 import org.apache.ignite.internal.processors.query.SqlIllegalSchemaSelfTest;
+import org.apache.ignite.internal.processors.query.SqlIncompatibleDataTypeExceptionTest;
 import org.apache.ignite.internal.processors.query.SqlNestedQuerySelfTest;
 import org.apache.ignite.internal.processors.query.SqlPushDownFunctionTest;
 import org.apache.ignite.internal.processors.query.SqlQueryHistoryFromClientSelfTest;
@@ -550,6 +551,8 @@
     //Query history.
     SqlQueryHistorySelfTest.class,
     SqlQueryHistoryFromClientSelfTest.class,
+
+    SqlIncompatibleDataTypeExceptionTest.class
 })
 public class IgniteBinaryCacheQueryTestSuite {
 }
diff --git a/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteBinaryCacheQueryTestSuite2.java b/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteBinaryCacheQueryTestSuite2.java
index 0476f47..a6278d0 100644
--- a/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteBinaryCacheQueryTestSuite2.java
+++ b/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteBinaryCacheQueryTestSuite2.java
@@ -51,6 +51,7 @@
 import org.apache.ignite.internal.processors.query.IgniteCacheGroupsSqlSegmentedIndexMultiNodeSelfTest;
 import org.apache.ignite.internal.processors.query.IgniteCacheGroupsSqlSegmentedIndexSelfTest;
 import org.apache.ignite.internal.processors.query.IgniteSqlCreateTableTemplateTest;
+import org.apache.ignite.internal.processors.query.LocalQueryLazyTest;
 import org.apache.ignite.internal.processors.query.SqlLocalQueryConnectionAndStatementTest;
 import org.apache.ignite.internal.processors.query.h2.CacheQueryEntityWithDateTimeApiFieldsTest;
 import org.apache.ignite.internal.processors.query.h2.twostep.CacheQueryMemoryLeakTest;
@@ -133,6 +134,8 @@
     NoneOrSinglePartitionsQueryOptimizationsTest.class,
 
     IgniteSqlCreateTableTemplateTest.class,
+
+    LocalQueryLazyTest.class,
 })
 public class IgniteBinaryCacheQueryTestSuite2 {
 }
diff --git a/modules/platforms/cpp/odbc/src/streaming/streaming_context.cpp b/modules/platforms/cpp/odbc/src/streaming/streaming_context.cpp
index 6953a3b..b9ee94a 100644
--- a/modules/platforms/cpp/odbc/src/streaming/streaming_context.cpp
+++ b/modules/platforms/cpp/odbc/src/streaming/streaming_context.cpp
@@ -57,6 +57,8 @@
 
                 enabled = true;
 
+                order = 0;
+
                 return SqlResult::AI_SUCCESS;
             }
 
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/ApiParity/ClusterParityTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/ApiParity/ClusterParityTest.cs
index f96a4c7..c0068a9 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/ApiParity/ClusterParityTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/ApiParity/ClusterParityTest.cs
@@ -33,7 +33,9 @@
             "startNodesAsync",
             "stopNodes",
             "restartNodes",
-            "baselineConfiguration"
+            "isBaselineAutoAdjustEnabled",
+            "baselineAutoAdjustEnabled",
+            "baselineAutoAdjustTimeout"
         };
 
         /** Members that are missing on .NET side and should be added in future. */
diff --git a/modules/rest-http/pom.xml b/modules/rest-http/pom.xml
index 9ca0e05..5a60e3d 100644
--- a/modules/rest-http/pom.xml
+++ b/modules/rest-http/pom.xml
@@ -49,12 +49,6 @@
         </dependency>
 
         <dependency>
-            <groupId>org.apache.tomcat</groupId>
-            <artifactId>tomcat-servlet-api</artifactId>
-            <version>${tomcat.version}</version>
-        </dependency>
-
-        <dependency>
             <groupId>commons-lang</groupId>
             <artifactId>commons-lang</artifactId>
             <version>${commons.lang.version}</version>
@@ -97,6 +91,12 @@
         </dependency>
 
         <dependency>
+            <groupId>javax.servlet</groupId>
+            <artifactId>javax.servlet-api</artifactId>
+            <version>3.1.0</version>
+        </dependency>
+
+        <dependency>
             <groupId>com.fasterxml.jackson.core</groupId>
             <artifactId>jackson-core</artifactId>
             <version>${jackson.version}</version>
diff --git a/modules/web-console/DEVNOTES.txt b/modules/web-console/DEVNOTES.txt
index e7c5eb3..6119d64 100644
--- a/modules/web-console/DEVNOTES.txt
+++ b/modules/web-console/DEVNOTES.txt
@@ -35,7 +35,7 @@
 Ignite Web Console Direct-Install Maven Build Instructions
 ==========================================================
 To build direct-install archive from sources run following command in Ignite project root folder:
-"mvn clean package -pl :ignite-web-console -am -P web-console,direct-install -DskipTests=true -DskipClientDocs -Dmaven.javadoc.skip=true"
+"mvn clean package -pl :ignite-web-console -am -P web-console,direct-install,lgpl -DskipTests=true -DskipClientDocs -Dmaven.javadoc.skip=true"
 
 Assembled archive can be found here: `modules/web-console/target/ignite-web-console-direct-install-*.zip`.
 
diff --git a/modules/web-console/backend/app/browsersHandler.js b/modules/web-console/backend/app/browsersHandler.js
index 1bfba89..4d5b02d 100644
--- a/modules/web-console/backend/app/browsersHandler.js
+++ b/modules/web-console/backend/app/browsersHandler.js
@@ -245,6 +245,7 @@
                 this.registerVisorTask('queryFetchX2', internalVisor('query.VisorQueryNextPageTask'), internalVisor('query.VisorQueryNextPageTaskArg'));
 
                 this.registerVisorTask('queryFetchFirstPage', internalVisor('query.VisorQueryFetchFirstPageTask'), internalVisor('query.VisorQueryNextPageTaskArg'));
+                this.registerVisorTask('queryPing', internalVisor('query.VisorQueryPingTask'), internalVisor('query.VisorQueryNextPageTaskArg'));
 
                 this.registerVisorTask('queryClose', internalVisor('query.VisorQueryCleanupTask'), 'java.util.Map', 'java.util.UUID', 'java.util.Set');
                 this.registerVisorTask('queryCloseX2', internalVisor('query.VisorQueryCleanupTask'), internalVisor('query.VisorQueryCleanupTaskArg'));
diff --git a/modules/web-console/backend/app/schemas.js b/modules/web-console/backend/app/schemas.js
index fe3c637..808bfd4 100644
--- a/modules/web-console/backend/app/schemas.js
+++ b/modules/web-console/backend/app/schemas.js
@@ -55,7 +55,10 @@
     // Install passport plugin.
     Account.plugin(passportMongo, {
         usernameField: 'email', limitAttempts: true, lastLoginField: 'lastLogin',
-        usernameLowerCase: true
+        usernameLowerCase: true,
+        errorMessages: {
+            UserExistsError: 'A user with the given email is already registered'
+        }
     });
 
     const transform = (doc, ret) => {
diff --git a/modules/web-console/backend/index.js b/modules/web-console/backend/index.js
old mode 100644
new mode 100755
diff --git a/modules/web-console/backend/package.json b/modules/web-console/backend/package.json
index 9d1918e..45a538d 100644
--- a/modules/web-console/backend/package.json
+++ b/modules/web-console/backend/package.json
@@ -34,6 +34,7 @@
       "migrations/*",
       "routes/*",
       "services/*",
+      "templates/*",
       "node_modules/getos/logic/*",
       "node_modules/mongodb-download/node_modules/getos/logic/*"
     ],
@@ -63,7 +64,7 @@
     "mongoose": "4.11.4",
     "morgan": "1.8.2",
     "nconf": "0.8.4",
-    "nodemailer": "4.0.1",
+    "nodemailer": "^5.1.1",
     "passport": "0.3.2",
     "passport-local": "1.0.0",
     "passport-local-mongoose": "4.0.0",
diff --git a/modules/web-console/backend/routes/admin.js b/modules/web-console/backend/routes/admin.js
index 4a38723..70f07b0 100644
--- a/modules/web-console/backend/routes/admin.js
+++ b/modules/web-console/backend/routes/admin.js
@@ -23,20 +23,19 @@
 
 module.exports = {
     implements: 'routes/admin',
-    inject: ['settings', 'mongo', 'services/spaces', 'services/mails', 'services/sessions', 'services/users', 'services/notifications']
+    inject: ['settings', 'mongo', 'services/spaces', 'services/sessions', 'services/users', 'services/notifications']
 };
 
 /**
  * @param settings
  * @param mongo
  * @param spacesService
- * @param {MailsService} mailsService
  * @param {SessionsService} sessionsService
  * @param {UsersService} usersService
  * @param {NotificationsService} notificationsService
  * @returns {Promise}
  */
-module.exports.factory = function(settings, mongo, spacesService, mailsService, sessionsService, usersService, notificationsService) {
+module.exports.factory = function(settings, mongo, spacesService, sessionsService, usersService, notificationsService) {
     return new Promise((factoryResolve) => {
         const router = new express.Router();
 
diff --git a/modules/web-console/backend/services/auth.js b/modules/web-console/backend/services/auth.js
index c6da86e..95fe006 100644
--- a/modules/web-console/backend/services/auth.js
+++ b/modules/web-console/backend/services/auth.js
@@ -57,7 +57,7 @@
 
                     return user.save();
                 })
-                .then((user) => mailsService.emailUserResetLink(host, user));
+                .then((user) => mailsService.sendResetLink(host, user));
         }
 
         /**
@@ -88,7 +88,7 @@
                         });
                     });
                 })
-                .then((user) => mailsService.emailPasswordChanged(host, user));
+                .then((user) => mailsService.sendPasswordChanged(host, user));
         }
 
         /**
@@ -168,7 +168,7 @@
 
                     return user.save();
                 })
-                .then((user) =>  mailsService.emailUserActivation(host, user));
+                .then((user) =>  mailsService.sendActivationLink(host, user));
         }
     }
 
diff --git a/modules/web-console/backend/services/mails.js b/modules/web-console/backend/services/mails.js
index 183fbe1..50d61e8 100644
--- a/modules/web-console/backend/services/mails.js
+++ b/modules/web-console/backend/services/mails.js
@@ -17,6 +17,7 @@
 
 'use strict';
 
+const fs = require('fs');
 const _ = require('lodash');
 const nodemailer = require('nodemailer');
 
@@ -34,16 +35,67 @@
 module.exports.factory = (settings) => {
     class MailsService {
         /**
+         * Read template file.
+         * @param {String} template Path to template file.
+         * @param template
+         */
+        readTemplate(template) {
+            try {
+                return fs.readFileSync(template, 'utf8');
+            }
+            catch (ignored) {
+                throw new Error('Failed to find email template: ' + template);
+            }
+        }
+
+        /**
+         * Get message with resolved variables.
+         *
+         * @param {string} template Message template.
+         * @param {object} ctx Context.
+         * @return Prepared template.
+         * @throws IOException If failed to prepare template.
+         */
+        getMessage(template, ctx) {
+            _.forIn(ctx, (value, key) => template = template.replace(new RegExp(`\\$\\{${key}\\}`, 'g'), value || 'n/a'));
+
+            return template;
+        }
+
+        /**
+         * @param {string} host Web Console host.
+         * @param {Account} user User that signed up.
+         * @param {string} message Message.
+         * @param {object} customCtx Custom context parameters.
+         */
+        buildContext(host, user, message, customCtx) {
+            return {
+                message,
+                ...customCtx,
+                greeting: settings.mail.greeting,
+                sign: settings.mail.sign,
+                firstName: user.firstName,
+                lastName: user.lastName,
+                email: user.res,
+                host,
+                activationLink: `${host}/signin?activationToken=${user.activationToken}`,
+                resetLink: `${host}/password/reset?token=${user.resetPasswordToken}`
+            };
+        }
+
+        /**
          * Send mail to user.
          *
-         * @param {Account} user
-         * @param {String} subject
-         * @param {String} html
-         * @param {String} sendErr
+         * @param {string} template Path to template file.
+         * @param {string} host Web Console host.
+         * @param {Account} user User that signed up.
+         * @param {string} subject Email subject.
+         * @param {string} message Email message.
+         * @param {object} customCtx Custom context parameters.
          * @throws {Error}
          * @return {Promise}
          */
-        send(user, subject, html, sendErr) {
+        send(template, host, user, subject, message, customCtx = {}) {
             const options = settings.mail;
 
             return new Promise((resolve, reject) => {
@@ -61,22 +113,21 @@
                     return transporter.verify().then(() => transporter);
                 })
                 .then((transporter) => {
-                    const sign = options.sign ? `<br><br>--------------<br>${options.sign}<br>` : '';
-                    const to = `"${user.firstName} ${user.lastName}" <${user.email}>`;
+                    const context = this.buildContext(host, user, message, customCtx);
+                    
+                    context.subject = this.getMessage(subject, context);
 
-                    const mail = {
+                    return transporter.sendMail({
                         from: options.from,
-                        to,
-                        subject,
-                        html: html + sign
-                    };
-
-                    return transporter.sendMail(mail);
+                        to: `"${user.firstName} ${user.lastName}" <${user.email}>`,
+                        subject: context.subject,
+                        html: this.getMessage(this.readTemplate(template), context)
+                    });
                 })
                 .catch((err) => {
                     console.log('Failed to send email.', err);
 
-                    return Promise.reject(sendErr ? new Error(sendErr) : err);
+                    return Promise.reject(err);
                 });
         }
 
@@ -87,23 +138,22 @@
          * @param user User that signed up.
          * @param createdByAdmin Whether user was created by admin.
          */
-        emailUserSignUp(host, user, createdByAdmin) {
-            const resetLink = `${host}/password/reset?token=${user.resetPasswordToken}`;
+        sendWelcomeLetter(host, user, createdByAdmin) {
+            if (createdByAdmin) {
+                return this.send('templates/base.html', host, user, 'Account was created for ${greeting}.',
+                    'You are receiving this email because administrator created account for you to use <a href="${host}">${greeting}</a>.<br><br>' +
+                    'If you do not know what this email is about, please ignore it.<br>' +
+                    'You may reset the password by clicking on the following link, or paste this into your browser:<br><br>' +
+                    '<a href="${resetLink}">${resetLink}</a>'
+                );
+            }
 
-            const sbj = createdByAdmin
-                ? 'Account was created for'
-                : 'Thanks for signing up for';
-
-            const reason = createdByAdmin
-                ? 'administrator created account for you'
-                : 'you have signed up';
-
-            return this.send(user, `${sbj} ${settings.mail.greeting}.`,
-                `Hello ${user.firstName} ${user.lastName}!<br><br>` +
-                `You are receiving this email because ${reason} to use <a href="${host}">${settings.mail.greeting}</a>.<br><br>` +
+            return this.send('templates/base.html', host, user, 'Thanks for signing up for ${greeting}.',
+                'You are receiving this email because you have signed up to use <a href="${host}">${greeting}</a>.<br><br>' +
                 'If you do not know what this email is about, please ignore it.<br>' +
                 'You may reset the password by clicking on the following link, or paste this into your browser:<br><br>' +
-                `<a href="${resetLink}">${resetLink}</a>`);
+                '<a href="${resetLink}">${resetLink}</a>'
+            );
         }
 
         /**
@@ -112,15 +162,13 @@
          * @param host
          * @param user
          */
-        emailUserActivation(host, user) {
-            const activationLink = `${host}/signin?activationToken=${user.activationToken}`;
-
-            return this.send(user, `Confirm your account on ${settings.mail.greeting}`,
-                `Hello ${user.firstName} ${user.lastName}!<br><br>` +
-                `You are receiving this email because you have signed up to use <a href="${host}">${settings.mail.greeting}</a>.<br><br>` +
+        sendActivationLink(host, user) {
+            return this.send('templates/base.html', host, user, 'Confirm your account on ${greeting}',
+                'You are receiving this email because you have signed up to use <a href="${host}">${greeting}</a>.<br><br>' +
                 'Please click on the following link, or paste this into your browser to activate your account:<br><br>' +
-                `<a href="${activationLink}">${activationLink}</a>`,
-                'Failed to send email with confirm account link!');
+                '<a href="${activationLink}">${activationLink}</a>'
+            )
+                .catch(() => Promise.reject(new Error('Failed to send email with confirm account link!')));
         }
 
         /**
@@ -129,16 +177,14 @@
          * @param host
          * @param user
          */
-        emailUserResetLink(host, user) {
-            const resetLink = `${host}/password/reset?token=${user.resetPasswordToken}`;
-
-            return this.send(user, 'Password Reset',
-                `Hello ${user.firstName} ${user.lastName}!<br><br>` +
+        sendResetLink(host, user) {
+            return this.send('templates/base.html', host, user, 'Password Reset',
                 'You are receiving this because you (or someone else) have requested the reset of the password for your account.<br><br>' +
                 'Please click on the following link, or paste this into your browser to complete the process:<br><br>' +
-                `<a href="${resetLink}">${resetLink}</a><br><br>` +
-                'If you did not request this, please ignore this email and your password will remain unchanged.',
-                'Failed to send email with reset link!');
+                '<a href="${resetLink}">${resetLink}</a><br><br>' +
+                'If you did not request this, please ignore this email and your password will remain unchanged.'
+            )
+                .catch(() => Promise.reject(new Error('Failed to send email with reset link!')));
         }
 
         /**
@@ -146,11 +192,11 @@
          * @param host
          * @param user
          */
-        emailPasswordChanged(host, user) {
-            return this.send(user, 'Your password has been changed',
-                `Hello ${user.firstName} ${user.lastName}!<br><br>` +
-                `This is a confirmation that the password for your account on <a href="${host}">${settings.mail.greeting}</a> has just been changed.<br><br>`,
-                'Password was changed, but failed to send confirmation email!');
+        sendPasswordChanged(host, user) {
+            return this.send('templates/base.html', host, user, 'Your password has been changed',
+                'This is a confirmation that the password for your account on <a href="${host}">${greeting}</a> has just been changed.'
+            )
+                .catch(() => Promise.reject(new Error('Password was changed, but failed to send confirmation email!')));
         }
 
         /**
@@ -158,11 +204,11 @@
          * @param host
          * @param user
          */
-        emailUserDeletion(host, user) {
-            return this.send(user, 'Your account was removed',
-                `Hello ${user.firstName} ${user.lastName}!<br><br>` +
-                `You are receiving this email because your account for <a href="${host}">${settings.mail.greeting}</a> was removed.`,
-                'Account was removed, but failed to send email notification to user!');
+        sendAccountDeleted(host, user) {
+            return this.send('templates/base.html', host, user, 'Your account was removed',
+                'You are receiving this email because your account for <a href="${host}">${greeting}</a> was removed.',
+                'Account was removed, but failed to send email notification to user!')
+                .catch(() => Promise.reject(new Error('Password was changed, but failed to send confirmation email!')));
         }
     }
 
diff --git a/modules/web-console/backend/services/users.js b/modules/web-console/backend/services/users.js
index ecfdc0b..377efed 100644
--- a/modules/web-console/backend/services/users.js
+++ b/modules/web-console/backend/services/users.js
@@ -56,6 +56,11 @@
                     user.resetPasswordToken = utilsService.randomString(settings.tokenLength);
                     user.activated = false;
 
+                    if (settings.activation.enabled) {
+                        user.activationToken = utilsService.randomString(settings.tokenLength);
+                        user.activationSentAt = new Date();
+                    }
+
                     if (settings.server.disableSignup && !user.admin && !createdByAdmin)
                         throw new errors.ServerErrorException('Sign-up is not allowed. Ask your Web Console administrator to create account for you.');
 
@@ -80,20 +85,15 @@
                 })
                 .then((registered) => {
                     if (settings.activation.enabled) {
-                        registered.activationToken = utilsService.randomString(settings.tokenLength);
-                        registered.activationSentAt = new Date();
+                        mailsService.sendActivationLink(host, registered);
 
-                        if (!createdByAdmin) {
-                            return registered.save()
-                                .then(() => {
-                                    mailsService.emailUserActivation(host, registered);
+                        if (createdByAdmin)
+                            return registered;
 
-                                    throw new errors.MissingConfirmRegistrationException(registered.email);
-                                });
-                        }
+                        throw new errors.MissingConfirmRegistrationException(registered.email);
                     }
 
-                    mailsService.emailUserSignUp(host, registered, createdByAdmin);
+                    mailsService.sendWelcomeLetter(host, registered, createdByAdmin);
 
                     return registered;
                 });
@@ -244,7 +244,7 @@
                         .catch((err) => console.error(`Failed to cleanup spaces [user=${user.username}, err=${err}`))
                         .then(() => user);
                 })
-                .then((user) => mailsService.emailUserDeletion(host, user));
+                .then((user) => mailsService.sendAccountDeleted(host, user));
         }
 
         /**
diff --git a/modules/web-console/backend/templates/base.html b/modules/web-console/backend/templates/base.html
new file mode 100644
index 0000000..4b741b1
--- /dev/null
+++ b/modules/web-console/backend/templates/base.html
@@ -0,0 +1,21 @@
+<!--
+  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.
+-->
+
+Hello ${firstName} ${lastName}!<br><br>
+${message}<br><br>
+--------------<br>
+${sign}<br>
\ No newline at end of file
diff --git a/modules/web-console/frontend/app/components/breadcrumbs/style.scss b/modules/web-console/frontend/app/components/breadcrumbs/style.scss
index f0a98ee..1638ea6 100644
--- a/modules/web-console/frontend/app/components/breadcrumbs/style.scss
+++ b/modules/web-console/frontend/app/components/breadcrumbs/style.scss
@@ -18,13 +18,12 @@
 breadcrumbs {
     $side-margin: 5px;
 
-    padding-left: $side-margin;
-    padding-right: $side-margin;
+    padding: 3px $side-margin;
     display: inline-flex;
     align-items: center;
     flex-direction: row;
 
-    height: 26px;
+    min-height: 20px;
     border-radius: 4px;
     background-color: rgba(197, 197, 197, 0.1);
     font-size: 12px;
diff --git a/modules/web-console/frontend/app/components/cluster-selector/controller.js b/modules/web-console/frontend/app/components/cluster-selector/controller.js
index 484a5eb..98e9043 100644
--- a/modules/web-console/frontend/app/components/cluster-selector/controller.js
+++ b/modules/web-console/frontend/app/components/cluster-selector/controller.js
@@ -19,6 +19,7 @@
 
 import { BehaviorSubject } from 'rxjs';
 import {tap, filter, combineLatest} from 'rxjs/operators';
+import {CancellationError} from 'app/errors/CancellationError';
 
 export default class {
     static $inject = ['AgentManager', 'IgniteConfirm', 'IgniteVersion', 'IgniteMessages'];
@@ -63,8 +64,13 @@
             this.clusters$.unsubscribe();
     }
 
-    change() {
-        this.agentMgr.switchCluster(this.cluster);
+    change(item) {
+        this.agentMgr.switchCluster(this.cluster)
+            .then(() => this.cluster = item)
+            .catch((err) => {
+                if (!(err instanceof CancellationError))
+                    this.Messages.showError('Failed to switch cluster: ', err);
+            });
     }
 
     isChangeStateAvailable() {
diff --git a/modules/web-console/frontend/app/components/cluster-selector/template.pug b/modules/web-console/frontend/app/components/cluster-selector/template.pug
index 39c1af2..8f34ca6 100644
--- a/modules/web-console/frontend/app/components/cluster-selector/template.pug
+++ b/modules/web-console/frontend/app/components/cluster-selector/template.pug
@@ -34,8 +34,6 @@
 
 span(data-ng-if='!$ctrl.isDemo && $ctrl.clusters.length > 1')
     div.btn-ignite.btn-ignite--primary(
-        ng-model='$ctrl.cluster'
-
         bs-dropdown=''
         data-trigger='click'
         data-container='body'
@@ -53,7 +51,7 @@
 
     ul.bs-select-menu.dropdown-menu(role='menu')
         li(ng-repeat='item in $ctrl.clusters')
-            button.btn-ignite.bssm-item-button(ng-click='$ctrl.cluster = item; $ctrl.change()')
+            button.btn-ignite.bssm-item-button(ng-click='$ctrl.change(item)')
                 span.icon-left
                     svg(ignite-icon='{{ item.secured ? "lockClosed" : "lockOpened" }}')
                 | {{ item.name }}
diff --git a/modules/web-console/frontend/app/components/list-editable/components/list-editable-add-item-button/component.spec.js b/modules/web-console/frontend/app/components/list-editable/components/list-editable-add-item-button/component.spec.js
index 9e37319..06c6b84 100644
--- a/modules/web-console/frontend/app/components/list-editable/components/list-editable-add-item-button/component.spec.js
+++ b/modules/web-console/frontend/app/components/list-editable/components/list-editable-add-item-button/component.spec.js
@@ -21,7 +21,7 @@
 import {ListEditableAddItemButton as Ctrl} from './component';
 
 suite('list-editable-add-item-button component', () => {
-    test.skip('has addItem method with correct locals', () => {
+    test('has addItem method with correct locals', () => {
         const i = new Ctrl();
         i._listEditable = {
             ngModel: {
@@ -32,10 +32,9 @@
         i._addItem = spy();
         i.addItem();
         assert.isOk(i._addItem.calledOnce);
-        assert.deepEqual(i._addItem.lastCall.args[0], {
-            $edit: i._listEditable.ngModel.editListItem
-        });
+        assert.deepEqual(i._addItem.lastCall.args[0].$edit, i._listEditable.ngModel.editListItem );
     });
+
     test('inserts button after list-editable', () => {
         Ctrl.hasItemsTemplate = 'tpl';
         const $scope = {};
@@ -57,6 +56,7 @@
         assert.equal($transclude.lastCall.args[0], $scope);
         assert.equal(clone.insertAfter.lastCall.args[0], i._listEditable.$element);
     });
+
     test('exposes hasItems getter', () => {
         const i = new Ctrl();
         i._listEditable = {
diff --git a/modules/web-console/frontend/app/components/page-queries/components/queries-notebook/controller.ts b/modules/web-console/frontend/app/components/page-queries/components/queries-notebook/controller.ts
index 7a96a91..ba31155 100644
--- a/modules/web-console/frontend/app/components/page-queries/components/queries-notebook/controller.ts
+++ b/modules/web-console/frontend/app/components/page-queries/components/queries-notebook/controller.ts
@@ -18,8 +18,8 @@
 import _ from 'lodash';
 import {nonEmpty, nonNil} from 'app/utils/lodashMixins';
 import id8 from 'app/utils/id8';
-import {timer, merge, defer, of, EMPTY, from} from 'rxjs';
-import {tap, switchMap, exhaustMap, take, pluck, distinctUntilChanged, filter, map, catchError} from 'rxjs/operators';
+import {Subject, defer, from, of, merge, timer, EMPTY} from 'rxjs';
+import {catchError, distinctUntilChanged, expand, exhaustMap, filter, finalize, first, ignoreElements, map, mergeMap, pluck, switchMap, takeUntil, takeWhile, take, tap} from 'rxjs/operators';
 
 import {CSV} from 'app/services/CSV';
 
@@ -33,6 +33,7 @@
 import {default as LegacyConfirmServiceFactory} from 'app/services/Confirm.service';
 import {default as InputDialog} from 'app/components/input-dialog/input-dialog.service';
 import {QueryActions} from './components/query-actions-button/controller';
+import {CancellationError} from 'app/errors/CancellationError';
 
 // Time line X axis descriptor.
 const TIME_LINE = {value: -1, type: 'java.sql.Date', label: 'TIME_LINE'};
@@ -82,6 +83,9 @@
         self.csvIsPreparing = false;
         self.scanningInProgress = false;
 
+        self.cancelQuerySubject = new Subject();
+        self.cancelExportSubject = new Subject();
+
         _.assign(this, paragraph);
 
         Object.defineProperty(this, 'gridOptions', {value: {
@@ -148,6 +152,13 @@
             message: ''
         }});
 
+        this.showLoading = (enable) => {
+            if (this.qryType === 'scan')
+                this.scanningInProgress = enable;
+
+            this.loading = enable;
+        };
+
         this.setError = (err) => {
             this.error.root = err;
             this.error.message = errorParser.extractMessage(err);
@@ -208,7 +219,7 @@
     }
 
     scanExplain() {
-        return this.queryExecuted() && this.queryArgs.type !== 'QUERY';
+        return this.queryExecuted() && (this.qryType === 'scan' || this.queryArgs.query.startsWith('EXPLAIN '));
     }
 
     timeLineSupported() {
@@ -251,20 +262,40 @@
 
         this.cancelRefresh($interval);
     }
+
+    toJSON() {
+        return {
+            name: this.name,
+            query: this.query,
+            result: this.result,
+            pageSize: this.pageSize,
+            timeLineSpan: this.timeLineSpan,
+            maxPages: this.maxPages,
+            cacheName: this.cacheName,
+            useAsDefaultSchema: this.useAsDefaultSchema,
+            chartsOptions: this.chartsOptions,
+            rate: this.rate,
+            qryType: this.qryType,
+            nonCollocatedJoins: this.nonCollocatedJoins,
+            enforceJoinOrder: this.enforceJoinOrder,
+            lazy: this.lazy,
+            collocated: this.collocated
+        };
+    }
 }
 
 // Controller for SQL notebook screen.
 export class NotebookCtrl {
-    static $inject = ['IgniteInput', '$rootScope', '$scope', '$http', '$q', '$timeout', '$interval', '$animate', '$location', '$anchorScroll', '$state', '$filter', '$modal', '$popover', '$window', 'IgniteLoading', 'IgniteLegacyUtils', 'IgniteMessages', 'IgniteConfirm', 'AgentManager', 'IgniteChartColors', 'IgniteNotebook', 'IgniteNodes', 'uiGridExporterConstants', 'IgniteVersion', 'IgniteActivitiesData', 'JavaTypes', 'IgniteCopyToClipboard', 'CSV', 'IgniteErrorParser', 'DemoInfo'];
+    static $inject = ['IgniteInput', '$rootScope', '$scope', '$http', '$q', '$timeout', '$transitions', '$interval', '$animate', '$location', '$anchorScroll', '$state', '$filter', '$modal', '$popover', '$window', 'IgniteLoading', 'IgniteLegacyUtils', 'IgniteMessages', 'IgniteConfirm', 'AgentManager', 'IgniteChartColors', 'IgniteNotebook', 'IgniteNodes', 'uiGridExporterConstants', 'IgniteVersion', 'IgniteActivitiesData', 'JavaTypes', 'IgniteCopyToClipboard', 'CSV', 'IgniteErrorParser', 'DemoInfo'];
 
     /**
      * @param {CSV} CSV
      */
-    constructor(private IgniteInput: InputDialog, $root, private $scope, $http, $q, $timeout, $interval, $animate, $location, $anchorScroll, $state, $filter, $modal, $popover, $window, Loading, LegacyUtils, private Messages: ReturnType<typeof MessagesServiceFactory>, private Confirm: ReturnType<typeof LegacyConfirmServiceFactory>, agentMgr, IgniteChartColors, private Notebook: Notebook, Nodes, uiGridExporterConstants, Version, ActivitiesData, JavaTypes, IgniteCopyToClipboard, CSV, errorParser, DemoInfo) {
+    constructor(private IgniteInput: InputDialog, $root, private $scope, $http, $q, $timeout, $transitions, $interval, $animate, $location, $anchorScroll, $state, $filter, $modal, $popover, $window, Loading, LegacyUtils, private Messages: ReturnType<typeof MessagesServiceFactory>, private Confirm: ReturnType<typeof LegacyConfirmServiceFactory>, agentMgr, IgniteChartColors, private Notebook: Notebook, Nodes, uiGridExporterConstants, Version, ActivitiesData, JavaTypes, IgniteCopyToClipboard, CSV, errorParser, DemoInfo) {
         const $ctrl = this;
 
         this.CSV = CSV;
-        Object.assign(this, { $root, $scope, $http, $q, $timeout, $interval, $animate, $location, $anchorScroll, $state, $filter, $modal, $popover, $window, Loading, LegacyUtils, Messages, Confirm, agentMgr, IgniteChartColors, Notebook, Nodes, uiGridExporterConstants, Version, ActivitiesData, JavaTypes, errorParser, DemoInfo });
+        Object.assign(this, { $root, $scope, $http, $q, $timeout, $transitions, $interval, $animate, $location, $anchorScroll, $state, $filter, $modal, $popover, $window, Loading, LegacyUtils, Messages, Confirm, agentMgr, IgniteChartColors, Notebook, Nodes, uiGridExporterConstants, Version, ActivitiesData, JavaTypes, errorParser, DemoInfo });
 
         // Define template urls.
         $ctrl.paragraphRateTemplateUrl = paragraphRateTemplateUrl;
@@ -1233,46 +1264,111 @@
             _rebuildColumns(paragraph);
         };
 
-        const _showLoading = (paragraph, enable) => {
-            if (paragraph.qryType === 'scan')
-                paragraph.scanningInProgress = enable;
+        /**
+         * Execute query and get first result page.
+         *
+         * @param qryType Query type. 'query' or `scan`.
+         * @param qryArg Argument with query properties.
+         * @param {(res) => any} onQueryStarted Action to execute when query ID is received.
+         * @return {Observable<VisorQueryResult>} Observable with first query result page.
+         */
+        const _executeQuery0 = (qryType, qryArg, onQueryStarted: (res) => any = () => {}) => {
+            return from(qryType === 'scan' ? agentMgr.queryScan(qryArg) : agentMgr.querySql(qryArg)).pipe(
+                tap((res) => {
+                    onQueryStarted(res);
+                    $scope.$applyAsync();
+                }),
+                exhaustMap((res) => {
+                    if (!_.isNil(res.rows))
+                        return of(res);
 
-            paragraph.loading = enable;
+                    const fetchFirstPageTask = timer(100, 500).pipe(
+                        exhaustMap(() => agentMgr.queryFetchFistsPage(qryArg.nid, res.queryId, qryArg.pageSize)),
+                        filter((res) => !_.isNil(res.rows))
+                    );
+
+                    const pingQueryTask = timer(60000, 60000).pipe(
+                        exhaustMap(() => agentMgr.queryPing(qryArg.nid, res.queryId)),
+                        takeWhile(({queryPingSupported}) => queryPingSupported),
+                        ignoreElements()
+                    );
+
+                    return merge(fetchFirstPageTask, pingQueryTask);
+                }),
+                first()
+            );
         };
 
-        const _fetchQueryResult = (paragraph, clearChart, res, qryArg) => {
-            if (!_.isNil(res.rows)) {
-                _processQueryResult(paragraph, clearChart, res);
-                _tryStartRefresh(paragraph);
-
-                $scope.$applyAsync();
-
-                return;
-            }
-
-            const subscription = timer(100, 500).pipe(
-                exhaustMap(() => agentMgr.queryFetchFistsPage(qryArg.nid, res.queryId, qryArg.pageSize)),
-                filter((res) => !_.isNil(res.rows)),
-                take(1),
-                map((res) => _fetchQueryResult(paragraph, false, res, qryArg)),
+        /**
+         * Execute query with old query clearing and showing of query result.
+         *
+         * @param paragraph Query paragraph.
+         * @param qryArg Argument with query properties.
+         * @param {(res) => any} onQueryStarted Action to execute when query ID is received.
+         * @param {(res) => any} onQueryFinished Action to execute when first query result page is received.
+         * @param {(err) => any} onError Action to execute when error occured.
+         * @return {Observable<VisorQueryResult>} Observable with first query result page.
+         */
+        const _executeQuery = (
+            paragraph,
+            qryArg,
+            onQueryStarted: (res) => any = () => {},
+            onQueryFinished: (res) => any = () => {},
+            onError: (err) => any = () => {}
+        ) => {
+            return from(_closeOldQuery(paragraph)).pipe(
+                switchMap(() => _executeQuery0(paragraph.qryType, qryArg, onQueryStarted)),
+                tap((res) => {
+                    onQueryFinished(res);
+                    $scope.$applyAsync();
+                }),
+                takeUntil(paragraph.cancelQuerySubject),
                 catchError((err) => {
-                    if (paragraph.subscription) {
-                        paragraph.subscription.unsubscribe();
-                        paragraph.setError(err);
-
-                        _showLoading(paragraph, false);
-                        delete paragraph.subscription;
-
-                        $scope.$applyAsync();
-                    }
+                    onError(err);
+                    $scope.$applyAsync();
 
                     return of(err);
                 })
-            ).subscribe();
+            );
+        };
 
-            Object.defineProperty(paragraph, 'subscription', {value: subscription, configurable: true});
+        /**
+         * Execute query and get all query results.
+         *
+         * @param paragraph Query paragraph.
+         * @param qryArg Argument with query properties.
+         * @param {(res) => any} onQueryStarted Action to execute when query ID is received.
+         * @param {(res) => any} onQueryFinished Action to execute when first query result page is received.
+         * @param {(err) => any} onError Action to execute when error occured.
+         * @return {Observable<any>} Observable with full query result.
+         */
+        const _exportQueryAll = (
+            paragraph,
+            qryArg,
+            onQueryStarted: (res) => any = () => {},
+            onQueryFinished: (res) => any = () => {},
+            onError: (err) => any = () => {}
+        ) => {
+            return from(_closeOldExport(paragraph)).pipe(
+                switchMap(() => _executeQuery0(paragraph.qryType, qryArg, onQueryStarted)),
+                expand((acc) => {
+                    return from(agentMgr.queryNextPage(acc.responseNodeId, acc.queryId, qryArg.pageSize)
+                        .then((res) => {
+                            acc.rows = acc.rows.concat(res.rows);
+                            acc.hasMore = res.hasMore;
 
-            return subscription;
+                            return acc;
+                        }));
+                }),
+                first((acc) => !acc.hasMore),
+                tap(onQueryFinished),
+                takeUntil(paragraph.cancelExportSubject),
+                catchError((err) => {
+                    onError(err);
+
+                    return of(err);
+                })
+            );
         };
 
         /**
@@ -1285,11 +1381,6 @@
             const prevKeyCols = paragraph.chartKeyCols;
             const prevValCols = paragraph.chartValCols;
 
-            if (paragraph.subscription) {
-                paragraph.subscription.unsubscribe();
-                delete paragraph.subscription;
-            }
-
             if (!_.eq(paragraph.meta, res.columns)) {
                 paragraph.meta = [];
 
@@ -1360,7 +1451,7 @@
             while (chartHistory.length > HISTORY_LENGTH)
                 chartHistory.shift();
 
-            _showLoading(paragraph, false);
+            paragraph.showLoading(false);
 
             if (_.isNil(paragraph.result) || paragraph.result === 'none' || paragraph.scanExplain())
                 paragraph.result = 'table';
@@ -1380,6 +1471,11 @@
             }
         };
 
+        const _fetchQueryResult = (paragraph, clearChart, res) => {
+            _processQueryResult(paragraph, clearChart, res);
+            _tryStartRefresh(paragraph);
+        };
+
         const _closeOldQuery = (paragraph) => {
             const nid = paragraph.resNodeId;
 
@@ -1393,25 +1489,27 @@
             return $q.when();
         };
 
-        $scope.cancelQuery = (paragraph) => {
-            if (paragraph.subscription) {
-                paragraph.subscription.unsubscribe();
-                delete paragraph.subscription;
+        const _closeOldExport = (paragraph) => {
+            const nid = paragraph.exportNodeId;
+
+            if (paragraph.exportId) {
+                const exportId = paragraph.exportId;
+                delete paragraph.exportId;
+
+                return agentMgr.queryClose(nid, exportId);
             }
 
-            _showLoading(paragraph, false);
+            return $q.when();
+        };
+
+        $scope.cancelQuery = (paragraph) => {
+            paragraph.cancelQuerySubject.next(true);
+
             this.$scope.stopRefresh(paragraph);
 
             _closeOldQuery(paragraph)
-                .then(() => _showLoading(paragraph, false))
-                .catch((err) => {
-                    _showLoading(paragraph, false);
-                    paragraph.setError(err);
-                });
-        };
-
-        $scope.cancelQueryAvailable = (paragraph) => {
-            return !!paragraph.subscription;
+                .catch((err) => paragraph.setError(err))
+                .finally(() => paragraph.showLoading(false));
         };
 
         /**
@@ -1464,10 +1562,11 @@
         const _executeRefresh = (paragraph) => {
             const args = paragraph.queryArgs;
 
-            agentMgr.awaitCluster()
-                .then(() => _closeOldQuery(paragraph))
-                .then(() => args.localNid || _chooseNode(args.cacheName, false))
-                .then((nid) => {
+            from(agentMgr.awaitCluster()).pipe(
+                switchMap(() => args.localNid ? of(args.localNid) : from(_chooseNode(args.cacheName, false))),
+                switchMap((nid) => {
+                    paragraph.showLoading(true);
+
                     const qryArg = {
                         nid,
                         cacheName: args.cacheName,
@@ -1481,16 +1580,24 @@
                         collocated: args.collocated
                     };
 
-                    return agentMgr.querySql(qryArg)
-                        .then((res) => _fetchQueryResult(paragraph, false, res, qryArg));
-                })
-                .catch((err) => paragraph.setError(err));
+                    return _executeQuery(
+                        paragraph,
+                        qryArg,
+                        (res) => _initQueryResult(paragraph, res),
+                        (res) => _fetchQueryResult(paragraph, false, res),
+                        (err) => {
+                            paragraph.setError(err);
+                            paragraph.ace && paragraph.ace.focus();
+                            $scope.stopRefresh(paragraph);
+                        }
+                    );
+                }),
+                finalize(() => paragraph.showLoading(false))
+            ).toPromise();
         };
 
         const _tryStartRefresh = function(paragraph) {
-            _tryStopRefresh(paragraph);
-
-            if (_.get(paragraph, 'rate.installed') && paragraph.queryExecuted()) {
+            if (_.get(paragraph, 'rate.installed') && paragraph.queryExecuted() && paragraph.nonRefresh()) {
                 $scope.chartAcceptKeyColumn(paragraph, TIME_LINE);
 
                 const delay = paragraph.rate.value * paragraph.rate.unit;
@@ -1532,23 +1639,34 @@
             paragraph.resNodeId = res.responseNodeId;
             paragraph.queryId = res.queryId;
 
-            paragraph.rows = [];
-            paragraph.gridOptions.adjustHeight(paragraph.rows.length);
+            if (paragraph.nonRefresh()) {
+                paragraph.rows = [];
 
-            paragraph.meta = [];
-            paragraph.setError({message: ''});
+                paragraph.meta = [];
+                paragraph.setError({message: ''});
+            }
 
             paragraph.hasNext = false;
         };
 
+        const _initExportResult = (paragraph, res) => {
+            paragraph.exportNodeId = res.responseNodeId;
+            paragraph.exportId = res.queryId;
+        };
+
         $scope.execute = (paragraph, local = false) => {
+            if (!$scope.queryAvailable(paragraph))
+                return;
+
             const nonCollocatedJoins = !!paragraph.nonCollocatedJoins;
             const enforceJoinOrder = !!paragraph.enforceJoinOrder;
             const lazy = !!paragraph.lazy;
             const collocated = !!paragraph.collocated;
 
-            $scope.queryAvailable(paragraph) && _chooseNode(paragraph.cacheName, local)
-                .then((nid) => {
+            _cancelRefresh(paragraph);
+
+            from(_chooseNode(paragraph.cacheName, local)).pipe(
+                switchMap((nid) => {
                     // If we are executing only selected part of query then Notebook shouldn't be saved.
                     if (!paragraph.partialQuery)
                         Notebook.save($scope.notebook).catch(Messages.showError);
@@ -1556,66 +1674,61 @@
                     paragraph.localQueryMode = local;
                     paragraph.prevQuery = paragraph.queryArgs ? paragraph.queryArgs.query : paragraph.query;
 
-                    _showLoading(paragraph, true);
+                    paragraph.showLoading(true);
 
-                    return _closeOldQuery(paragraph)
-                        .then(() => {
-                            const query = paragraph.partialQuery || paragraph.query;
+                    const query = paragraph.partialQuery || paragraph.query;
 
-                            const args = paragraph.queryArgs = {
-                                type: 'QUERY',
-                                cacheName: $scope.cacheNameForSql(paragraph),
-                                query,
-                                pageSize: paragraph.pageSize,
-                                maxPages: paragraph.maxPages,
-                                nonCollocatedJoins,
-                                enforceJoinOrder,
-                                localNid: local ? nid : null,
-                                lazy,
-                                collocated
-                            };
+                    const args = paragraph.queryArgs = {
+                        cacheName: $scope.cacheNameForSql(paragraph),
+                        query,
+                        pageSize: paragraph.pageSize,
+                        maxPages: paragraph.maxPages,
+                        nonCollocatedJoins,
+                        enforceJoinOrder,
+                        localNid: local ? nid : null,
+                        lazy,
+                        collocated
+                    };
 
-                            ActivitiesData.post({ group: 'sql', action: '/queries/execute' });
+                    ActivitiesData.post({ group: 'sql', action: '/queries/execute' });
 
-                            const qry = args.maxPages ? addLimit(args.query, args.pageSize * args.maxPages) : query;
-                            const qryArg = {
-                                nid,
-                                cacheName: args.cacheName,
-                                query: qry,
-                                nonCollocatedJoins,
-                                enforceJoinOrder,
-                                replicatedOnly: false,
-                                local,
-                                pageSize: args.pageSize,
-                                lazy,
-                                collocated
-                            };
+                    const qry = args.maxPages ? addLimit(args.query, args.pageSize * args.maxPages) : query;
+                    const qryArg = {
+                        nid,
+                        cacheName: args.cacheName,
+                        query: qry,
+                        nonCollocatedJoins,
+                        enforceJoinOrder,
+                        replicatedOnly: false,
+                        local,
+                        pageSize: args.pageSize,
+                        lazy,
+                        collocated
+                    };
 
-                            return agentMgr.querySql(qryArg)
-                                .then((res) => {
-                                    _initQueryResult(paragraph, res);
-
-                                    return _fetchQueryResult(paragraph, true, res, qryArg);
-                                });
-                        })
-                        .catch((err) => {
+                    return _executeQuery(
+                        paragraph,
+                        qryArg,
+                        (res) => _initQueryResult(paragraph, res),
+                        (res) => _fetchQueryResult(paragraph, true, res),
+                        (err) => {
                             paragraph.setError(err);
-
-                            _showLoading(paragraph, false);
-
+                            paragraph.ace && paragraph.ace.focus();
                             $scope.stopRefresh(paragraph);
 
                             Messages.showError(err);
-                        })
-                        .then(() => paragraph.ace.focus());
-                });
+                        }
+                    );
+                }),
+                finalize(() => paragraph.showLoading(false))
+            ).toPromise();
         };
 
         const _cancelRefresh = (paragraph) => {
             if (paragraph.rate && paragraph.rate.stopTime) {
                 delete paragraph.queryArgs;
 
-                paragraph.rate.installed = false;
+                _.set(paragraph, 'rate.installed', false);
 
                 $interval.cancel(paragraph.rate.stopTime);
 
@@ -1624,25 +1737,23 @@
         };
 
         $scope.explain = (paragraph) => {
+            if (!$scope.queryAvailable(paragraph))
+                return;
+
             const nonCollocatedJoins = !!paragraph.nonCollocatedJoins;
             const enforceJoinOrder = !!paragraph.enforceJoinOrder;
             const collocated = !!paragraph.collocated;
 
-            if (!$scope.queryAvailable(paragraph))
-                return;
-
             if (!paragraph.partialQuery)
                 Notebook.save($scope.notebook).catch(Messages.showError);
 
             _cancelRefresh(paragraph);
 
-            _showLoading(paragraph, true);
+            paragraph.showLoading(true);
 
-            _closeOldQuery(paragraph)
-                .then(() => _chooseNode(paragraph.cacheName, false))
-                .then((nid) => {
+            from(_chooseNode(paragraph.cacheName, false)).pipe(
+                switchMap((nid) => {
                     const args = paragraph.queryArgs = {
-                        type: 'EXPLAIN',
                         cacheName: $scope.cacheNameForSql(paragraph),
                         query: 'EXPLAIN ' + (paragraph.partialQuery || paragraph.query),
                         pageSize: paragraph.pageSize
@@ -1662,76 +1773,64 @@
                         lazy: false, collocated
                     };
 
-                    return agentMgr.querySql(qryArg)
-                        .then((res) => {
-                            _initQueryResult(paragraph, res);
-
-                            return _fetchQueryResult(paragraph, true, res, qryArg);
-                        });
-                })
-                .catch((err) => {
-                    paragraph.setError(err);
-
-                    _showLoading(paragraph, false);
-                })
-                .then(() => paragraph.ace.focus());
+                    return _executeQuery(
+                        paragraph,
+                        qryArg,
+                        (res) => _initQueryResult(paragraph, res),
+                        (res) => _fetchQueryResult(paragraph, true, res),
+                        (err) => {
+                            paragraph.setError(err);
+                            paragraph.ace && paragraph.ace.focus();
+                        }
+                    );
+                }),
+                finalize(() => paragraph.showLoading(false))
+            ).toPromise();
         };
 
         $scope.scan = (paragraph, local = false) => {
+            if (!$scope.scanAvailable(paragraph))
+                return;
+
             const cacheName = paragraph.cacheName;
             const caseSensitive = !!paragraph.caseSensitive;
             const filter = paragraph.filter;
             const pageSize = paragraph.pageSize;
 
-            $scope.scanAvailable(paragraph) && _chooseNode(cacheName, local)
-                .then((nid) => {
+            from(_chooseNode(cacheName, local)).pipe(
+                switchMap((nid) => {
                     paragraph.localQueryMode = local;
 
                     Notebook.save($scope.notebook)
                         .catch(Messages.showError);
 
-                    _cancelRefresh(paragraph);
+                    paragraph.showLoading(true);
 
-                    _showLoading(paragraph, true);
+                    const qryArg = paragraph.queryArgs = {
+                        cacheName,
+                        filter,
+                        regEx: false,
+                        caseSensitive,
+                        near: false,
+                        pageSize,
+                        localNid: local ? nid : null
+                    };
 
-                    _closeOldQuery(paragraph)
-                        .then(() => {
-                            paragraph.queryArgs = {
-                                type: 'SCAN',
-                                cacheName,
-                                filter,
-                                regEx: false,
-                                caseSensitive,
-                                near: false,
-                                pageSize,
-                                localNid: local ? nid : null
-                            };
+                    qryArg.nid = nid;
+                    qryArg.local = local;
 
-                            ActivitiesData.post({ group: 'sql', action: '/queries/scan' });
+                    ActivitiesData.post({ group: 'sql', action: '/queries/scan' });
 
-                            const qryArg = {
-                                nid,
-                                cacheName,
-                                filter,
-                                regEx: false,
-                                caseSensitive,
-                                near: false,
-                                local,
-                                pageSize
-                            };
-
-                            return agentMgr.queryScan(qryArg).then((res) => {
-                                _initQueryResult(paragraph, res);
-
-                                return _fetchQueryResult(paragraph, true, res, qryArg);
-                            });
-                        })
-                        .catch((err) => {
-                            paragraph.setError(err);
-
-                            _showLoading(paragraph, false);
-                        });
-                });
+                    return _executeQuery(
+                        paragraph,
+                        qryArg,
+                        (res) => _initQueryResult(paragraph, res),
+                        (res) => _fetchQueryResult(paragraph, true, res),
+                        (err) => paragraph.setError(err)
+                    );
+                }),
+                finalize(() => paragraph.showLoading(false))
+            ).toPromise();
         };
 
         function _updatePieChartsWithData(paragraph, newDatum) {
@@ -1751,41 +1850,52 @@
             });
         }
 
+        const _processQueryNextPage = (paragraph, res) => {
+            paragraph.page++;
+
+            paragraph.total += paragraph.rows.length;
+
+            paragraph.duration = res.duration;
+
+            paragraph.rows = res.rows;
+
+            if (paragraph.chart()) {
+                if (paragraph.result === 'pie')
+                    _updatePieChartsWithData(paragraph, _pieChartDatum(paragraph));
+                else
+                    _updateChartsWithData(paragraph, _chartDatum(paragraph));
+            }
+
+            paragraph.gridOptions.adjustHeight(paragraph.rows.length);
+
+            paragraph.showLoading(false);
+
+            if (!res.hasMore)
+                delete paragraph.queryId;
+        };
+
         $scope.nextPage = (paragraph) => {
-            _showLoading(paragraph, true);
+            paragraph.showLoading(true);
 
             paragraph.queryArgs.pageSize = paragraph.pageSize;
 
-            agentMgr.queryNextPage(paragraph.resNodeId, paragraph.queryId, paragraph.pageSize)
-                .then((res) => {
-                    paragraph.page++;
-
-                    paragraph.total += paragraph.rows.length;
-
-                    paragraph.duration = res.duration;
-
-                    paragraph.rows = res.rows;
-
-                    if (paragraph.chart()) {
-                        if (paragraph.result === 'pie')
-                            _updatePieChartsWithData(paragraph, _pieChartDatum(paragraph));
-                        else
-                            _updateChartsWithData(paragraph, _chartDatum(paragraph));
-                    }
-
-                    paragraph.gridOptions.adjustHeight(paragraph.rows.length);
-
-                    _showLoading(paragraph, false);
-
-                    if (!res.hasMore)
-                        delete paragraph.queryId;
-                })
+            const nextPageTask = from(agentMgr.queryNextPage(paragraph.resNodeId, paragraph.queryId, paragraph.pageSize)
+                .then((res) => _processQueryNextPage(paragraph, res))
                 .catch((err) => {
                     paragraph.setError(err);
+                    paragraph.ace && paragraph.ace.focus();
+                }));
 
-                    _showLoading(paragraph, false);
-                })
-                .then(() => paragraph.ace && paragraph.ace.focus());
+            const pingQueryTask = timer(60000, 60000).pipe(
+                exhaustMap(() => agentMgr.queryPing(paragraph.resNodeId, paragraph.queryId)),
+                takeWhile(({queryPingSupported}) => queryPingSupported),
+                ignoreElements()
+            );
+
+            merge(nextPageTask, pingQueryTask).pipe(
+                take(1),
+                takeUntil(paragraph.cancelQuerySubject)
+            ).subscribe();
         };
 
         const _export = (fileName, columnDefs, meta, rows, toClipBoard = false) => {
@@ -1844,7 +1954,7 @@
         const exportFileName = (paragraph, all) => {
             const args = paragraph.queryArgs;
 
-            if (args.type === 'SCAN')
+            if (paragraph.qryType === 'scan')
                 return `export-scan-${args.cacheName}-${paragraph.name}${all ? '-all' : ''}.csv`;
 
             return `export-query-${paragraph.name}${all ? '-all' : ''}.csv`;
@@ -1865,39 +1975,26 @@
         };
 
         $scope.exportCsvAll = (paragraph) => {
-            paragraph.csvIsPreparing = true;
-
             const args = paragraph.queryArgs;
 
-            return Promise.resolve(args.localNid || _chooseNode(args.cacheName, false))
-                .then((nid) => args.type === 'SCAN'
-                    ? agentMgr.queryScanGetAll({
-                        nid,
-                        cacheName: args.cacheName,
-                        filter: args.query,
-                        regEx: !!args.regEx,
-                        caseSensitive: !!args.caseSensitive,
-                        near: !!args.near,
-                        local: !!args.localNid
-                    })
-                    : agentMgr.querySqlGetAll({
-                        nid,
-                        cacheName: args.cacheName,
-                        query: args.query,
-                        nonCollocatedJoins: !!args.nonCollocatedJoins,
-                        enforceJoinOrder: !!args.enforceJoinOrder,
-                        replicatedOnly: false,
-                        local: !!args.localNid,
-                        lazy: !!args.lazy,
-                        collocated: !!args.collocated
-                    }))
-                .then((res) => _export(exportFileName(paragraph, true), paragraph.gridOptions.columnDefs, res.columns, res.rows))
-                .catch(Messages.showError)
-                .then(() => {
-                    paragraph.csvIsPreparing = false;
+            paragraph.cancelExportSubject.next(true);
 
-                    return paragraph.ace && paragraph.ace.focus();
-                });
+            paragraph.csvIsPreparing = true;
+
+            return (args.localNid ? of(args.localNid) : from(_chooseNode(args.cacheName, false))).pipe(
+                map((nid) => _.assign({}, args, {nid, pageSize: 1024, local: !!args.localNid, replicatedOnly: false})),
+                switchMap((arg) => _exportQueryAll(
+                    paragraph,
+                    arg,
+                    (res) => _initExportResult(paragraph, res),
+                    (res) => _export(exportFileName(paragraph, true), paragraph.gridOptions.columnDefs, res.columns, res.rows),
+                    (err) => {
+                        Messages.showError(err);
+                        return of(err);
+                    }
+                )),
+                finalize(() => paragraph.csvIsPreparing = false)
+            ).toPromise();
         };
 
         // $scope.exportPdfAll = function(paragraph) {
@@ -1924,6 +2021,8 @@
         };
 
         $scope.startRefresh = function(paragraph, value, unit) {
+            $scope.stopRefresh(paragraph);
+
             paragraph.rate.value = value;
             paragraph.rate.unit = unit;
             paragraph.rate.installed = true;
@@ -1933,7 +2032,7 @@
         };
 
         $scope.stopRefresh = function(paragraph) {
-            paragraph.rate.installed = false;
+            _.set(paragraph, 'rate.installed', false);
 
             _tryStopRefresh(paragraph);
         };
@@ -2022,7 +2121,7 @@
             if (!_.isNil(paragraph)) {
                 const scope = $scope.$new();
 
-                if (paragraph.queryArgs.type === 'SCAN') {
+                if (paragraph.qryType === 'scan') {
                     scope.title = 'SCAN query';
 
                     const filter = paragraph.queryArgs.filter;
@@ -2032,7 +2131,7 @@
                     else
                         scope.content = [`SCAN query for cache: <b>${maskCacheName(paragraph.queryArgs.cacheName, true)}</b> with filter: <b>${filter}</b>`];
                 }
-                else if (paragraph.queryArgs.query .startsWith('EXPLAIN ')) {
+                else if (paragraph.queryArgs.query.startsWith('EXPLAIN ')) {
                     scope.title = 'Explain query';
                     scope.content = paragraph.queryArgs.query.split(/\r?\n/);
                 }
@@ -2076,21 +2175,77 @@
             }
         };
 
-        $window.addEventListener('beforeunload', () => {
-            this._closeOpenedQueries(this.$scope.notebook.paragraphs);
+        this.offTransitions = $transitions.onBefore({from: 'base.sql.notebook'}, ($transition$) => {
+            const options = $transition$.options();
+
+            // Skip query closing in case of auto redirection on state change.
+            if (options.redirectedFrom)
+                return true;
+
+            return this.closeOpenedQueries();
         });
+
+        $window.addEventListener('beforeunload', this.closeOpenedQueries);
+
+        this.onClusterSwitchLnr = () => {
+            const paragraphs = _.get(this, '$scope.notebook.paragraphs');
+
+            if (this._hasRunningQueries(paragraphs)) {
+                try {
+                    return Confirm.confirm('You have running queries. Are you sure you want to cancel them?')
+                        .then(() => this._closeOpenedQueries(paragraphs));
+                }
+                catch (err) {
+                    return Promise.reject(new CancellationError());
+                }
+            }
+
+            return Promise.resolve(true);
+        };
+
+        agentMgr.addClusterSwitchListener(this.onClusterSwitchLnr);
     }
 
     _closeOpenedQueries(paragraphs) {
-        _.forEach(paragraphs, ({queryId, subscription, resNodeId}) => {
-            if (subscription)
-                subscription.unsubscribe();
+        return Promise.all(_.map(paragraphs, (paragraph) => {
+            paragraph.cancelQuerySubject.next(true);
+            paragraph.cancelExportSubject.next(true);
 
-            if (queryId) {
-                this.agentMgr.queryClose(resNodeId, queryId)
-                    .catch(() => { /* No-op. */ });
+            return Promise.all([paragraph.queryId
+                ? this.agentMgr.queryClose(paragraph.resNodeId, paragraph.queryId)
+                    .catch(() => Promise.resolve(true))
+                    .finally(() => delete paragraph.queryId)
+                : Promise.resolve(true),
+            paragraph.csvIsPreparing && paragraph.exportId
+                ? this.agentMgr.queryClose(paragraph.exportNodeId, paragraph.exportId)
+                    .catch(() => Promise.resolve(true))
+                    .finally(() => delete paragraph.exportId)
+                : Promise.resolve(true)]
+            );
+        }));
+    }
+
+    _hasRunningQueries(paragraphs) {
+        return !!_.find(paragraphs,
+            (paragraph) => paragraph.loading || paragraph.scanningInProgress || paragraph.csvIsPreparing);
+    }
+
+    async closeOpenedQueries() {
+        const paragraphs = _.get(this, '$scope.notebook.paragraphs');
+
+        if (this._hasRunningQueries(paragraphs)) {
+            try {
+                await this.Confirm.confirm('You have running queries. Are you sure you want to cancel them?');
+                this._closeOpenedQueries(paragraphs);
+
+                return true;
             }
-        });
+            catch (ignored) {
+                return false;
+            }
+        }
+
+        return true;
     }
 
     scanActions: QueryActions<Paragraph & {type: 'scan'}> = [
@@ -2148,9 +2303,13 @@
 
     async removeParagraph(paragraph: Paragraph) {
         try {
-            await this.Confirm.confirm('Are you sure you want to remove query: "' + paragraph.name + '"?');
-            this.$scope.stopRefresh(paragraph);
+            const msg = (this._hasRunningQueries([paragraph])
+                ? 'Query is being executed. Are you sure you want to cancel and remove query: "'
+                : 'Are you sure you want to remove query: "') + paragraph.name + '"?';
 
+            await this.Confirm.confirm(msg);
+
+            this.$scope.stopRefresh(paragraph);
             this._closeOpenedQueries([paragraph]);
 
             const paragraph_idx = _.findIndex(this.$scope.notebook.paragraphs, (item) => paragraph === item);
@@ -2162,6 +2321,9 @@
             this.$scope.notebook.paragraphs.splice(paragraph_idx, 1);
             this.$scope.rebuildScrollParagraphs();
 
+            paragraph.cancelQuerySubject.complete();
+            paragraph.cancelExportSubject.complete();
+
             await this.Notebook.save(this.$scope.notebook)
                 .catch(this.Messages.showError);
         }
@@ -2184,9 +2346,13 @@
     }
 
     $onDestroy() {
-        this._closeOpenedQueries(this.$scope.notebook.paragraphs);
-
         if (this.subscribers$)
             this.subscribers$.unsubscribe();
+
+        if (this.offTransitions)
+            this.offTransitions();
+
+        this.agentMgr.removeClusterSwitchListener(this.onClusterSwitchLnr);
+        this.$window.removeEventListener('beforeunload', this.closeOpenedQueries);
     }
 }
diff --git a/modules/web-console/frontend/app/components/page-queries/components/queries-notebook/template.tpl.pug b/modules/web-console/frontend/app/components/page-queries/components/queries-notebook/template.tpl.pug
index 5342333..dead633 100644
--- a/modules/web-console/frontend/app/components/page-queries/components/queries-notebook/template.tpl.pug
+++ b/modules/web-console/frontend/app/components/page-queries/components/queries-notebook/template.tpl.pug
@@ -182,7 +182,7 @@
     button.btn-ignite.btn-ignite--secondary(ng-disabled='!queryAvailable(paragraph)' ng-click='explain(paragraph)' data-placement='bottom' bs-tooltip='' data-title='{{queryTooltip(paragraph, "explain query")}}')
         | Explain
 
-    button.btn-ignite.btn-ignite--secondary(ng-if='cancelQueryAvailable(paragraph)' ng-click='cancelQuery(paragraph)' data-placement='bottom' bs-tooltip='' data-title='{{"Cancel query execution"}}')
+    button.btn-ignite.btn-ignite--secondary(ng-if='paragraph.executionInProgress(false) || paragraph.executionInProgress(true)' ng-click='cancelQuery(paragraph)' data-placement='bottom' bs-tooltip='' data-title='{{"Cancel query execution"}}')
         | Cancel
 
 mixin table-result-heading-query
@@ -338,7 +338,7 @@
                     span.icon-left.fa.fa-fw.fa-refresh.fa-spin(ng-show='paragraph.checkScanInProgress(true)')
                     | Scan on selected node
 
-                button.btn-ignite.btn-ignite--secondary(ng-if='cancelQueryAvailable(paragraph)' ng-click='cancelQuery(paragraph)' data-placement='bottom' bs-tooltip='' data-title='{{"Cancel query execution"}}')
+                button.btn-ignite.btn-ignite--secondary(ng-if='paragraph.checkScanInProgress(false) || paragraph.checkScanInProgress(true)' ng-click='cancelQuery(paragraph)' data-placement='bottom' bs-tooltip='' data-title='{{"Cancel query execution"}}')
                     | Cancel
             div
 
@@ -354,7 +354,7 @@
                     span(ng-if='paragraph.queryArgs.filter') &nbsp; with filter: #[b {{ paragraph.queryArgs.filter }}]
                     span(ng-if='paragraph.queryArgs.localNid') &nbsp; on node: #[b {{ paragraph.queryArgs.localNid | limitTo:8 }}]
 
-                -var nextVisibleCondition = 'paragraph.resultType() != "error" && paragraph.queryId && paragraph.nonRefresh() && (paragraph.table() || paragraph.chart() && !paragraph.scanExplain())'
+                -var nextVisibleCondition = 'paragraph.resultType() != "error" && !paragraph.loading && paragraph.queryId && paragraph.nonRefresh() && (paragraph.table() || paragraph.chart() && !paragraph.scanExplain())'
 
                 .pull-right(ng-show=`${nextVisibleCondition}` ng-class='{disabled: paragraph.loading}' ng-click='!paragraph.loading && nextPage(paragraph)')
                     i.fa.fa-chevron-circle-right
@@ -422,7 +422,7 @@
             .footer.clearfix(ng-show='paragraph.resultType() !== "error"')
                 a.pull-left(ng-click='showResultQuery(paragraph)') Show query
 
-                -var nextVisibleCondition = 'paragraph.resultType() !== "error" && paragraph.queryId && paragraph.nonRefresh() && (paragraph.table() || paragraph.chart() && !paragraph.scanExplain())'
+                -var nextVisibleCondition = 'paragraph.resultType() !== "error" && !paragraph.loading && paragraph.queryId && paragraph.nonRefresh() && (paragraph.table() || paragraph.chart() && !paragraph.scanExplain())'
 
                 .pull-right(ng-show=`${nextVisibleCondition}` ng-class='{disabled: paragraph.loading}' ng-click='!paragraph.loading && nextPage(paragraph)')
                     i.fa.fa-chevron-circle-right
diff --git a/modules/web-console/frontend/app/components/web-console-header/components/user-menu/style.scss b/modules/web-console/frontend/app/components/web-console-header/components/user-menu/style.scss
index 898047b..9d9e3e3 100644
--- a/modules/web-console/frontend/app/components/web-console-header/components/user-menu/style.scss
+++ b/modules/web-console/frontend/app/components/web-console-header/components/user-menu/style.scss
@@ -18,11 +18,26 @@
 user-menu {
     --active-link-color: #ee2b27;
     font-size: 14px;
+    max-width: 150px;
+    max-height: 100%;
+    display: flex;
 
     &>.active {
         color: var(--active-link-color)
     }
     .caret {
         margin-left: 8px;
+        margin-top: 3px;
+        align-self: center;
+    }
+    .user-menu__username {
+        text-overflow: ellipsis;
+        overflow: hidden;
+        white-space: nowrap;
+    }
+    .user-menu__trigger {
+        display: flex;
+        max-height: 100%;
+        overflow: hidden;
     }
 }
\ No newline at end of file
diff --git a/modules/web-console/frontend/app/components/web-console-header/components/user-menu/template.pug b/modules/web-console/frontend/app/components/web-console-header/components/user-menu/template.pug
index e946c78..4940e52 100644
--- a/modules/web-console/frontend/app/components/web-console-header/components/user-menu/template.pug
+++ b/modules/web-console/frontend/app/components/web-console-header/components/user-menu/template.pug
@@ -14,7 +14,7 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 
-div(
+div.user-menu__trigger(
     ng-class='{active: $ctrl.$state.includes("base.settings")}'
     ng-click='$event.stopPropagation()'
     bs-dropdown='$ctrl.items'
@@ -22,5 +22,5 @@
     data-trigger='hover focus'
     data-container='self'
 )
-    span {{$ctrl.user.firstName}} {{$ctrl.user.lastName}}
+    span.user-menu__username {{$ctrl.user.firstName}} {{$ctrl.user.lastName}}
     span.caret
\ No newline at end of file
diff --git a/modules/web-console/frontend/app/configuration/components/page-configure-basic/controller.spec.js b/modules/web-console/frontend/app/configuration/components/page-configure-basic/controller.spec.js
deleted file mode 100644
index a4a1d30..0000000
--- a/modules/web-console/frontend/app/configuration/components/page-configure-basic/controller.spec.js
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- * 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.
- */
-
-import {suite, test} from 'mocha';
-import {assert} from 'chai';
-import {spy} from 'sinon';
-
-import {TestScheduler} from 'rxjs/testing';
-import {Subscriber, Subject, BehaviorSubject} from 'rxjs';
-import Controller from './controller';
-
-const mocks = () => new Map([
-    ['$scope', {
-        $applyAsync: spy((fn) => fn())
-    }],
-    ['pageService', {
-        setCluster: spy()
-    }],
-    ['Clusters', {
-        discoveries: 1,
-        minMemoryPolicySize: 1000
-    }],
-    ['ConfigureState', {
-        state$: new Subject()
-    }],
-    ['ConfigurationDownload', {
-        downloadClusterConfiguration: spy()
-    }],
-    ['IgniteVersion', {
-        currentSbj: new BehaviorSubject({ignite: '1.9.0'}),
-        since: (a, b) => a === b
-    }],
-    ['state$', {
-        params: {
-            clusterID: null
-        }
-    }]
-]);
-
-suite.skip('page-configure-basic component controller', () => {
-    test('$onInit method', () => {
-        const c = new Controller(...mocks().values());
-        c.getObservable = spy(c.getObservable.bind(c));
-        c.$onInit();
-        assert.deepEqual(
-            c.getObservable.lastCall.args,
-            [c.ConfigureState.state$, c.Version.currentSbj],
-            'calls getObservable with correct arguments'
-        );
-        assert.instanceOf(c.subscription, Subscriber, 'stores subscription for later');
-        assert.equal(c.discoveries, 1, 'exposes discoveries');
-        assert.equal(c.minMemorySize, 1000, 'exposes minMemorySize');
-        assert.deepEqual(
-            c.sizesMenu,
-            [
-                {label: 'Kb', value: 1024},
-                {label: 'Mb', value: 1024 * 1024},
-                {label: 'Gb', value: 1024 * 1024 * 1024}
-            ],
-            'exposes sizesMenu'
-        );
-        assert.equal(c.memorySizeScale, c.sizesMenu[2], 'sets default memorySizeScale to Gb');
-        assert.deepEqual(
-            c.pageService.setCluster.lastCall.args, ['-1'],
-            'sets cluster to -1 by clusterID state param is missing'
-        );
-    });
-
-    test('$onDestroy method', () => {
-        const c = new Controller(...mocks().values());
-        c.$onInit();
-        c.subscription.unsubscribe = spy(c.subscription.unsubscribe);
-        c.$onDestroy();
-        assert(c.subscription.unsubscribe.calledOnce, 'unsubscribes from Observable');
-    });
-
-    test('getObservable method', () => {
-        const testScheduler = new TestScheduler((...args) => assert.deepEqual(...args));
-        const c = new Controller(...mocks().values());
-
-        c.applyValue = spy(c.applyValue.bind(c));
-
-        const version  = 'a-b-';
-        const state    = '-a-b';
-        const expected = '-abc';
-
-        const version$ = testScheduler.createHotObservable(version, {
-            a: {ignite: '1.9.0'},
-            b: {ignite: '2.0.0'}
-        });
-
-        const state$ = testScheduler.createHotObservable(state, {
-            a: {
-                list: {
-                    clusters: new Map(),
-                    caches: new Map()
-                },
-                configureBasic: {
-                    newClusterCaches: [],
-                    oldClusterCaches: [],
-                    cluster: null
-                }
-            },
-            b: {
-                list: {
-                    clusters: new Map([
-                        [1, {_id: 1, name: '1', caches: [1, 2]}],
-                        [2, {_id: 2, name: '2'}]
-                    ]),
-                    caches: new Map([
-                        [1, {_id: 1, name: '1'}],
-                        [2, {_id: 2, name: '2'}]
-                    ])
-                },
-                configureBasic: {
-                    newClusterCaches: [],
-                    oldClusterCaches: [
-                        {_id: 1, name: '1'},
-                        {_id: 2, name: '2'}
-                    ],
-                    cluster: {_id: 1, name: '1', caches: [1, 2]}
-                }
-            }
-        });
-
-
-        const expectedValues = {
-            a: {
-                clusters: new Map(),
-                caches: new Map(),
-                state: {
-                    newClusterCaches: [],
-                    oldClusterCaches: [],
-                    cluster: null
-                },
-                allClusterCaches: [],
-                cachesMenu: [],
-                defaultMemoryPolicy: void 0,
-                memorySizeInputVisible: false
-            },
-            b: {
-                clusters: new Map(),
-                caches: new Map(),
-                state: {
-                    newClusterCaches: [],
-                    oldClusterCaches: [],
-                    cluster: null
-                },
-                allClusterCaches: [],
-                cachesMenu: [],
-                defaultMemoryPolicy: void 0,
-                memorySizeInputVisible: true
-            },
-            c: {
-                clusters: new Map([
-                    [1, {_id: 1, name: '1', caches: [1, 2]}],
-                    [2, {_id: 2, name: '2'}]
-                ]),
-                caches: new Map([
-                    [1, {_id: 1, name: '1'}],
-                    [2, {_id: 2, name: '2'}]
-                ]),
-                state: {
-                    newClusterCaches: [],
-                    oldClusterCaches: [
-                        {_id: 1, name: '1'},
-                        {_id: 2, name: '2'}
-                    ],
-                    cluster: {_id: 1, name: '1', caches: [1, 2]}
-                },
-                allClusterCaches: [
-                    {_id: 1, name: '1'},
-                    {_id: 2, name: '2'}
-                ],
-                cachesMenu: [
-                    {_id: 1, name: '1'},
-                    {_id: 2, name: '2'}
-                ],
-                defaultMemoryPolicy: void 0,
-                memorySizeInputVisible: true
-            }
-        };
-
-        testScheduler.expectObservable(c.getObservable(state$, version$)).toBe(expected, expectedValues);
-        testScheduler.flush();
-
-        assert.deepEqual(c.applyValue.getCall(0).args[0], expectedValues.a, 'applies value a');
-        assert.deepEqual(c.applyValue.getCall(1).args[0], expectedValues.b, 'applies value b');
-        assert.deepEqual(c.applyValue.getCall(2).args[0], expectedValues.c, 'applies value c');
-        assert.equal(c.applyValue.callCount, 3, 'applyValue was called correct amount of times');
-    });
-});
diff --git a/modules/web-console/frontend/app/configuration/components/page-configure-basic/reducer.spec.js b/modules/web-console/frontend/app/configuration/components/page-configure-basic/reducer.spec.js
index 56c9eb8..3489bf8 100644
--- a/modules/web-console/frontend/app/configuration/components/page-configure-basic/reducer.spec.js
+++ b/modules/web-console/frontend/app/configuration/components/page-configure-basic/reducer.spec.js
@@ -26,7 +26,7 @@
     reducer
 } from './reducer';
 
-suite.skip('page-configure-basic component reducer', () => {
+suite('page-configure-basic component reducer', () => {
     test('Default state', () => {
         assert.deepEqual(reducer(void 0, {}), {
             clusterID: -1,
@@ -35,6 +35,7 @@
             oldClusterCaches: []
         });
     });
+
     test('SET_CLUSTER action', () => {
         const root = {
             list: {
@@ -43,6 +44,7 @@
                 spaces: new Map([[0, {}]])
             }
         };
+
         const defaultCluster = {
             _id: null,
             discovery: {
@@ -62,6 +64,7 @@
             },
             caches: []
         };
+
         assert.deepEqual(
             reducer(void 0, {type: SET_CLUSTER, _id: -1, cluster: defaultCluster}, root),
             {
@@ -76,6 +79,7 @@
             },
             'inits new cluster if _id is fake'
         );
+
         assert.deepEqual(
             reducer(void 0, {type: SET_CLUSTER, _id: 1}, root),
             {
@@ -87,6 +91,7 @@
             'inits new cluster if _id is real'
         );
     });
+
     test('ADD_NEW_CACHE action', () => {
         const state = {
             clusterID: -1,
@@ -94,12 +99,14 @@
             newClusterCaches: [{name: 'New cache (1)'}],
             oldClusterCaches: []
         };
+
         const root = {
             list: {
                 caches: new Map([[1, {name: 'New cache'}]]),
                 spaces: new Map([[1, {}]])
             }
         };
+
         const defaultCache = {
             _id: null,
             space: null,
@@ -113,6 +120,7 @@
             cacheStoreFactory: {CacheJdbcBlobStoreFactory: {connectVia: 'DataSource'}},
             memoryPolicyName: 'default'
         };
+
         assert.deepEqual(
             reducer(state, {type: ADD_NEW_CACHE, _id: -1}, root),
             {
@@ -131,16 +139,19 @@
             'adds new cache'
         );
     });
+
     test('REMOVE_CACHE action', () => {
         const state = {
             newClusterCaches: [{_id: -1}],
             oldClusterCaches: [{_id: 1}]
         };
+
         assert.deepEqual(
             reducer(state, {type: REMOVE_CACHE, cache: {_id: null}}),
             state,
             'removes nothing if there\'s no matching cache'
         );
+
         assert.deepEqual(
             reducer(state, {type: REMOVE_CACHE, cache: {_id: -1}}),
             {
@@ -149,6 +160,7 @@
             },
             'removes new cluster cache'
         );
+
         assert.deepEqual(
             reducer(state, {type: REMOVE_CACHE, cache: {_id: 1}}),
             {
@@ -158,19 +170,23 @@
             'removes old cluster cache'
         );
     });
+
     test('SET_SELECTED_CACHES action', () => {
         const state = {
             cluster: {caches: []},
             oldClusterCaches: []
         };
+
         const root = {
             list: {caches: new Map([[1, {_id: 1}], [2, {_id: 2}], [3, {_id: 3}]])}
         };
+
         assert.deepEqual(
             reducer(state, {type: SET_SELECTED_CACHES, cacheIDs: []}, root),
             state,
             'select no caches if action.cacheIDs is empty'
         );
+
         assert.deepEqual(
             reducer(state, {type: SET_SELECTED_CACHES, cacheIDs: [1]}, root),
             {
@@ -179,6 +195,7 @@
             },
             'selects existing cache'
         );
+
         assert.deepEqual(
             reducer(state, {type: SET_SELECTED_CACHES, cacheIDs: [1, 2, 3]}, root),
             {
diff --git a/modules/web-console/frontend/app/configuration/components/page-configure-basic/reducer.ts b/modules/web-console/frontend/app/configuration/components/page-configure-basic/reducer.ts
index cc5d42c..1bc7a26 100644
--- a/modules/web-console/frontend/app/configuration/components/page-configure-basic/reducer.ts
+++ b/modules/web-console/frontend/app/configuration/components/page-configure-basic/reducer.ts
@@ -47,21 +47,22 @@
                 : Object.assign({}, action.cluster, {
                     _id: -1,
                     space: defaultSpace(root),
-                    name: uniqueName('Cluster', [...root.list.clusters.values()])
+                    name: uniqueName('New cluster', [...root.list.clusters.values()], ({name, i}) => `${name} (${i})`)
                 });
-            const value = Object.assign({}, state, {
+
+            return Object.assign({}, state, {
                 clusterID: cluster._id,
                 cluster,
                 newClusterCaches: [],
                 oldClusterCaches: existingCaches(root.list.caches, cluster)
             });
-            return value;
         }
+
         case ADD_NEW_CACHE: {
             const cache = {
                 _id: action._id,
                 space: defaultSpace(root),
-                name: uniqueName('Cache', [...root.list.caches.values(), ...state.newClusterCaches]),
+                name: uniqueName('New cache', [...root.list.caches.values(), ...state.newClusterCaches], ({name, i}) => `${name} (${i})`),
                 cacheMode: 'PARTITIONED',
                 atomicityMode: 'ATOMIC',
                 readFromBackup: true,
@@ -71,14 +72,16 @@
                 cacheStoreFactory: {CacheJdbcBlobStoreFactory: {connectVia: 'DataSource'}},
                 memoryPolicyName: 'default'
             };
-            const value = Object.assign({}, state, {
+
+            return Object.assign({}, state, {
                 newClusterCaches: [...state.newClusterCaches, cache]
             });
-            return value;
         }
+
         case REMOVE_CACHE: {
             const cache = action.cache;
-            const value = Object.assign({}, state, {
+
+            return Object.assign({}, state, {
                 newClusterCaches: isNewItem(cache)
                     ? state.newClusterCaches.filter((c) => c._id !== cache._id)
                     : state.newClusterCaches,
@@ -86,17 +89,20 @@
                     ? state.oldClusterCaches
                     : state.oldClusterCaches.filter((c) => c._id !== cache._id)
             });
-            return value;
         }
+
         case SET_SELECTED_CACHES: {
             const value = Object.assign({}, state, {
                 cluster: Object.assign({}, state.cluster, {
                     caches: [...action.cacheIDs.filter((id) => id)]
                 })
             });
+
             value.oldClusterCaches = existingCaches(root.list.caches, value.cluster);
+
             return value;
         }
+
         default:
             return state;
     }
diff --git a/modules/web-console/frontend/app/configuration/generator/generator/JavaTransformer.spec.js b/modules/web-console/frontend/app/configuration/generator/generator/JavaTransformer.spec.js
deleted file mode 100644
index aa75f8d..0000000
--- a/modules/web-console/frontend/app/configuration/generator/generator/JavaTransformer.spec.js
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * 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.
- */
-
-import JavaTypes from 'app/services/JavaTypes.service';
-
-import generator from './ConfigurationGenerator';
-import transformer from './JavaTransformer.service';
-
-suite.skip('JavaTransformerTestsSuite', () => {
-    test('AtomicConfiguration', () => {
-        const ConfigurationGenerator = generator[1]();
-        const JavaTransformer = transformer[1][2](JavaTypes[1](), ConfigurationGenerator);
-
-        const acfg = {
-            atomicSequenceReserveSize: 1001,
-            backups: 1,
-            cacheMode: 'LOCAL'
-        };
-
-        const bean = ConfigurationGenerator.clusterAtomics(acfg);
-
-        console.log(JavaTransformer.generateSection(bean));
-    });
-
-    test('IgniteConfiguration', () => {
-        const ConfigurationGenerator = generator[1]();
-        const JavaTransformer = transformer[1][2](JavaTypes[1](), ConfigurationGenerator);
-
-        const clusterCfg = {
-            atomics: {
-                atomicSequenceReserveSize: 1001,
-                backups: 1,
-                cacheMode: 'LOCAL'
-            }
-        };
-
-        const bean = ConfigurationGenerator.igniteConfiguration(clusterCfg);
-
-        console.log(JavaTransformer.toClassFile(bean, 'config', 'ServerConfigurationFactory', null));
-    });
-});
diff --git a/modules/web-console/frontend/app/configuration/generator/generator/SharpTransformer.spec.js b/modules/web-console/frontend/app/configuration/generator/generator/SharpTransformer.spec.js
deleted file mode 100644
index 57725d4..0000000
--- a/modules/web-console/frontend/app/configuration/generator/generator/SharpTransformer.spec.js
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * 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.
- */
-
-import generator from './PlatformGenerator';
-import transformer from './SharpTransformer.service';
-
-suite.skip('SharpTransformerTestsSuite', () => {
-    test('AtomicConfiguration', () => {
-        const PlatformGenerator = generator[1]();
-        const SharpTransformer = transformer[1](PlatformGenerator);
-
-        const acfg = {
-            atomicSequenceReserveSize: 1001,
-            backups: 1,
-            cacheMode: 'LOCAL'
-        };
-
-        const bean = PlatformGenerator.clusterAtomics(acfg);
-
-        console.log(SharpTransformer.generateSection(bean));
-    });
-
-    test('IgniteConfiguration', () => {
-        const PlatformGenerator = generator[1]();
-        const SharpTransformer = transformer[1](PlatformGenerator);
-
-        const clusterCfg = {
-            atomics: {
-                atomicSequenceReserveSize: 1001,
-                backups: 1,
-                cacheMode: 'LOCAL'
-            }
-        };
-
-        const bean = PlatformGenerator.igniteConfiguration(clusterCfg);
-
-        console.log(SharpTransformer.toClassFile(bean, 'config', 'ServerConfigurationFactory', null));
-    });
-});
diff --git a/modules/web-console/frontend/app/configuration/generator/generator/SpringTransformer.spec.js b/modules/web-console/frontend/app/configuration/generator/generator/SpringTransformer.spec.js
deleted file mode 100644
index 2a08219..0000000
--- a/modules/web-console/frontend/app/configuration/generator/generator/SpringTransformer.spec.js
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * 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.
- */
-
-import JavaTypes from 'app/services/JavaTypes.service';
-import generator from './ConfigurationGenerator';
-import transformer from './SpringTransformer.service';
-
-suite.skip('SpringTransformerTestsSuite', () => {
-    test('AtomicConfiguration', () => {
-        const ConfigurationGenerator = generator[1]();
-        const SpringTransformer = transformer[1][2](JavaTypes[1](), ConfigurationGenerator);
-
-        const acfg = {
-            atomicSequenceReserveSize: 1001,
-            backups: 1,
-            cacheMode: 'LOCAL'
-        };
-
-        const bean = ConfigurationGenerator.clusterAtomics(acfg);
-
-        console.log(SpringTransformer.generateSection(bean));
-    });
-
-    test('IgniteConfiguration', () => {
-        const ConfigurationGenerator = generator[1]();
-        const SpringTransformer = transformer[1][2](JavaTypes[1](), ConfigurationGenerator);
-
-        const cfg = {
-            atomics: {
-                atomicSequenceReserveSize: 1001,
-                backups: 1,
-                cacheMode: 'LOCAL'
-            }
-        };
-
-        const bean = ConfigurationGenerator.igniteConfiguration(cfg);
-
-        console.log(SpringTransformer.generate(bean));
-    });
-});
diff --git a/modules/web-console/frontend/app/configuration/services/ConfigurationDownload.spec.js b/modules/web-console/frontend/app/configuration/services/ConfigurationDownload.spec.js
index 581993d..9c949d6 100644
--- a/modules/web-console/frontend/app/configuration/services/ConfigurationDownload.spec.js
+++ b/modules/web-console/frontend/app/configuration/services/ConfigurationDownload.spec.js
@@ -46,6 +46,12 @@
     ['$q', Promise],
     ['$rootScope', {
         IgniteDemoMode: true
+    }],
+    ['PageConfigure', {
+        getClusterConfiguration: () => Promise.resolve({clusters: [{_id: 1, name: 'An Cluster'}]})
+    }],
+    ['IgniteConfigurationResource', {
+        populate: () => Promise.resolve({clusters: []})
     }]
 ]);
 
@@ -53,20 +59,7 @@
     saveAs: spy()
 });
 
-suite.skip('page-configure, ConfigurationDownload service', () => {
-    test('fails and shows error message when cluster not found', () => {
-        const service = new Provider(...mocks().values());
-
-        return service.downloadClusterConfiguration({_id: 1, name: 'An Cluster'})
-        .then(() => Promise.reject('Should not happen'))
-        .catch(() => {
-            assert.equal(
-                service.messages.showError.getCall(0).args[0],
-                'Failed to generate project files. Cluster An Cluster not found',
-                'shows correct error message when cluster was not found'
-            );
-        });
-    });
+suite('page-configure, ConfigurationDownload service', () => {
     test('fails and shows error message when summary zipper fails', () => {
         const service = new Provider(...mocks().values());
         const cluster = {_id: 1, name: 'An Cluster'};
@@ -83,6 +76,7 @@
             );
         });
     });
+
     test('calls correct dependcies', () => {
         const service = new Provider(...mocks().values());
         service.saver = saverMock();
diff --git a/modules/web-console/frontend/app/configuration/services/PageConfigure.spec.js b/modules/web-console/frontend/app/configuration/services/PageConfigure.spec.js
deleted file mode 100644
index dc18b69..0000000
--- a/modules/web-console/frontend/app/configuration/services/PageConfigure.spec.js
+++ /dev/null
@@ -1,240 +0,0 @@
-/*
- * 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.
- */
-
-import {assert} from 'chai';
-import {spy} from 'sinon';
-import {of, throwError} from 'rxjs';
-import {TestScheduler} from 'rxjs/testing';
-
-const mocks = () => new Map([
-    ['IgniteConfigurationResource', {}],
-    ['$state', {}],
-    ['ConfigureState', {}],
-    ['Clusters', {}]
-]);
-
-import {REMOVE_CLUSTERS_LOCAL_REMOTE, CLONE_CLUSTERS} from './PageConfigure';
-import PageConfigure from './PageConfigure';
-import {REMOVE_CLUSTERS, LOAD_LIST, ADD_CLUSTERS, UPDATE_CLUSTER} from '../store/reducer';
-
-suite.skip('PageConfigure service', () => {
-    suite('cloneCluster$ effect', () => {
-        test('successfull clusters clone', () => {
-            const testScheduler = new TestScheduler((...args) => assert.deepEqual(...args));
-            const values = {
-                s: {
-                    list: {
-                        clusters: new Map([
-                            [1, {_id: 1, name: 'Cluster 1'}],
-                            [2, {_id: 2, name: 'Cluster 1 (clone)'}]
-                        ])
-                    }
-                },
-                a: {
-                    type: CLONE_CLUSTERS,
-                    clusters: [
-                        {_id: 1, name: 'Cluster 1'},
-                        {_id: 2, name: 'Cluster 1 (clone)'}
-                    ]
-                },
-                b: {
-                    type: ADD_CLUSTERS,
-                    clusters: [
-                        {_id: -1, name: 'Cluster 1 (clone) (1)'},
-                        {_id: -2, name: 'Cluster 1 (clone) (clone)'}
-                    ]
-                },
-                c: {
-                    type: UPDATE_CLUSTER,
-                    _id: -1,
-                    cluster: {_id: 99}
-                },
-                d: {
-                    type: UPDATE_CLUSTER,
-                    _id: -2,
-                    cluster: {_id: 99}
-                }
-            };
-            const actions = '-a----';
-            const state   = 's-----';
-            const output  = '-(bcd)';
-
-            const deps = mocks()
-            .set('Clusters', {
-                saveCluster$: (c) => of({data: 99})
-            })
-            .set('ConfigureState', {
-                actions$: testScheduler.createHotObservable(actions, values),
-                state$: testScheduler.createHotObservable(state, values),
-                dispatchAction: spy()
-            });
-
-            const s = new PageConfigure(...deps.values());
-
-            testScheduler.expectObservable(s.cloneClusters$).toBe(output, values);
-            testScheduler.flush();
-            assert.equal(s.ConfigureState.dispatchAction.callCount, 3);
-        });
-        test('some clusters clone failure', () => {
-            const testScheduler = new TestScheduler((...args) => assert.deepEqual(...args));
-            const values = {
-                s: {
-                    list: {
-                        clusters: new Map([
-                            [1, {_id: 1, name: 'Cluster 1'}],
-                            [2, {_id: 2, name: 'Cluster 1 (clone)'}]
-                        ])
-                    }
-                },
-                a: {
-                    type: CLONE_CLUSTERS,
-                    clusters: [
-                        {_id: 1, name: 'Cluster 1'},
-                        {_id: 2, name: 'Cluster 1 (clone)'}
-                    ]
-                },
-                b: {
-                    type: ADD_CLUSTERS,
-                    clusters: [
-                        {_id: -1, name: 'Cluster 1 (clone) (1)'},
-                        {_id: -2, name: 'Cluster 1 (clone) (clone)'}
-                    ]
-                },
-                c: {
-                    type: UPDATE_CLUSTER,
-                    _id: -1,
-                    cluster: {_id: 99}
-                },
-                d: {
-                    type: REMOVE_CLUSTERS,
-                    clusterIDs: [-2]
-                }
-            };
-            const actions = '-a----';
-            const state   = 's-----';
-            const output  = '-(bcd)';
-
-            const deps = mocks()
-            .set('Clusters', {
-                saveCluster$: (c) => c.name === values.b.clusters[0].name
-                    ? of({data: 99})
-                    : throwError()
-            })
-            .set('ConfigureState', {
-                actions$: testScheduler.createHotObservable(actions, values),
-                state$: testScheduler.createHotObservable(state, values),
-                dispatchAction: spy()
-            });
-
-            const s = new PageConfigure(...deps.values());
-
-            testScheduler.expectObservable(s.cloneClusters$).toBe(output, values);
-            testScheduler.flush();
-            assert.equal(s.ConfigureState.dispatchAction.callCount, 3);
-        });
-    });
-    suite('removeCluster$ effect', () => {
-        test('successfull clusters removal', () => {
-            const testScheduler = new TestScheduler((...args) => assert.deepEqual(...args));
-
-            const values = {
-                a: {
-                    type: REMOVE_CLUSTERS_LOCAL_REMOTE,
-                    clusters: [1, 2, 3, 4, 5].map((i) => ({_id: i}))
-                },
-                b: {
-                    type: REMOVE_CLUSTERS,
-                    clusterIDs: [1, 2, 3, 4, 5]
-                },
-                c: {
-                    type: LOAD_LIST,
-                    list: []
-                },
-                d: {
-                    type: REMOVE_CLUSTERS,
-                    clusterIDs: [1, 2, 3, 4, 5]
-                },
-                s: {
-                    list: []
-                }
-            };
-
-            const actions = '-a';
-            const state   = 's-';
-            const output  = '-d';
-
-            const deps = mocks()
-            .set('ConfigureState', {
-                actions$: testScheduler.createHotObservable(actions, values),
-                state$: testScheduler.createHotObservable(state, values),
-                dispatchAction: spy()
-            })
-            .set('Clusters', {
-                removeCluster$: (v) => of(v)
-            });
-            const s = new PageConfigure(...deps.values());
-
-            testScheduler.expectObservable(s.removeClusters$).toBe(output, values);
-            testScheduler.flush();
-            assert.equal(s.ConfigureState.dispatchAction.callCount, 1);
-        });
-        test('some clusters removal failure', () => {
-            const testScheduler = new TestScheduler((...args) => assert.deepEqual(...args));
-
-            const values = {
-                a: {
-                    type: REMOVE_CLUSTERS_LOCAL_REMOTE,
-                    clusters: [1, 2, 3, 4, 5].map((i) => ({_id: i}))
-                },
-                b: {
-                    type: REMOVE_CLUSTERS,
-                    clusterIDs: [1, 2, 3, 4, 5]
-                },
-                c: {
-                    type: LOAD_LIST,
-                    list: []
-                },
-                d: {
-                    type: REMOVE_CLUSTERS,
-                    clusterIDs: [1, 3, 5]
-                },
-                s: {
-                    list: []
-                }
-            };
-
-            const actions = '-a----';
-            const state   = 's-----';
-            const output  = '-(bcd)';
-
-            const deps = mocks()
-            .set('ConfigureState', {
-                actions$: testScheduler.createHotObservable(actions, values),
-                state$: testScheduler.createHotObservable(state, values),
-                dispatchAction: spy()
-            })
-            .set('Clusters', {
-                removeCluster$: (v) => v._id % 2 ? of(v) : throwError()
-            });
-            const s = new PageConfigure(...deps.values());
-
-            testScheduler.expectObservable(s.removeClusters$).toBe(output, values);
-            testScheduler.flush();
-            assert.equal(s.ConfigureState.dispatchAction.callCount, 3);
-        });
-    });
-});
diff --git a/modules/web-console/frontend/app/configuration/store/reducer.spec.js b/modules/web-console/frontend/app/configuration/store/reducer.spec.js
index fb47973..19bf663 100644
--- a/modules/web-console/frontend/app/configuration/store/reducer.spec.js
+++ b/modules/web-console/frontend/app/configuration/store/reducer.spec.js
@@ -20,7 +20,7 @@
 
 import {
     ADD_CLUSTER,
-    REMOVE_CLUSTER,
+    REMOVE_CLUSTERS,
     UPDATE_CLUSTER,
     UPSERT_CLUSTERS,
     ADD_CACHE,
@@ -30,7 +30,7 @@
     reducer
 } from './reducer';
 
-suite.skip('page-configure component reducer', () => {
+suite('page-configure component reducer', () => {
     test('Default state', () => {
         assert.deepEqual(
             reducer(void 0, {}),
@@ -41,6 +41,7 @@
             }
         );
     });
+
     test('ADD_CLUSTER action', () => {
         assert.deepEqual(
             reducer(
@@ -53,13 +54,18 @@
             'adds a cluster'
         );
     });
-    test('REMOVE_CLUSTER action', () => {
+
+    test('REMOVE_CLUSTERS action', () => {
         assert.deepEqual(
-            reducer({}, {type: REMOVE_CLUSTER}),
-            {},
-            'does nothing yet'
+            reducer(
+                {clusters: new Map([[1, {_id: 1, name: 'Cluster 1'}], [2, {_id: 2, name: 'Cluster 2'}]])},
+                {type: REMOVE_CLUSTERS, clusterIDs: [1]}
+            ),
+            {clusters: new Map([[2, {_id: 2, name: 'Cluster 2'}]])},
+            'deletes clusters by id'
         );
     });
+
     test('UPDATE_CLUSTER action', () => {
         assert.deepEqual(
             reducer(
@@ -70,6 +76,7 @@
             'updates a cluster'
         );
     });
+
     test('UPSERT_CLUSTERS', () => {
         assert.deepEqual(
             reducer(
@@ -85,6 +92,7 @@
             ])},
             'updates one cluster'
         );
+
         assert.deepEqual(
             reducer(
                 {clusters: new Map([
@@ -105,6 +113,7 @@
             ])},
             'updates two clusters'
         );
+
         assert.deepEqual(
             reducer(
                 {clusters: new Map()},
@@ -115,6 +124,7 @@
             ])},
             'adds one cluster'
         );
+
         assert.deepEqual(
             reducer(
                 {clusters: new Map([[1, {_id: 1}]])},
@@ -127,6 +137,7 @@
             ])},
             'adds two clusters'
         );
+
         assert.deepEqual(
             reducer(
                 {clusters: new Map([[1, {_id: 1}]])},
@@ -147,6 +158,7 @@
             'adds and updates several clusters'
         );
     });
+
     test('ADD_CACHE action', () => {
         assert.deepEqual(
             reducer(
@@ -159,6 +171,7 @@
             'adds a cache'
         );
     });
+
     test('REMOVE_CACHE action', () => {
         assert.deepEqual(
             reducer({}, {type: REMOVE_CACHE}),
@@ -166,6 +179,7 @@
             'does nothing yet'
         );
     });
+
     test('UPDATE_CACHE action', () => {
         assert.deepEqual(
             reducer(
@@ -176,6 +190,7 @@
             'updates a cache'
         );
     });
+
     test('UPSERT_CACHES', () => {
         assert.deepEqual(
             reducer(
@@ -191,6 +206,7 @@
             ])},
             'updates one cache'
         );
+
         assert.deepEqual(
             reducer(
                 {caches: new Map([
@@ -211,6 +227,7 @@
             ])},
             'updates two caches'
         );
+
         assert.deepEqual(
             reducer(
                 {caches: new Map()},
@@ -221,6 +238,7 @@
             ])},
             'adds one cache'
         );
+
         assert.deepEqual(
             reducer(
                 {caches: new Map([[1, {_id: 1}]])},
@@ -233,6 +251,7 @@
             ])},
             'adds two caches'
         );
+
         assert.deepEqual(
             reducer(
                 {caches: new Map([[1, {_id: 1}]])},
diff --git a/modules/web-console/frontend/app/modules/agent/AgentManager.service.js b/modules/web-console/frontend/app/modules/agent/AgentManager.service.js
index 0c698c1..1156844 100644
--- a/modules/web-console/frontend/app/modules/agent/AgentManager.service.js
+++ b/modules/web-console/frontend/app/modules/agent/AgentManager.service.js
@@ -44,6 +44,17 @@
 const LAZY_QUERY_SINCE = [['2.1.4-p1', '2.2.0'], '2.2.1'];
 const COLLOCATED_QUERY_SINCE = [['2.3.5', '2.4.0'], ['2.4.6', '2.5.0'], ['2.5.1-p13', '2.6.0'], '2.7.0'];
 const COLLECT_BY_CACHE_GROUPS_SINCE = '2.7.0';
+const QUERY_PING_SINCE = [['2.5.6', '2.6.0'], '2.7.4'];
+
+/**
+ * Query execution result.
+ * @typedef {{responseNodeId: String, queryId: String, columns: String[], rows: {Object[][]}, hasMore: Boolean, duration: Number}} VisorQueryResult
+ */
+
+/**
+ * Query ping result.
+ * @typedef {{}} VisorQueryPingResult
+ */
 
 /** Reserved cache names */
 const RESERVED_CACHE_NAMES = [
@@ -150,6 +161,17 @@
 
     socket = null;
 
+    /** @type {Set<() => Promise>} */
+    switchClusterListeners = new Set();
+
+    addClusterSwitchListener(func) {
+        this.switchClusterListeners.add(func);
+    }
+
+    removeClusterSwitchListener(func) {
+        this.switchClusterListeners.delete(func);
+    }
+
     static restoreActiveCluster() {
         try {
             return JSON.parse(localStorage.cluster);
@@ -280,13 +302,18 @@
     }
 
     switchCluster(cluster) {
-        const state = this.connectionSbj.getValue();
+        return Promise.all(_.map([...this.switchClusterListeners], (lnr) => lnr()))
+            .then(() => {
+                const state = this.connectionSbj.getValue();
 
-        state.updateCluster(cluster);
+                state.updateCluster(cluster);
 
-        this.connectionSbj.next(state);
+                this.connectionSbj.next(state);
 
-        this.saveToStorage(cluster);
+                this.saveToStorage(cluster);
+
+                return Promise.resolve();
+            });
     }
 
     /**
@@ -678,7 +705,7 @@
      * @param {Number} pageSize
      * @param {Boolean} [lazy] query flag.
      * @param {Boolean} [collocated] Collocated query.
-     * @returns {Promise}
+     * @returns {Promise.<VisorQueryResult>} Query execution result.
      */
     querySql({nid, cacheName, query, nonCollocatedJoins, enforceJoinOrder, replicatedOnly, local, pageSize, lazy = false, collocated = false}) {
         if (this.available(IGNITE_2_0)) {
@@ -721,7 +748,7 @@
      * @param {String} nid Node id.
      * @param {String} queryId Query ID.
      * @param {Number} pageSize
-     * @returns {Promise}
+     * @returns {Promise.<VisorQueryResult>} Query execution result.
      */
     queryFetchFistsPage(nid, queryId, pageSize) {
         return this.visorTask('queryFetchFirstPage', nid, queryId, pageSize).then(({error, result}) => {
@@ -734,9 +761,27 @@
 
     /**
      * @param {String} nid Node id.
+     * @param {String} queryId Query ID.
+     * @returns {Promise.<VisorQueryPingResult>} Query execution result.
+     */
+    queryPing(nid, queryId) {
+        if (this.available(...QUERY_PING_SINCE)) {
+            return this.visorTask('queryPing', nid, queryId, 1).then(({error, result}) => {
+                if (_.isEmpty(error))
+                    return {queryPingSupported: true};
+
+                return Promise.reject(error);
+            });
+        }
+
+        return Promise.resolve({queryPingSupported: false});
+    }
+
+    /**
+     * @param {String} nid Node id.
      * @param {Number} queryId
      * @param {Number} pageSize
-     * @returns {Promise}
+     * @returns {Promise.<VisorQueryResult>} Query execution result.
      */
     queryNextPage(nid, queryId, pageSize) {
         if (this.available(IGNITE_2_0))
@@ -745,58 +790,10 @@
         return this.visorTask('queryFetch', nid, queryId, pageSize);
     }
 
-    _fetchQueryAllResults(acc, pageSize) {
-        if (!_.isNil(acc.rows)) {
-            if (!acc.hasMore)
-                return acc;
-
-            return of(acc).pipe(
-                expand((acc) => {
-                    return from(this.queryNextPage(acc.responseNodeId, acc.queryId, pageSize)
-                        .then((res) => {
-                            acc.rows = acc.rows.concat(res.rows);
-                            acc.hasMore = res.hasMore;
-
-                            return acc;
-                        }));
-                }),
-                takeWhile((acc) => acc.hasMore),
-                last()
-            ).toPromise();
-        }
-
-        return timer(100, 500).pipe(
-            exhaustMap(() => this.queryFetchFistsPage(acc.responseNodeId, acc.queryId, pageSize)),
-            filter((res) => !_.isNil(res.rows)),
-            first(),
-            map((res) => this._fetchQueryAllResults(res, 1024))
-        ).toPromise();
-    }
-
-    /**
-     * @param {String} nid Node id.
-     * @param {String} cacheName Cache name.
-     * @param {String} [query] Query if null then scan query.
-     * @param {Boolean} nonCollocatedJoins Flag whether to execute non collocated joins.
-     * @param {Boolean} enforceJoinOrder Flag whether enforce join order is enabled.
-     * @param {Boolean} replicatedOnly Flag whether query contains only replicated tables.
-     * @param {Boolean} local Flag whether to execute query locally.
-     * @param {Boolean} lazy query flag.
-     * @param {Boolean} collocated Collocated query.
-     * @returns {Promise}
-     */
-    querySqlGetAll({nid, cacheName, query, nonCollocatedJoins, enforceJoinOrder, replicatedOnly, local, lazy, collocated}) {
-        // Page size for query.
-        const pageSize = 1024;
-
-        return this.querySql({nid, cacheName, query, nonCollocatedJoins, enforceJoinOrder, replicatedOnly, local, pageSize, lazy, collocated})
-            .then((res) => this._fetchQueryAllResults(res, pageSize));
-    }
-
     /**
      * @param {String} nid Node id.
      * @param {Number} [queryId]
-     * @returns {Promise}
+     * @returns {Promise<Void>}
      */
     queryClose(nid, queryId) {
         if (this.available(IGNITE_2_0)) {
@@ -816,7 +813,7 @@
      * @param {Boolean} near Scan near cache.
      * @param {Boolean} local Flag whether to execute query locally.
      * @param {Number} pageSize Page size.
-     * @returns {Promise}
+     * @returns {Promise.<VisorQueryResult>} Query execution result.
      */
     queryScan({nid, cacheName, filter, regEx, caseSensitive, near, local, pageSize}) {
         if (this.available(IGNITE_2_0)) {
@@ -842,24 +839,6 @@
     }
 
     /**
-     * @param {String} nid Node id.
-     * @param {String} cacheName Cache name.
-     * @param {String} filter Filter text.
-     * @param {Boolean} regEx Flag whether filter by regexp.
-     * @param {Boolean} caseSensitive Case sensitive filtration.
-     * @param {Boolean} near Scan near cache.
-     * @param {Boolean} local Flag whether to execute query locally.
-     * @returns {Promise}
-     */
-    queryScanGetAll({nid, cacheName, filter, regEx, caseSensitive, near, local}) {
-        // Page size for query.
-        const pageSize = 1024;
-
-        return this.queryScan({nid, cacheName, filter, regEx, caseSensitive, near, local, pageSize})
-            .then((res) => this._fetchQueryAllResults(res, pageSize));
-    }
-
-    /**
      * Change cluster active state.
      *
      * @returns {Promise}
diff --git a/modules/web-console/frontend/app/services/Version.service.js b/modules/web-console/frontend/app/services/Version.service.js
index 8b76d58..511cf66 100644
--- a/modules/web-console/frontend/app/services/Version.service.js
+++ b/modules/web-console/frontend/app/services/Version.service.js
@@ -23,55 +23,8 @@
  */
 const VERSION_MATCHER = /(\d+)\.(\d+)\.(\d+)([-.]([^0123456789][^-]+)(-SNAPSHOT)?)?(-(\d+))?(-([\da-f]+))?/i;
 
-/**
- * Tries to parse product version from it's string representation.
- *
- * @param {String} ver - String representation of version.
- * @returns {{major: Number, minor: Number, maintenance: Number, stage: String, revTs: Number, revHash: String}} - Object that contains product version fields.
- */
-const parse = (ver) => {
-    // Development or built from source ZIP.
-    ver = ver.replace(/(-DEV|-n\/a)$/i, '');
-
-    const [, major, minor, maintenance, stage, ...chunks] = ver.match(VERSION_MATCHER);
-
-    return {
-        major: parseInt(major, 10),
-        minor: parseInt(minor, 10),
-        maintenance: parseInt(maintenance, 10),
-        stage: (stage || '').substring(1),
-        revTs: chunks[2] ? parseInt(chunks[3], 10) : 0,
-        revHash: chunks[4] ? chunks[5] : null
-    };
-};
-
 const numberComparator = (a, b) => a > b ? 1 : a < b ? -1 : 0;
 
-/**
- * Compare to version.
- * @param {Object} a first compared version.
- * @param {Object} b second compared version.
- * @returns {Number} 1 if a > b, 0 if versions equals, -1 if a < b
- */
-const compare = (a, b) => {
-    let res = numberComparator(a.major, b.major);
-
-    if (res !== 0)
-        return res;
-
-    res = numberComparator(a.minor, b.minor);
-
-    if (res !== 0)
-        return res;
-
-    res = numberComparator(a.maintenance, b.maintenance);
-
-    if (res !== 0)
-        return res;
-
-    return numberComparator(a.stage, b.stage);
-};
-
 export default class IgniteVersion {
     constructor() {
         this.webConsole = '2.8.0';
@@ -159,17 +112,17 @@
      * @returns {Boolean} `True` if version is equal or greater than specified range.
      */
     since(target, ...ranges) {
-        const targetVer = parse(target);
+        const targetVer = this.parse(target);
 
         return !!_.find(ranges, (range) => {
             if (_.isArray(range)) {
                 const [after, before] = range;
 
-                return compare(targetVer, parse(after)) >= 0 &&
-                    (_.isNil(before) || compare(targetVer, parse(before)) < 0);
+                return this.compare(targetVer, this.parse(after)) >= 0 &&
+                    (_.isNil(before) || this.compare(targetVer, this.parse(before)) < 0);
             }
 
-            return compare(targetVer, parse(range)) >= 0;
+            return this.compare(targetVer, this.parse(range)) >= 0;
         });
     }
 
@@ -193,4 +146,53 @@
     available(...ranges) {
         return this.since(this.current, ...ranges);
     }
+
+    /**
+     * Tries to parse product version from it's string representation.
+     *
+     * @param {String} ver - String representation of version.
+     * @returns {{major: Number, minor: Number, maintenance: Number, stage: String, revTs: Number, revHash: String}} - Object that contains product version fields.
+     */
+    parse(ver) {
+        // Development or built from source ZIP.
+        ver = ver.replace(/(-DEV|-n\/a)$/i, '');
+
+        const [, major, minor, maintenance, stage, ...chunks] = ver.match(VERSION_MATCHER);
+
+        return {
+            major: parseInt(major, 10),
+            minor: parseInt(minor, 10),
+            maintenance: parseInt(maintenance, 10),
+            stage: (stage || '').substring(1),
+            revTs: chunks[2] ? parseInt(chunks[3], 10) : 0,
+            revHash: chunks[4] ? chunks[5] : null
+        };
+    }
+
+    /**
+     * Compare to version.
+     *
+     * @param {Object} a first compared version.
+     * @param {Object} b second compared version.
+     * @returns {Number} 1 if a > b, 0 if versions equals, -1 if a < b
+     */
+    compare(a, b) {
+        let res = numberComparator(a.major, b.major);
+
+        if (res !== 0)
+            return res;
+
+        res = numberComparator(a.minor, b.minor);
+
+        if (res !== 0)
+            return res;
+
+        res = numberComparator(a.maintenance, b.maintenance);
+
+        if (res !== 0)
+            return res;
+
+        return numberComparator(a.stage, b.stage);
+    }
+
 }
diff --git a/modules/web-console/frontend/app/services/Version.spec.js b/modules/web-console/frontend/app/services/Version.spec.js
index 12e769c..c0f6984 100644
--- a/modules/web-console/frontend/app/services/Version.spec.js
+++ b/modules/web-console/frontend/app/services/Version.spec.js
@@ -23,7 +23,7 @@
 import { assert } from 'chai';
 
 suite('VersionServiceTestsSuite', () => {
-    test.skip('Parse 1.7.0-SNAPSHOT', () => {
+    test('Parse 1.7.0-SNAPSHOT', () => {
         const version = INSTANCE.parse('1.7.0-SNAPSHOT');
         assert.equal(version.major, 1);
         assert.equal(version.minor, 7);
@@ -33,7 +33,7 @@
         assert.isNull(version.revHash);
     });
 
-    test.skip('Parse strip -DEV 1.7.0-DEV', () => {
+    test('Parse strip -DEV 1.7.0-DEV', () => {
         const version = INSTANCE.parse('1.7.0-DEV');
         assert.equal(version.major, 1);
         assert.equal(version.minor, 7);
@@ -41,7 +41,7 @@
         assert.equal(version.stage, '');
     });
 
-    test.skip('Parse strip -n/a 1.7.0-n/a', () => {
+    test('Parse strip -n/a 1.7.0-n/a', () => {
         const version = INSTANCE.parse('1.7.0-n/a');
         assert.equal(version.major, 1);
         assert.equal(version.minor, 7);
@@ -49,23 +49,23 @@
         assert.equal(version.stage, '');
     });
 
-    test.skip('Check patch version', () => {
+    test('Check patch version', () => {
         assert.equal(INSTANCE.compare(INSTANCE.parse('1.7.2'), INSTANCE.parse('1.7.1')), 1);
     });
 
-    test.skip('Check minor version', () => {
+    test('Check minor version', () => {
         assert.equal(INSTANCE.compare(INSTANCE.parse('1.8.1'), INSTANCE.parse('1.7.1')), 1);
     });
 
-    test.skip('Check major version', () => {
+    test('Check major version', () => {
         assert.equal(INSTANCE.compare(INSTANCE.parse('2.7.1'), INSTANCE.parse('1.7.1')), 1);
     });
 
-    test.skip('Version a > b', () => {
+    test('Version a > b', () => {
         assert.equal(INSTANCE.compare(INSTANCE.parse('1.7.0'), INSTANCE.parse('1.5.0')), 1);
     });
 
-    test.skip('Version a = b', () => {
+    test('Version a = b', () => {
         assert.equal(INSTANCE.compare(INSTANCE.parse('1.0.0'), INSTANCE.parse('1.0.0')), 0);
         assert.equal(INSTANCE.compare(INSTANCE.parse('1.2.0'), INSTANCE.parse('1.2.0')), 0);
         assert.equal(INSTANCE.compare(INSTANCE.parse('1.2.3'), INSTANCE.parse('1.2.3')), 0);
@@ -75,7 +75,7 @@
         assert.equal(INSTANCE.compare(INSTANCE.parse('1.2.3-1'), INSTANCE.parse('1.2.3-1')), 0);
     });
 
-    test.skip('Version a < b', () => {
+    test('Version a < b', () => {
         assert.equal(INSTANCE.compare(INSTANCE.parse('1.5.1'), INSTANCE.parse('1.5.2')), -1);
     });
 
diff --git a/modules/web-console/frontend/public/stylesheets/style.scss b/modules/web-console/frontend/public/stylesheets/style.scss
index a8b9a10..be31060 100644
--- a/modules/web-console/frontend/public/stylesheets/style.scss
+++ b/modules/web-console/frontend/public/stylesheets/style.scss
@@ -2071,7 +2071,7 @@
 
 
     h1 {
-        height: 36px;
+        min-height: 36px;
         margin: 0;
         margin-right: 8px;
 
diff --git a/modules/web-console/frontend/views/index.pug b/modules/web-console/frontend/views/index.pug
index 6029993..71d5363 100644
--- a/modules/web-console/frontend/views/index.pug
+++ b/modules/web-console/frontend/views/index.pug
@@ -21,6 +21,8 @@
 
         meta(http-equiv='content-type' content='text/html; charset=utf-8')
         meta(http-equiv='content-language' content='en')
+        meta(http-equiv="Cache-control" content="no-cache, no-store, must-revalidate")
+        meta(http-equiv="Pragma" content="no-cache")
         meta(http-equiv='X-UA-Compatible' content='IE=Edge')
         meta(name='viewport' content='width=device-width, height=device-height, initial-scale=1.0, minimum-scale=1.0')
 
diff --git a/modules/web-console/pom.xml b/modules/web-console/pom.xml
index c72e32d..5e026ec 100644
--- a/modules/web-console/pom.xml
+++ b/modules/web-console/pom.xml
@@ -68,7 +68,7 @@
 
         <dependency>
             <groupId>org.apache.ignite</groupId>
-            <artifactId>ignite-hibernate_4.2</artifactId>
+            <artifactId>ignite-hibernate_5.1</artifactId>
             <version>${project.version}</version>
             <scope>test</scope>
         </dependency>
@@ -410,9 +410,13 @@
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-jar-plugin</artifactId>
-                <configuration>
-                    <skip>true</skip>
-                </configuration>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>test-jar</goal>
+                        </goals>
+                    </execution>
+                </executions>
             </plugin>
 
             <plugin>
diff --git a/modules/zookeeper/src/main/java/org/apache/ignite/spi/discovery/zk/internal/ZookeeperDiscoveryImpl.java b/modules/zookeeper/src/main/java/org/apache/ignite/spi/discovery/zk/internal/ZookeeperDiscoveryImpl.java
index 8d887f9..04f1586 100644
--- a/modules/zookeeper/src/main/java/org/apache/ignite/spi/discovery/zk/internal/ZookeeperDiscoveryImpl.java
+++ b/modules/zookeeper/src/main/java/org/apache/ignite/spi/discovery/zk/internal/ZookeeperDiscoveryImpl.java
@@ -569,7 +569,7 @@
     public boolean allNodesSupport(IgniteFeatures feature) {
         checkState();
 
-        return rtState.top.isAllNodes(n -> IgniteFeatures.nodeSupports(n, feature));
+        return rtState != null && rtState.top.isAllNodes(n -> IgniteFeatures.nodeSupports(n, feature));
     }
 
     /**
@@ -2022,7 +2022,7 @@
     }
 
     /**
-     * @param node Joining node data.
+     * @param joiningNodeData Joining node data.
      * @return Validation result.
      */
     private ZkNodeValidateResult validateJoiningNode(ZkJoiningNodeData joiningNodeData) {
@@ -4468,7 +4468,7 @@
             id = IgniteUuid.fromUuid(node.id());
 
             endTime = System.currentTimeMillis() + node.sessionTimeout() + 1000;
-        };
+        }
 
         /** {@inheritDoc} */
         @Override public IgniteUuid id() {
diff --git a/modules/zookeeper/src/test/java/org/apache/ignite/spi/discovery/tcp/ipfinder/zk/ZookeeperIpFinderTest.java b/modules/zookeeper/src/test/java/org/apache/ignite/spi/discovery/tcp/ipfinder/zk/ZookeeperIpFinderTest.java
index b49ff18..f531848 100644
--- a/modules/zookeeper/src/test/java/org/apache/ignite/spi/discovery/tcp/ipfinder/zk/ZookeeperIpFinderTest.java
+++ b/modules/zookeeper/src/test/java/org/apache/ignite/spi/discovery/tcp/ipfinder/zk/ZookeeperIpFinderTest.java
@@ -35,6 +35,7 @@
 import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
 import org.apache.ignite.spi.discovery.tcp.ipfinder.zk.curator.TestingCluster;
 import org.apache.ignite.testframework.GridTestUtils;
+import org.apache.ignite.testframework.junits.WithSystemProperty;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
 import org.junit.Rule;
 import org.junit.Test;
@@ -45,6 +46,7 @@
  *
  * @author Raul Kripalani
  */
+@WithSystemProperty(key = "zookeeper.jmx.log4j.disable", value = "true") // disable JMX for tests
 public class ZookeeperIpFinderTest extends GridCommonAbstractTest {
     /** Per test timeout */
     @Rule
@@ -81,9 +83,6 @@
         // remove stale system properties
         System.getProperties().remove(TcpDiscoveryZookeeperIpFinder.PROP_ZK_CONNECTION_STRING);
 
-        // disable JMX for tests
-        System.setProperty("zookeeper.jmx.log4j.disable", "true");
-
         // start the ZK cluster
         zkCluster = new TestingCluster(ZK_CLUSTER_SIZE);
 
diff --git a/modules/zookeeper/src/test/java/org/apache/ignite/spi/discovery/zk/ZookeeperDiscoverySpiTestSuite1.java b/modules/zookeeper/src/test/java/org/apache/ignite/spi/discovery/zk/ZookeeperDiscoverySpiTestSuite1.java
index dd64e4e..f8a5f36 100644
--- a/modules/zookeeper/src/test/java/org/apache/ignite/spi/discovery/zk/ZookeeperDiscoverySpiTestSuite1.java
+++ b/modules/zookeeper/src/test/java/org/apache/ignite/spi/discovery/zk/ZookeeperDiscoverySpiTestSuite1.java
@@ -19,17 +19,17 @@
 
 import org.apache.curator.test.ByteCodeRewrite;
 import org.apache.ignite.spi.discovery.zk.internal.ZookeeperClientTest;
+import org.apache.ignite.spi.discovery.zk.internal.ZookeeperDiscoveryClientDisconnectTest;
 import org.apache.ignite.spi.discovery.zk.internal.ZookeeperDiscoveryClientReconnectTest;
-import org.apache.ignite.spi.discovery.zk.internal.ZookeeperDiscoverySpiSaslFailedAuthTest;
-import org.apache.ignite.spi.discovery.zk.internal.ZookeeperDiscoverySpiSaslSuccessfulAuthTest;
+import org.apache.ignite.spi.discovery.zk.internal.ZookeeperDiscoveryCommunicationFailureTest;
+import org.apache.ignite.spi.discovery.zk.internal.ZookeeperDiscoveryConcurrentStartAndStartStopTest;
+import org.apache.ignite.spi.discovery.zk.internal.ZookeeperDiscoveryCustomEventsTest;
 import org.apache.ignite.spi.discovery.zk.internal.ZookeeperDiscoveryMiscTest;
 import org.apache.ignite.spi.discovery.zk.internal.ZookeeperDiscoverySegmentationAndConnectionRestoreTest;
-import org.apache.ignite.spi.discovery.zk.internal.ZookeeperDiscoveryConcurrentStartAndStartStopTest;
-import org.apache.ignite.spi.discovery.zk.internal.ZookeeperDiscoveryTopologyChangeAndReconnectTest;
-import org.apache.ignite.spi.discovery.zk.internal.ZookeeperDiscoveryCommunicationFailureTest;
-import org.apache.ignite.spi.discovery.zk.internal.ZookeeperDiscoveryClientDisconnectTest;
+import org.apache.ignite.spi.discovery.zk.internal.ZookeeperDiscoverySpiSaslFailedAuthTest;
+import org.apache.ignite.spi.discovery.zk.internal.ZookeeperDiscoverySpiSaslSuccessfulAuthTest;
 import org.apache.ignite.spi.discovery.zk.internal.ZookeeperDiscoverySplitBrainTest;
-import org.apache.ignite.spi.discovery.zk.internal.ZookeeperDiscoveryCustomEventsTest;
+import org.apache.ignite.spi.discovery.zk.internal.ZookeeperDiscoveryTopologyChangeAndReconnectTest;
 import org.apache.zookeeper.jmx.MBeanRegistry;
 import org.apache.zookeeper.server.ZooKeeperServer;
 import org.apache.zookeeper.server.quorum.LearnerZooKeeperServer;
diff --git a/modules/zookeeper/src/test/java/org/apache/ignite/spi/discovery/zk/internal/ZookeeperDiscoveryClientReconnectTest.java b/modules/zookeeper/src/test/java/org/apache/ignite/spi/discovery/zk/internal/ZookeeperDiscoveryClientReconnectTest.java
index 019511b..03daa01 100644
--- a/modules/zookeeper/src/test/java/org/apache/ignite/spi/discovery/zk/internal/ZookeeperDiscoveryClientReconnectTest.java
+++ b/modules/zookeeper/src/test/java/org/apache/ignite/spi/discovery/zk/internal/ZookeeperDiscoveryClientReconnectTest.java
@@ -17,19 +17,17 @@
 
 package org.apache.ignite.spi.discovery.zk.internal;
 
+import java.util.concurrent.Callable;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ThreadLocalRandom;
+import java.util.concurrent.atomic.AtomicInteger;
 import org.apache.ignite.Ignite;
 import org.apache.ignite.internal.IgniteEx;
 import org.apache.ignite.internal.util.lang.GridAbsPredicate;
 import org.apache.ignite.lang.IgniteInClosure;
 import org.apache.ignite.testframework.GridTestUtils;
-import org.junit.Ignore;
 import org.junit.Test;
 
-import java.util.concurrent.Callable;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.ThreadLocalRandom;
-import java.util.concurrent.atomic.AtomicInteger;
-
 import static java.util.concurrent.TimeUnit.SECONDS;
 import static org.apache.ignite.events.EventType.EVT_CLIENT_NODE_DISCONNECTED;
 
@@ -40,7 +38,6 @@
     /**
      * @throws Exception If failed.
      */
-    @Ignore("https://issues.apache.org/jira/browse/IGNITE-8178")
     @Test
     public void testReconnectServersRestart_1() throws Exception {
         reconnectServersRestart(1);
@@ -49,11 +46,11 @@
     /**
      * @throws Exception If failed.
      */
-    @Ignore("https://issues.apache.org/jira/browse/IGNITE-8178")
     @Test
     public void testReconnectServersRestart_2() throws Exception {
         reconnectServersRestart(3);
     }
+
     /**
      * @throws Exception If failed.
      */
@@ -141,6 +138,8 @@
      * @throws Exception If failed.
      */
     private void reconnectServersRestart(int srvs) throws Exception {
+        sesTimeout = 30_000;
+
         startGridsMultiThreaded(srvs);
 
         helper.clientMode(true);
diff --git a/modules/zookeeper/src/test/java/org/apache/ignite/spi/discovery/zk/internal/ZookeeperDiscoveryConcurrentStartAndStartStopTest.java b/modules/zookeeper/src/test/java/org/apache/ignite/spi/discovery/zk/internal/ZookeeperDiscoveryConcurrentStartAndStartStopTest.java
index 3a80d3e..4aebb2b 100644
--- a/modules/zookeeper/src/test/java/org/apache/ignite/spi/discovery/zk/internal/ZookeeperDiscoveryConcurrentStartAndStartStopTest.java
+++ b/modules/zookeeper/src/test/java/org/apache/ignite/spi/discovery/zk/internal/ZookeeperDiscoveryConcurrentStartAndStartStopTest.java
@@ -29,9 +29,12 @@
 import org.apache.ignite.internal.util.typedef.internal.CU;
 import org.apache.ignite.lang.IgniteInClosure;
 import org.apache.ignite.testframework.GridTestUtils;
+import org.apache.ignite.testframework.junits.WithSystemProperty;
 import org.apache.zookeeper.ZkTestClientCnxnSocketNIO;
 import org.junit.Test;
 
+import static org.apache.ignite.spi.discovery.zk.internal.ZookeeperDiscoveryImpl.IGNITE_ZOOKEEPER_DISCOVERY_SPI_MAX_EVTS;
+
 /**
  * Tests for Zookeeper SPI discovery.
  */
@@ -128,15 +131,9 @@
      * @throws Exception If failed.
      */
     @Test
+    @WithSystemProperty(key = IGNITE_ZOOKEEPER_DISCOVERY_SPI_MAX_EVTS, value = "1")
     public void testConcurrentStartStop2_EventsThrottle() throws Exception {
-        System.setProperty(ZookeeperDiscoveryImpl.IGNITE_ZOOKEEPER_DISCOVERY_SPI_MAX_EVTS, "1");
-
-        try {
-            concurrentStartStop(5);
-        }
-        finally {
-            System.clearProperty(ZookeeperDiscoveryImpl.IGNITE_ZOOKEEPER_DISCOVERY_SPI_MAX_EVTS);
-        }
+        concurrentStartStop(5);
     }
 
     /**
diff --git a/modules/zookeeper/src/test/java/org/apache/ignite/spi/discovery/zk/internal/ZookeeperDiscoverySegmentationAndConnectionRestoreTest.java b/modules/zookeeper/src/test/java/org/apache/ignite/spi/discovery/zk/internal/ZookeeperDiscoverySegmentationAndConnectionRestoreTest.java
index ae4e44a..9b16503 100644
--- a/modules/zookeeper/src/test/java/org/apache/ignite/spi/discovery/zk/internal/ZookeeperDiscoverySegmentationAndConnectionRestoreTest.java
+++ b/modules/zookeeper/src/test/java/org/apache/ignite/spi/discovery/zk/internal/ZookeeperDiscoverySegmentationAndConnectionRestoreTest.java
@@ -40,6 +40,7 @@
 import org.apache.ignite.spi.discovery.zk.ZookeeperDiscoverySpi;
 import org.apache.ignite.spi.discovery.zk.ZookeeperDiscoverySpiTestUtil;
 import org.apache.ignite.testframework.GridTestUtils;
+import org.apache.ignite.testframework.junits.WithSystemProperty;
 import org.apache.ignite.transactions.Transaction;
 import org.apache.zookeeper.ZkTestClientCnxnSocketNIO;
 import org.apache.zookeeper.ZooKeeper;
@@ -47,6 +48,7 @@
 import org.junit.Ignore;
 import org.junit.Test;
 
+import static org.apache.ignite.IgniteSystemProperties.IGNITE_WAL_LOG_TX_RECORDS;
 import static org.apache.ignite.transactions.TransactionConcurrency.OPTIMISTIC;
 import static org.apache.ignite.transactions.TransactionConcurrency.PESSIMISTIC;
 import static org.apache.ignite.transactions.TransactionIsolation.READ_COMMITTED;
@@ -64,83 +66,77 @@
      * @see <a href="https://issues.apache.org/jira/browse/IGNITE-9040">IGNITE-9040</a> ticket for more context of the test.
      */
     @Test
+    @WithSystemProperty(key = IGNITE_WAL_LOG_TX_RECORDS, value = "true")
     public void testStopNodeOnSegmentaion() throws Exception {
-        try {
-            System.setProperty("IGNITE_WAL_LOG_TX_RECORDS", "true");
+        sesTimeout = 2000;
+        testSockNio = true;
+        persistence = true;
+        atomicityMode = CacheAtomicityMode.TRANSACTIONAL;
+        backups = 2;
 
-            sesTimeout = 2000;
-            testSockNio = true;
-            persistence = true;
-            atomicityMode = CacheAtomicityMode.TRANSACTIONAL;
-            backups = 2;
+        final Ignite node0 = startGrid(0);
 
-            final Ignite node0 = startGrid(0);
+        sesTimeout = 10_000;
+        testSockNio = false;
 
-            sesTimeout = 10_000;
-            testSockNio = false;
+        startGrid(1);
 
-            startGrid(1);
+        node0.cluster().active(true);
 
-            node0.cluster().active(true);
+        helper.clientMode(true);
 
-            helper.clientMode(true);
+        final IgniteEx client = startGrid(2);
 
-            final IgniteEx client = startGrid(2);
+        //first transaction
+        client.transactions().txStart(PESSIMISTIC, READ_COMMITTED, 0, 0);
+        client.cache(DEFAULT_CACHE_NAME).put(0, 0);
 
-            //first transaction
-            client.transactions().txStart(PESSIMISTIC, READ_COMMITTED, 0, 0);
-            client.cache(DEFAULT_CACHE_NAME).put(0, 0);
+        //second transaction to create a deadlock with the first one
+        // and guarantee transaction futures will be presented on segmented node
+        // (erroneous write to WAL on segmented node stop happens
+        // on completing transaction with NodeStoppingException)
+        GridTestUtils.runAsync(new Runnable() {
+            @Override public void run() {
+                Transaction tx2 = client.transactions().txStart(OPTIMISTIC, READ_COMMITTED, 0, 0);
+                client.cache(DEFAULT_CACHE_NAME).put(0, 0);
+                tx2.commit();
+            }
+        });
 
-            //second transaction to create a deadlock with the first one
-            // and guarantee transaction futures will be presented on segmented node
-            // (erroneous write to WAL on segmented node stop happens
-            // on completing transaction with NodeStoppingException)
-            GridTestUtils.runAsync(new Runnable() {
-                @Override public void run() {
-                    Transaction tx2 = client.transactions().txStart(OPTIMISTIC, READ_COMMITTED, 0, 0);
-                    client.cache(DEFAULT_CACHE_NAME).put(0, 0);
-                    tx2.commit();
+        //next block simulates Ignite node segmentation by closing socket of ZooKeeper client
+        {
+            final CountDownLatch l = new CountDownLatch(1);
+
+            node0.events().localListen(new IgnitePredicate<Event>() {
+                @Override public boolean apply(Event evt) {
+                    l.countDown();
+
+                    return false;
                 }
-            });
+            }, EventType.EVT_NODE_SEGMENTED);
 
-            //next block simulates Ignite node segmentation by closing socket of ZooKeeper client
-            {
-                final CountDownLatch l = new CountDownLatch(1);
+            ZkTestClientCnxnSocketNIO c0 = ZkTestClientCnxnSocketNIO.forNode(node0);
 
-                node0.events().localListen(new IgnitePredicate<Event>() {
-                    @Override public boolean apply(Event evt) {
-                        l.countDown();
+            c0.closeSocket(true);
 
-                        return false;
-                    }
-                }, EventType.EVT_NODE_SEGMENTED);
+            for (int i = 0; i < 10; i++) {
+                //noinspection BusyWait
+                Thread.sleep(1_000);
 
-                ZkTestClientCnxnSocketNIO c0 = ZkTestClientCnxnSocketNIO.forNode(node0);
-
-                c0.closeSocket(true);
-
-                for (int i = 0; i < 10; i++) {
-                    //noinspection BusyWait
-                    Thread.sleep(1_000);
-
-                    if (l.getCount() == 0)
-                        break;
-                }
-
-                info("Allow connect");
-
-                c0.allowConnect();
-
-                assertTrue(l.await(10, TimeUnit.SECONDS));
+                if (l.getCount() == 0)
+                    break;
             }
 
-            waitForNodeStop(node0.name());
+            info("Allow connect");
 
-            checkStoppedNodeThreads(node0.name());
+            c0.allowConnect();
+
+            assertTrue(l.await(10, TimeUnit.SECONDS));
         }
-        finally {
-            System.clearProperty("IGNITE_WAL_LOG_TX_RECORDS");
-        }
+
+        waitForNodeStop(node0.name());
+
+        checkStoppedNodeThreads(node0.name());
     }
 
     /** */
diff --git a/modules/zookeeper/src/test/java/org/apache/ignite/spi/discovery/zk/internal/ZookeeperDiscoverySpiSaslFailedAuthTest.java b/modules/zookeeper/src/test/java/org/apache/ignite/spi/discovery/zk/internal/ZookeeperDiscoverySpiSaslFailedAuthTest.java
index 84e75fe..c26cdd5 100644
--- a/modules/zookeeper/src/test/java/org/apache/ignite/spi/discovery/zk/internal/ZookeeperDiscoverySpiSaslFailedAuthTest.java
+++ b/modules/zookeeper/src/test/java/org/apache/ignite/spi/discovery/zk/internal/ZookeeperDiscoverySpiSaslFailedAuthTest.java
@@ -16,11 +16,12 @@
  */
 package org.apache.ignite.spi.discovery.zk.internal;
 
-import org.apache.zookeeper.client.ZooKeeperSaslClient;
+import org.apache.ignite.testframework.junits.WithSystemProperty;
 import org.junit.Assert;
 import org.junit.Test;
 
 import static org.apache.ignite.IgniteSystemProperties.IGNITE_ZOOKEEPER_DISCOVERY_MAX_RETRY_COUNT;
+import static org.apache.zookeeper.client.ZooKeeperSaslClient.LOGIN_CONTEXT_NAME_KEY;
 
 /**
  *
@@ -30,12 +31,9 @@
      * @throws Exception If failed.
      */
     @Test
+    @WithSystemProperty(key = LOGIN_CONTEXT_NAME_KEY, value = "InvalidZookeeperClient")
+    @WithSystemProperty(key = IGNITE_ZOOKEEPER_DISCOVERY_MAX_RETRY_COUNT, value = "1")
     public void testIgniteNodeWithInvalidPasswordFailsToJoin() throws Exception {
-        System.setProperty(ZooKeeperSaslClient.LOGIN_CONTEXT_NAME_KEY,
-            "InvalidZookeeperClient");
-
-        System.setProperty(IGNITE_ZOOKEEPER_DISCOVERY_MAX_RETRY_COUNT, "1");
-
         try {
             startGrid(0);
 
@@ -44,8 +42,5 @@
         catch (Exception ignored) {
             //ignored
         }
-        finally {
-            System.clearProperty(IGNITE_ZOOKEEPER_DISCOVERY_MAX_RETRY_COUNT);
-        }
     }
 }
diff --git a/modules/zookeeper/src/test/java/org/apache/ignite/spi/discovery/zk/internal/ZookeeperDiscoverySpiSaslSuccessfulAuthTest.java b/modules/zookeeper/src/test/java/org/apache/ignite/spi/discovery/zk/internal/ZookeeperDiscoverySpiSaslSuccessfulAuthTest.java
index 39a4555..e78d5af 100644
--- a/modules/zookeeper/src/test/java/org/apache/ignite/spi/discovery/zk/internal/ZookeeperDiscoverySpiSaslSuccessfulAuthTest.java
+++ b/modules/zookeeper/src/test/java/org/apache/ignite/spi/discovery/zk/internal/ZookeeperDiscoverySpiSaslSuccessfulAuthTest.java
@@ -16,9 +16,11 @@
  */
 package org.apache.ignite.spi.discovery.zk.internal;
 
-import org.apache.zookeeper.client.ZooKeeperSaslClient;
+import org.apache.ignite.testframework.junits.WithSystemProperty;
 import org.junit.Test;
 
+import static org.apache.zookeeper.client.ZooKeeperSaslClient.LOGIN_CONTEXT_NAME_KEY;
+
 /**
  *
  */
@@ -27,10 +29,8 @@
      * @throws Exception If failed.
      */
     @Test
+    @WithSystemProperty(key = LOGIN_CONTEXT_NAME_KEY, value = "ValidZookeeperClient")
     public void testIgniteNodesWithValidPasswordSuccessfullyJoins() throws Exception {
-        System.setProperty(ZooKeeperSaslClient.LOGIN_CONTEXT_NAME_KEY,
-            "ValidZookeeperClient");
-
         startGrids(3);
 
         waitForTopology(3);
diff --git a/modules/zookeeper/src/test/java/org/apache/ignite/spi/discovery/zk/internal/ZookeeperDiscoverySpiTestBase.java b/modules/zookeeper/src/test/java/org/apache/ignite/spi/discovery/zk/internal/ZookeeperDiscoverySpiTestBase.java
index 38147e1..08d8935 100644
--- a/modules/zookeeper/src/test/java/org/apache/ignite/spi/discovery/zk/internal/ZookeeperDiscoverySpiTestBase.java
+++ b/modules/zookeeper/src/test/java/org/apache/ignite/spi/discovery/zk/internal/ZookeeperDiscoverySpiTestBase.java
@@ -432,13 +432,13 @@
                 private UUID nodeId = currNodeId;
 
                 @Override public boolean apply(Event evt) {
-                    if(evt.type() == EVT_CLIENT_NODE_RECONNECTED){
+                    if (evt.type() == EVT_CLIENT_NODE_RECONNECTED) {
                         evts.remove(nodeId);
 
                         nodeId = evt.node().id();
                     }
 
-                    return false;
+                    return true;
                 }
             }, new int[] {EVT_CLIENT_NODE_RECONNECTED});
         }