Merge remote-tracking branch 'remotes/origin/master' into ignite-10044
diff --git a/.gitignore b/.gitignore
index c2eea34..f66b732 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,7 +1,6 @@
 *.log
 /out/
 /work/
-.idea/
 */build/
 xcuserdata/
 *.iws
@@ -31,6 +30,10 @@
 *.exe
 .mvn/
 
+#Ignore all Intellij IDEA files (except default inspections config)
+.idea/
+!.idea/inspectionProfiles/Project_Default.xml
+
 #Visual Studio files
 *.[Oo]bj
 *.user
diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
new file mode 100644
index 0000000..23515ed
--- /dev/null
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -0,0 +1,776 @@
+<profile version="1.0">
+    <option name="myName" value="ignite_inspections"/>
+    <inspection_tool class="AbstractMethodCallInConstructor" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="AccessorLikeMethodIsEmptyParen" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AccessorLikeMethodIsUnit" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintAddJavascriptInterface" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintAllowAllHostnameVerifier" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintAlwaysShowAction" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintAppCompatMethod" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintAuthLeak" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintBadHostnameVerifier" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintBatteryLife" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintCommitPrefEdits" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintCommitTransaction" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintCustomViewStyleable" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintCutPasteId" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintDefaultLocale" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintDrawAllocation" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintExportedContentProvider" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintExportedPreferenceActivity" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintExportedReceiver" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintExportedService" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintFloatMath" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintGetInstance" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintGifUsage" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintGoogleAppIndexingUrlError" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintGoogleAppIndexingWarning" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintGrantAllUris" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintHandlerLeak" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintIconColors" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintIconDensities" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintIconDipSize" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintIconDuplicates" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintIconDuplicatesConfig" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintIconExtension" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintIconLauncherShape" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintIconLocation" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintIconMissingDensityFolder" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintIconMixedNinePatch" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintIconNoDpi" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintIconXmlAndPng" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintInconsistentLayout" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintInflateParams" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintInlinedApi" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintInvalidUsesTagAttribute" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintJavascriptInterface" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintLocalSuppress" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintLogTagMismatch" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintLongLogTag" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintMergeRootFrame" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintMissingIntentFilterForMediaSearch" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintMissingMediaBrowserServiceIntentFilter" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintMissingOnPlayFromSearch" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintMissingSuperCall" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintNewApi" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintOverdraw" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintOverride" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintOverrideAbstract" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintPackageManagerGetSignatures" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintParcelClassLoader" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintParcelCreator" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintPendingBindings" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintPluralsCandidate" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintPrivateResource" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintRecycle" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintRecyclerView" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintRegistered" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintRequiredSize" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintRtlCompat" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintRtlEnabled" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintRtlHardcoded" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintRtlSymmetry" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintSQLiteString" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintSSLCertificateSocketFactoryCreateSocket" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintSSLCertificateSocketFactoryGetInsecure" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintSdCardPath" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintSecureRandom" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintServiceCast" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintSetJavaScriptEnabled" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintSetTextI18n" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintSetWorldReadable" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintSetWorldWritable" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintShiftFlags" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintShortAlarm" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintShowToast" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintSimpleDateFormat" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintStringFormatCount" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintStringFormatInvalid" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintStringFormatMatches" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintSupportAnnotationUsage" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintSuspiciousImport" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintSwitchIntDef" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintTrustAllX509TrustManager" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintUniqueConstants" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintUnlocalizedSms" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintUnprotectedSMSBroadcastReceiver" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintUnsafeDynamicallyLoadedCode" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintUnsafeNativeCodeLocation" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintUnsafeProtectedBroadcastReceiver" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintUnusedAttribute" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintUseSparseArrays" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintUseValueOf" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintValidFragment" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintViewConstructor" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintViewHolder" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintViewTag" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintWorldReadableFiles" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintWorldWriteableFiles" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintWrongCall" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidKLintWrongViewCast" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintAaptCrash" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintAccidentalOctal" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintAdapterViewChildren" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintAddJavascriptInterface" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintAllowAllHostnameVerifier" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintAllowBackup" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintAlwaysShowAction" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintAppCompatMethod" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintAppCompatResource" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintAssert" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintAuthLeak" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintBadHostnameVerifier" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintBatteryLife" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintButtonCase" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintButtonOrder" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintButtonStyle" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintByteOrderMark" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintCommitPrefEdits" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintCommitTransaction" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintContentDescription" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintCustomViewStyleable" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintCutPasteId" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintDefaultLocale" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintDeprecated" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintDeviceAdmin" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintDisableBaselineAlignment" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintDrawAllocation" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintDuplicateActivity" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintDuplicateDefinition" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintDuplicateIds" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintDuplicateIncludedIds" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintDuplicateUsesFeature" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintEnforceUTF8" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintExportedContentProvider" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintExportedPreferenceActivity" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintExportedReceiver" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintExportedService" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintExtraText" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintExtraTranslation" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintFloatMath" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintFullBackupContent" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintGetInstance" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintGifUsage" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintGoogleAppIndexingUrlError" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintGoogleAppIndexingWarning" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintGradleCompatible" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintGradleDependency" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintGradleDeprecated" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintGradleDynamicVersion" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintGradleGetter" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintGradleIdeError" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintGradleOverrides" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintGradlePath" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintGradlePluginVersion" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintGrantAllUris" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintGridLayout" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintHandlerLeak" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintHardcodedDebugMode" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintHardcodedText" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintHardwareIds" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintIconColors" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintIconDensities" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintIconDipSize" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintIconDuplicates" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintIconDuplicatesConfig" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintIconExtension" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintIconLauncherShape" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintIconLocation" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintIconMissingDensityFolder" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintIconMixedNinePatch" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintIconNoDpi" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintIconXmlAndPng" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintIllegalResourceRef" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintImpliedQuantity" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintInOrMmUsage" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintIncludeLayoutParam" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintInconsistentArrays" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintInconsistentLayout" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintInefficientWeight" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintInflateParams" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintInlinedApi" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintInnerclassSeparator" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintInvalidId" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintInvalidResourceFolder" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintInvalidUsesTagAttribute" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintJavascriptInterface" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintLabelFor" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintLibraryCustomView" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintLocalSuppress" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintLocaleFolder" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintLogTagMismatch" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintLongLogTag" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintManifestOrder" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintManifestResource" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintMenuTitle" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintMergeRootFrame" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintMipmapIcons" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintMissingApplicationIcon" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintMissingConstraints" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintMissingId" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintMissingIntentFilterForMediaSearch" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintMissingLeanbackLauncher" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintMissingLeanbackSupport" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintMissingMediaBrowserServiceIntentFilter" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintMissingOnPlayFromSearch" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintMissingPrefix" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintMissingQuantity" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintMissingSuperCall" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintMissingTranslation" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintMissingTvBanner" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintMissingVersion" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintMockLocation" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintMultipleUsesSdk" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintNestedScrolling" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintNestedWeights" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintNewApi" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintNfcTechWhitespace" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintNotInterpolated" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintNotSibling" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintObsoleteLayoutParam" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintOldTargetApi" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintOrientation" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintOverdraw" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintOverride" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintOverrideAbstract" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintPackageManagerGetSignatures" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintPackagedPrivateKey" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintParcelClassLoader" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintParcelCreator" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintPendingBindings" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintPermissionImpliesUnsupportedHardware" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintPluralsCandidate" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintPrivateResource" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintProguard" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintProguardSplit" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintPropertyEscape" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintProtectedPermissions" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintPxUsage" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintRecycle" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintRecyclerView" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintReferenceType" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintRegistered" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintRelativeOverlap" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintRequiredSize" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintResAuto" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintResourceCycle" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintResourceName" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintRtlCompat" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintRtlEnabled" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintRtlHardcoded" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintRtlSymmetry" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintSQLiteString" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintSSLCertificateSocketFactoryCreateSocket" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintSSLCertificateSocketFactoryGetInsecure" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintScrollViewCount" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintScrollViewSize" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintSdCardPath" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintSecureRandom" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintServiceCast" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintSetJavaScriptEnabled" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintSetTextI18n" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintSetWorldReadable" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintSetWorldWritable" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintShiftFlags" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintShortAlarm" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintShowToast" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintSignatureOrSystemPermissions" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintSimpleDateFormat" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintSmallSp" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintSpUsage" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintStateListReachable" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintStaticFieldLeak" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintStringFormatCount" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintStringFormatInvalid" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintStringFormatMatches" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintStringShouldBeInt" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintSupportAnnotationUsage" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintSuspicious0dp" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintSuspiciousImport" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintSwitchIntDef" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintTextFields" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintTextViewEdits" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintTooDeepLayout" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintTooManyViews" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintTrustAllX509TrustManager" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintTypographyDashes" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintTypographyEllipsis" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintTypographyFractions" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintTypographyOther" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintTypos" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintUniqueConstants" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintUniquePermission" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintUnknownId" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintUnknownIdInLayout" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintUnlocalizedSms" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintUnprotectedSMSBroadcastReceiver" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintUnsafeDynamicallyLoadedCode" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintUnsafeNativeCodeLocation" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintUnsafeProtectedBroadcastReceiver" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintUnsupportedTvHardware" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintUnusedAttribute" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintUnusedQuantity" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintUnusedResources" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintUseAlpha2" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintUseCompoundDrawables" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintUseSparseArrays" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintUseValueOf" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintUselessLeaf" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintUselessParent" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintUsesMinSdkAttributes" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintUsingHttp" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintValidFragment" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintValidRestrictions" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintVectorDrawableCompat" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintVectorRaster" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintViewConstructor" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintViewHolder" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintViewTag" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintWearableBindListener" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintWebViewLayout" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintWorldReadableFiles" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintWorldWriteableFiles" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintWrongCall" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintWrongCase" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintWrongFolder" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintWrongRegion" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AndroidLintWrongViewCast" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AntDuplicateTargetsInspection" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AntMissingPropertiesFileInspection" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="AntResolveInspection" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="ApparentRefinementOfResultType" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="AppliedTypeLambdaCanBeSimplified" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="ArrayCreationWithoutNewKeyword" enabled="false" level="INFORMATION" enabled_by_default="false"/>
+    <inspection_tool class="AssertAsName" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="AssignmentToCatchBlockParameter" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="AssignmentToDateFieldFromParameter" enabled="true" level="WARNING" enabled_by_default="true">
+        <option name="ignorePrivateMethods" value="true"/>
+    </inspection_tool>
+    <inspection_tool class="BadOddness" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="BigDecimalEquals" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="BooleanMethodIsAlwaysInverted" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="BreakStatementWithLabel" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="BusyWait" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="CStyleArrayDeclaration" enabled="false" level="INFORMATION" enabled_by_default="false"/>
+    <inspection_tool class="CallToStringConcatCanBeReplacedByOperator" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="CaseClassParam" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="ChainedPackage" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="ClassMayBeInterface" enabled="false" level="INFORMATION" enabled_by_default="false"/>
+    <inspection_tool class="ClassNameDiffersFromFileName" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="ClassNameSameAsAncestorName" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="CloneCallsConstructors" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="CloneInNonCloneableClass" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="CloneableImplementsClone" enabled="true" level="WARNING" enabled_by_default="true">
+        <option name="m_ignoreCloneableDueToInheritance" value="true"/>
+    </inspection_tool>
+    <inspection_tool class="CollectionContainsUrl" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="CollectionsFieldAccessReplaceableByMethodCall" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="ComparableImplementedButEqualsNotOverridden" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="ComparatorNotSerializable" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="ComparingDiffCollectionKinds" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="ComparingUnrelatedTypes" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="ComparisonOfShortAndChar" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="ComparisonToNaN" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="ConditionSignal" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="ConstantConditions" enabled="false" level="WARNING" enabled_by_default="false">
+        <option name="SUGGEST_NULLABLE_ANNOTATIONS" value="true"/>
+        <option name="DONT_REPORT_TRUE_ASSERT_STATEMENTS" value="true"/>
+    </inspection_tool>
+    <inspection_tool class="ConstantValueVariableUse" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="ContinueStatementWithLabel" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="ControlFlowStatementWithoutBraces" enabled="false" level="INFORMATION" enabled_by_default="false"/>
+    <inspection_tool class="Convert2Lambda" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="ConvertExpressionToSAM" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="ConvertNullInitializerToUnderscore" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="ConvertibleToMethodValue" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="CorrespondsUnsorted" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="CovariantCompareTo" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="CovariantEquals" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="DangerousCatchAll" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="DanglingJavadoc" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="DefaultNotLastCaseInSwitch" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="DeprecatedIsStillUsed" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="DeprecatedViewBound" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="DialogTitleCapitalization" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="DivideByZero" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="DollarSignInName" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="DottyDeprecatedWith" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="DropTakeToSlice" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="DuplicateBooleanBranch" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="DuplicateCondition" enabled="false" level="WARNING" enabled_by_default="false">
+        <option name="ignoreMethodCalls" value="false"/>
+    </inspection_tool>
+    <inspection_tool class="DuplicateThrows" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="EmptyCheck" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="EmptyInitializer" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="EmptyParenMethodAccessedAsParameterless" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="EmptyParenMethodOverridenAsParameterless" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="EmptySynchronizedStatement" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="EnumAsName" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="EnumSwitchStatementWhichMissesCases" enabled="true" level="WARNING" enabled_by_default="true">
+        <option name="ignoreSwitchStatementsWithDefault" value="true"/>
+    </inspection_tool>
+    <inspection_tool class="EqualityToSameElements" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="EqualsCalledOnEnumConstant" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="EqualsHashCodeCalledOnUrl" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="EqualsWhichDoesntCheckParameterClass" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="ErrorRethrown" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="ExceptionNameDoesntEndWithException" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="ExistsEquals" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="ExtendsUtilityClass" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="ExternalizableWithSerializationMethods" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="FieldAccessedSynchronizedAndUnsynchronized" enabled="true" level="WARNING" enabled_by_default="true">
+        <option name="countGettersAndSetters" value="false"/>
+    </inspection_tool>
+    <inspection_tool class="FieldCanBeLocal" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="FieldFromDelayedInit" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="FieldMayBeStatic" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="FilterEmptyCheck" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="FilterHeadOption" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="FilterOtherContains" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="FilterSize" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="FinalizeNotProtected" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="FindAndMapToApply" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="FindEmptyCheck" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="FloatLiteralEndingWithDecimalPoint" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="FloatingPointEquality" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="FoldTrueAnd" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="ForCanBeForeach" enabled="false" level="WARNING" enabled_by_default="false">
+        <option name="REPORT_INDEXED_LOOP" value="true"/>
+        <option name="ignoreUntypedCollections" value="false"/>
+    </inspection_tool>
+    <inspection_tool class="ForwardReference" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="FunctionTupleSyntacticSugar" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="GetGetOrElse" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="GetOrElseNull" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="HashCodeUsesVar" enabled="false" level="WEAK WARNING" enabled_by_default="false"/>
+    <inspection_tool class="HeadOrLastOption" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="HoconIncludeResolution" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="HtmlPresentationalElement" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="IfElseToOption" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="IfMayBeConditional" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="IfStatementWithIdenticalBranches" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="IgnoreResultOfCall" enabled="false" level="WARNING" enabled_by_default="false">
+        <option name="m_reportAllNonLibraryCalls" value="false"/>
+        <option name="callCheckString" value="java.io.InputStream,read,java.io.InputStream,skip,java.lang.StringBuffer,toString,java.lang.StringBuilder,toString,java.lang.String,.*,java.math.BigInteger,.*,java.math.BigDecimal,.*,java.net.InetAddress,.*,java.io.File,.*,java.lang.Object,equals|hashCode"/>
+    </inspection_tool>
+    <inspection_tool class="InjectionNotApplicable" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="InnerClassMayBeStatic" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="InstanceofThis" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="IntLiteralMayBeLongLiteral" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="IntegerDivisionInFloatingPointContext" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="IteratorHasNextCallsIteratorNext" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="IteratorNextDoesNotThrowNoSuchElementException" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="JavaAccessorMethodCalledAsEmptyParen" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="JavaAccessorMethodOverridenAsEmptyParen" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="JavaFxColorRgb" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="JavaFxDefaultTag" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="JavaFxEventHandler" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="JavaFxRedundantPropertyValue" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="JavaFxResourcePropertyValue" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="JavaFxUnresolvedFxIdReference" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="JavaFxUnusedImports" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="JavaLangImport" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="JavaMutatorMethodAccessedAsParameterless" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="JavaMutatorMethodOverridenAsParameterless" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="JsonDuplicatePropertyKeys" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="JsonStandardCompliance" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="KindProjectorSimplifyTypeProjection" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="KindProjectorUseCorrectLambdaKeyword" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="LabeledStatement" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="LanguageFeature" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="LanguageMismatch" enabled="false" level="WARNING" enabled_by_default="false">
+        <option name="CHECK_NON_ANNOTATED_REFERENCES" value="true"/>
+    </inspection_tool>
+    <inspection_tool class="LastIndexToLast" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="LengthOneStringInIndexOf" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="ListIndexOfReplaceableByContains" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="LiteralAsArgToStringEquals" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="LoopVariableNotUpdated" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="LossyEncoding" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="MapFlatten" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="MapGetGet" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="MapGetOrElseBoolean" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="MapKeys" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="MapReplaceableByEnumMap" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="MapToBooleanContains" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="MapValues" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="MatchToPartialFunction" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="MethodNameSameAsParentName" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="MethodNamesDifferOnlyByCase" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="MethodOverridesPackageLocalMethod" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="MethodOverridesPrivateMethod" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="MethodOverridesStaticMethod" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="MismatchedCollectionQueryUpdate" enabled="false" level="WEAK WARNING" enabled_by_default="false">
+        <option name="queryNames">
+            <value/>
+        </option>
+        <option name="updateNames">
+            <value/>
+        </option>
+        <option name="ignoredClasses">
+            <value/>
+        </option>
+    </inspection_tool>
+    <inspection_tool class="MissingDeprecatedAnnotation" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="MissingOverrideAnnotation" enabled="true" level="ERROR" enabled_by_default="true">
+        <option name="ignoreObjectMethods" value="true"/>
+        <option name="ignoreAnonymousClassMethods" value="false"/>
+    </inspection_tool>
+    <inspection_tool class="MissortedModifiers" enabled="true" level="ERROR" enabled_by_default="true">
+        <option name="m_requireAnnotationsFirst" value="false"/>
+    </inspection_tool>
+    <inspection_tool class="MisspelledCompareTo" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="MisspelledEquals" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="MisspelledHashcode" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="MisspelledToString" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="MultipleArgListsInAnnotation" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="MultipleRepositoryUrls" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="MutatorLikeMethodIsParameterless" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="NakedNotify" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="NameBooleanParameters" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="NoReturnTypeForImplicitDef" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="NonExceptionNameEndsWithException" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="NonFinalStaticVariableUsedInClassInitialization" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="NonProtectedConstructorInAbstractClass" enabled="true" level="WARNING" enabled_by_default="true">
+        <option name="m_ignoreNonPublicClasses" value="false"/>
+    </inspection_tool>
+    <inspection_tool class="NonSerializableObjectBoundToHttpSession" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="NonSerializableWithSerialVersionUIDField" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="NonSerializableWithSerializationMethods" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="NonSynchronizedMethodOverridesSynchronizedMethod" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="NonThreadSafeLazyInitialization" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="NotImplementedCode" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="NotifyCalledOnCondition" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="NotifyNotInSynchronizedContext" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="NotifyWithoutCorrespondingWait" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="NullableProblems" enabled="true" level="WARNING" enabled_by_default="true">
+        <option name="REPORT_NULLABLE_METHOD_OVERRIDES_NOTNULL" value="true"/>
+        <option name="REPORT_NOT_ANNOTATED_METHOD_OVERRIDES_NOTNULL" value="false"/>
+        <option name="REPORT_NOTNULL_PARAMETER_OVERRIDES_NULLABLE" value="true"/>
+        <option name="REPORT_NOT_ANNOTATED_PARAMETER_OVERRIDES_NOTNULL" value="true"/>
+        <option name="REPORT_NOT_ANNOTATED_GETTER" value="true"/>
+        <option name="REPORT_NOT_ANNOTATED_SETTER_PARAMETER" value="true"/>
+        <option name="REPORT_ANNOTATION_NOT_PROPAGATED_TO_OVERRIDERS" value="false"/>
+        <option name="REPORT_NULLS_PASSED_TO_NON_ANNOTATED_METHOD" value="true"/>
+    </inspection_tool>
+    <inspection_tool class="ObjectNotify" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="ObsoleteCollection" enabled="true" level="WARNING" enabled_by_default="true">
+        <option name="ignoreRequiredObsoleteCollectionTypes" value="false"/>
+    </inspection_tool>
+    <inspection_tool class="OptionEqualsSome" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="OverlyStrongTypeCast" enabled="true" level="WARNING" enabled_by_default="true">
+        <option name="ignoreInMatchingInstanceof" value="false"/>
+    </inspection_tool>
+    <inspection_tool class="OverriddenMethodCallDuringObjectConstruction" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="PackageVisibleInnerClass" enabled="true" level="WARNING" enabled_by_default="false">
+        <scope name="Production" level="WARNING" enabled="true">
+            <option name="ignoreEnums" value="false"/>
+            <option name="ignoreInterfaces" value="false"/>
+        </scope>
+        <option name="ignoreEnums" value="false"/>
+        <option name="ignoreInterfaces" value="false"/>
+    </inspection_tool>
+    <inspection_tool class="ParameterNameDiffersFromOverriddenParameter" enabled="false" level="WARNING" enabled_by_default="false">
+        <option name="m_ignoreSingleCharacterNames" value="false"/>
+        <option name="m_ignoreOverridesOfLibraryMethods" value="true"/>
+    </inspection_tool>
+    <inspection_tool class="ParameterlessMemberOverridenAsEmptyParen" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="PointlessIndexOfComparison" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="ProtectedMemberInFinalClass" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="PublicField" enabled="true" level="WARNING" enabled_by_default="false">
+        <scope name="Production" level="WARNING" enabled="true">
+            <option name="ignoreEnums" value="false"/>
+            <option name="ignorableAnnotations">
+                <value/>
+            </option>
+        </scope>
+        <option name="ignoreEnums" value="false"/>
+        <option name="ignorableAnnotations">
+            <value/>
+        </option>
+    </inspection_tool>
+    <inspection_tool class="PublicFieldAccessedInSynchronizedContext" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="PublicInnerClass" enabled="true" level="WARNING" enabled_by_default="false">
+        <scope name="Production" level="WARNING" enabled="true">
+            <option name="ignoreEnums" value="false"/>
+            <option name="ignoreInterfaces" value="false"/>
+        </scope>
+        <option name="ignoreEnums" value="false"/>
+        <option name="ignoreInterfaces" value="false"/>
+    </inspection_tool>
+    <inspection_tool class="RangeToIndices" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="ReadObjectAndWriteObjectPrivate" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="ReadObjectInitialization" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="ReadResolveAndWriteReplaceProtected" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="RedundantBlock" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="RedundantCollectionConversion" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="RedundantDefaultArgument" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="RedundantFieldInitialization" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="RedundantHeadOrLastOption" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="RedundantImplements" enabled="true" level="WARNING" enabled_by_default="true">
+        <option name="ignoreSerializable" value="false"/>
+        <option name="ignoreCloneable" value="false"/>
+    </inspection_tool>
+    <inspection_tool class="RedundantImport" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="RedundantMethodOverride" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="RedundantNewCaseClass" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="RedundantSuppression" enabled="true" level="ERROR" enabled_by_default="true"/>
+    <inspection_tool class="RedundantThrowsDeclaration" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="ReferenceMustBePrefixed" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="RemoveRedundantReturn" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="ReplaceAssignmentWithOperatorAssignment" enabled="true" level="WARNING" enabled_by_default="true">
+        <option name="ignoreLazyOperators" value="true"/>
+        <option name="ignoreObscureOperators" value="false"/>
+    </inspection_tool>
+    <inspection_tool class="ReplaceToWithUntil" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="ReplaceWithFlatten" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="RequiredAttributes" enabled="false" level="WARNING" enabled_by_default="false">
+        <option name="myAdditionalRequiredHtmlAttributes" value=""/>
+    </inspection_tool>
+    <inspection_tool class="ResultOfObjectAllocationIgnored" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="ResultSetIndexZero" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="ReturnOfDateField" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="ReverseIterator" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="ReverseMap" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="ReverseTakeReverse" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="SafeLock" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="SafeVarargsDetector" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="SameElementsToEquals" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="SamePackageImport" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="SameParameterValue" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="ScalaDefaultFileTemplate" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="ScalaDefaultFileTemplateUsage" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="ScalaDeprecatedIdentifier" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="ScalaDeprecation" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="ScalaDocInlinedTag" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="ScalaDocMissingParameterDescription" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="ScalaDocUnbalancedHeader" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="ScalaDocUnclosedTagWithoutParser" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="ScalaDocUnknownParameter" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="ScalaDocUnknownTag" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="ScalaFileName" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="ScalaMalformedFormatString" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="ScalaPackageName" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="ScalaRedundantCast" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="ScalaRedundantConversion" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="ScalaStyle" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="ScalaUnnecessaryParentheses" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="ScalaUnnecessarySemicolon" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="ScalaUnreachableCode" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="ScalaUnusedSymbol" enabled="false" level="WEAK WARNING" enabled_by_default="false"/>
+    <inspection_tool class="ScalaUselessExpression" enabled="false" level="WEAK WARNING" enabled_by_default="false"/>
+    <inspection_tool class="ScalaXmlUnmatchedTag" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="SerialPersistentFieldsWithWrongSignature" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="SerialVersionUIDNotStaticFinal" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="SignalWithoutCorrespondingAwait" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="SimplifiableFoldOrReduce" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="SimplifiableIfStatement" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="SimplifyBoolean" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="SimplifyBooleanMatch" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="SingleImport" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="SizeReplaceableByIsEmpty" enabled="true" level="ERROR" enabled_by_default="true"/>
+    <inspection_tool class="SizeToLength" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="SleepWhileHoldingLock" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="SortFilter" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="SpellCheckingInspection" enabled="false" level="WEAK WARNING" enabled_by_default="false">
+        <option name="processCode" value="true"/>
+        <option name="processLiterals" value="true"/>
+        <option name="processComments" value="true"/>
+    </inspection_tool>
+    <inspection_tool class="StringBufferToStringInConcatenation" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="StringEqualsEmptyString" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="SubtractionInCompareTo" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="SynchronizeOnLock" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="SynchronizedOnLiteralObject" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="SystemRunFinalizersOnExit" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="TextLabelInSwitchStatement" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="ThreadDeathRethrown" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="ThreadRun" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="ThreadStartInConstruction" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="ThreadStopSuspendResume" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="ThreadYield" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="ThrowableInstanceNeverThrown" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="ThrowableResultOfMethodCallIgnored" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="ToSetAndBack" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="TransientFieldInNonSerializableClass" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="TransientFieldNotInitialized" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="TrivialStringConcatenation" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="TypeAnnotation" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="TypeCheckCanBeMatch" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="TypeParameterExtendsFinalClass" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="TypeParameterShadow" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="UNCHECKED_WARNING" enabled="true" level="WARNING" enabled_by_default="true">
+        <option name="IGNORE_UNCHECKED_ASSIGNMENT" value="false"/>
+        <option name="IGNORE_UNCHECKED_GENERICS_ARRAY_CREATION" value="true"/>
+        <option name="IGNORE_UNCHECKED_CALL" value="false"/>
+        <option name="IGNORE_UNCHECKED_CAST" value="true"/>
+        <option name="IGNORE_UNCHECKED_OVERRIDING" value="false"/>
+    </inspection_tool>
+    <inspection_tool class="UNUSED_SYMBOL" enabled="true" level="WARNING" enabled_by_default="true">
+        <option name="LOCAL_VARIABLE" value="true"/>
+        <option name="FIELD" value="true"/>
+        <option name="METHOD" value="false"/>
+        <option name="CLASS" value="false"/>
+        <option name="PARAMETER" value="true"/>
+        <option name="REPORT_PARAMETER_FOR_PUBLIC_METHODS" value="false"/>
+    </inspection_tool>
+    <inspection_tool class="UnaryPlus" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="UnconditionalWait" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="UnitInMap" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="UnitMethodIsParameterless" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="UnknownLanguage" enabled="false" level="ERROR" enabled_by_default="false"/>
+    <inspection_tool class="UnnecessarilyQualifiedStaticUsage" enabled="true" level="WARNING" enabled_by_default="true">
+        <option name="m_ignoreStaticFieldAccesses" value="false"/>
+        <option name="m_ignoreStaticMethodCalls" value="false"/>
+        <option name="m_ignoreStaticAccessFromStaticContext" value="false"/>
+    </inspection_tool>
+    <inspection_tool class="UnnecessaryAnnotationParentheses" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="UnnecessaryCallToStringValueOf" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="UnnecessaryConstructor" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="UnnecessaryFinalOnLocalVariable" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="UnnecessaryFinalOnParameter" enabled="true" level="WARNING" enabled_by_default="true">
+        <option name="onlyWarnOnAbstractMethods" value="false"/>
+    </inspection_tool>
+    <inspection_tool class="UnnecessaryFullyQualifiedName" enabled="false" level="WARNING" enabled_by_default="false">
+        <option name="m_ignoreJavadoc" value="true"/>
+        <option name="ignoreInModuleStatements" value="true"/>
+    </inspection_tool>
+    <inspection_tool class="UnnecessaryInterfaceModifier" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="UnnecessaryJavaDocLink" enabled="true" level="WARNING" enabled_by_default="true">
+        <option name="ignoreInlineLinkToSuper" value="false"/>
+    </inspection_tool>
+    <inspection_tool class="UnnecessaryPartialFunction" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="UnnecessaryQualifierForThis" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="UnnecessarySuperConstructor" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="UnnecessarySuperQualifier" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="UnnecessaryThis" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="UnnecessaryUnaryMinus" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="UnusedCatchParameter" enabled="true" level="WARNING" enabled_by_default="true">
+        <option name="m_ignoreCatchBlocksWithComments" value="false"/>
+        <option name="m_ignoreTestCases" value="false"/>
+    </inspection_tool>
+    <!-- Unused imports used by IntelliJ Idea 2017 -->
+    <inspection_tool class="UnusedImport" enabled="true" level="ERROR" enabled_by_default="true"/>
+    <!-- Unused imporst used by IntelliJ Idea 2018 -->
+    <inspection_tool class="UNUSED_IMPORT" enabled="true" level="ERROR" enabled_by_default="true"/>
+    <inspection_tool class="UnusedLibrary" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="UnusedReturnValue" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="UpperCaseFieldNameNotConstant" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="Use of postfix method call" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="VarCouldBeVal" enabled="false" level="WEAK WARNING" enabled_by_default="false"/>
+    <inspection_tool class="VariablePatternShadow" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="WaitCalledOnCondition" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="WaitNotInLoop" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="WaitNotInSynchronizedContext" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="WaitWhileHoldingTwoLocks" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="WaitWithoutCorrespondingNotify" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="WeakerAccess" enabled="false" level="WARNING" enabled_by_default="false">
+        <option name="SUGGEST_PACKAGE_LOCAL_FOR_MEMBERS" value="true"/>
+        <option name="SUGGEST_PACKAGE_LOCAL_FOR_TOP_CLASSES" value="true"/>
+        <option name="SUGGEST_PRIVATE_FOR_INNERS" value="false"/>
+    </inspection_tool>
+    <inspection_tool class="ZeroIndexToHead" enabled="false" level="WARNING" enabled_by_default="false"/>
+    <inspection_tool class="ZeroLengthArrayInitialization" enabled="true" level="WARNING" enabled_by_default="true"/>
+    <inspection_tool class="ZipWithIndex" enabled="false" level="WARNING" enabled_by_default="false"/>
+</profile>
\ No newline at end of file
diff --git a/examples/config/example-ignite-ml.xml b/examples/config/example-ignite-ml.xml
new file mode 100644
index 0000000..a8ac705
--- /dev/null
+++ b/examples/config/example-ignite-ml.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+  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.
+-->
+
+<!--
+    Ignite configuration with all defaults and enabled p2p deployment and enabled events.
+-->
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="http://www.springframework.org/schema/beans
+        http://www.springframework.org/schema/beans/spring-beans.xsd">
+    <!-- Imports default Ignite configuration -->
+    <import resource="example-default.xml"/>
+
+    <bean parent="ignite.cfg">
+        <property name="pluginConfigurations">
+            <bean class="org.apache.ignite.ml.util.plugin.MLPluginConfiguration">
+                <property name="withMdlStorage" value="#{true}" />
+                <property name="withMdlDescStorage" value="#{true}" />
+            </bean>
+        </property>
+    </bean>
+</beans>
diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/dataset/AlgorithmSpecificDatasetExample.java b/examples/src/main/java/org/apache/ignite/examples/ml/dataset/AlgorithmSpecificDatasetExample.java
index 4d42d19..5148d9a 100644
--- a/examples/src/main/java/org/apache/ignite/examples/ml/dataset/AlgorithmSpecificDatasetExample.java
+++ b/examples/src/main/java/org/apache/ignite/examples/ml/dataset/AlgorithmSpecificDatasetExample.java
@@ -73,7 +73,7 @@
             try (AlgorithmSpecificDataset dataset = DatasetFactory.create(
                 ignite,
                 persons,
-                (upstream, upstreamSize) -> new AlgorithmSpecificPartitionContext(),
+                (env, upstream, upstreamSize) -> new AlgorithmSpecificPartitionContext(),
                 new SimpleLabeledDatasetDataBuilder<Integer, Person, AlgorithmSpecificPartitionContext>(
                     (k, v) -> VectorUtils.of(v.getAge()),
                     (k, v) -> new double[] {v.getSalary()}
diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/inference/ModelStorageExample.java b/examples/src/main/java/org/apache/ignite/examples/ml/inference/ModelStorageExample.java
new file mode 100644
index 0000000..5b704f3
--- /dev/null
+++ b/examples/src/main/java/org/apache/ignite/examples/ml/inference/ModelStorageExample.java
@@ -0,0 +1,122 @@
+/*
+ * 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.examples.ml.inference;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import org.apache.ignite.Ignite;
+import org.apache.ignite.Ignition;
+import org.apache.ignite.lang.IgniteBiTuple;
+import org.apache.ignite.ml.inference.InfModel;
+import org.apache.ignite.ml.inference.ModelDescriptor;
+import org.apache.ignite.ml.inference.ModelSignature;
+import org.apache.ignite.ml.inference.builder.SingleInfModelBuilder;
+import org.apache.ignite.ml.inference.parser.IgniteFunctionInfModelParser;
+import org.apache.ignite.ml.inference.reader.ModelStorageInfModelReader;
+import org.apache.ignite.ml.inference.storage.descriptor.ModelDescriptorStorage;
+import org.apache.ignite.ml.inference.storage.descriptor.ModelDescriptorStorageFactory;
+import org.apache.ignite.ml.inference.storage.model.ModelStorage;
+import org.apache.ignite.ml.inference.storage.model.ModelStorageFactory;
+import org.apache.ignite.ml.math.functions.IgniteFunction;
+
+/**
+ * This example demonstrates how to work with {@link ModelStorage}.
+ */
+public class ModelStorageExample {
+    /** Run example. */
+    public static void main(String... args) throws IOException, ClassNotFoundException {
+        try (Ignite ignite = Ignition.start("examples/config/example-ignite-ml.xml")) {
+            System.out.println(">>> Ignite grid started.");
+
+            ModelStorage storage = new ModelStorageFactory().getModelStorage(ignite);
+            ModelDescriptorStorage descStorage = new ModelDescriptorStorageFactory().getModelDescriptorStorage(ignite);
+
+            System.out.println("Saving model into model storage...");
+            byte[] mdl = serialize((IgniteFunction<byte[], byte[]>)i -> i);
+            storage.mkdirs("/");
+            storage.putFile("/my_model", mdl);
+
+            System.out.println("Saving model descriptor into model descriptor storage...");
+            ModelDescriptor desc = new ModelDescriptor(
+                "MyModel",
+                "My Cool Model",
+                new ModelSignature("", "", ""),
+                new ModelStorageInfModelReader("/my_model"),
+                new IgniteFunctionInfModelParser<>()
+            );
+            descStorage.put("my_model", desc);
+
+            System.out.println("List saved models...");
+            for (IgniteBiTuple<String, ModelDescriptor> model : descStorage)
+                System.out.println("-> {'" + model.getKey() + "' : " + model.getValue() + "}");
+
+            System.out.println("Load saved model descriptor...");
+            desc = descStorage.get("my_model");
+
+            System.out.println("Build inference model...");
+            SingleInfModelBuilder mdlBuilder = new SingleInfModelBuilder();
+            try (InfModel<byte[], byte[]> infMdl = mdlBuilder.build(desc.getReader(), desc.getParser())) {
+
+                System.out.println("Make inference...");
+                for (int i = 0; i < 10; i++) {
+                    Integer res = deserialize(infMdl.predict(serialize(i)));
+                    System.out.println(i + " -> " + res);
+                }
+            }
+        }
+    }
+
+    /**
+     * Serialized the specified object.
+     *
+     * @param o Object to be serialized.
+     * @return Serialized object as byte array.
+     * @throws IOException In case of exception.
+     */
+    private static <T extends Serializable> byte[] serialize(T o) throws IOException {
+        try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
+             ObjectOutputStream oos = new ObjectOutputStream(baos)) {
+            oos.writeObject(o);
+            oos.flush();
+
+            return baos.toByteArray();
+        }
+    }
+
+    /**
+     * Deserialized object represented as a byte array.
+     *
+     * @param o Serialized object.
+     * @param <T> Type of serialized object.
+     * @return Deserialized object.
+     * @throws IOException In case of exception.
+     * @throws ClassNotFoundException In case of exception.
+     */
+    @SuppressWarnings("unchecked")
+    private static <T extends Serializable> T deserialize(byte[] o) throws IOException, ClassNotFoundException {
+        try (ByteArrayInputStream bais = new ByteArrayInputStream(o);
+             ObjectInputStream ois = new ObjectInputStream(bais)) {
+
+            return (T)ois.readObject();
+        }
+    }
+}
diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/naivebayes/GaussianNaiveBayesTrainerExample.java b/examples/src/main/java/org/apache/ignite/examples/ml/naivebayes/GaussianNaiveBayesTrainerExample.java
index b5e36ea..7cbc6d1 100644
--- a/examples/src/main/java/org/apache/ignite/examples/ml/naivebayes/GaussianNaiveBayesTrainerExample.java
+++ b/examples/src/main/java/org/apache/ignite/examples/ml/naivebayes/GaussianNaiveBayesTrainerExample.java
@@ -17,6 +17,7 @@
 
 package org.apache.ignite.examples.ml.naivebayes;
 
+import java.io.FileNotFoundException;
 import java.util.Arrays;
 import javax.cache.Cache;
 import org.apache.ignite.Ignite;
@@ -24,14 +25,12 @@
 import org.apache.ignite.Ignition;
 import org.apache.ignite.cache.query.QueryCursor;
 import org.apache.ignite.cache.query.ScanQuery;
+import org.apache.ignite.examples.ml.util.MLSandboxDatasets;
 import org.apache.ignite.examples.ml.util.SandboxMLCache;
 import org.apache.ignite.ml.math.primitives.vector.Vector;
-import org.apache.ignite.ml.math.primitives.vector.VectorUtils;
 import org.apache.ignite.ml.naivebayes.gaussian.GaussianNaiveBayesModel;
 import org.apache.ignite.ml.naivebayes.gaussian.GaussianNaiveBayesTrainer;
 
-import static org.apache.ignite.examples.util.IrisDataset.irisDatasetFirstAndSecondClasses;
-
 /**
  * Run naive Bayes classification model based on <a href="https://en.wikipedia.org/wiki/Naive_Bayes_classifier"> naive
  * Bayes classifier</a> algorithm ({@link GaussianNaiveBayesTrainer}) over distributed cache.
@@ -49,15 +48,15 @@
  */
 public class GaussianNaiveBayesTrainerExample {
     /** Run example. */
-    public static void main(String[] args) throws InterruptedException {
+    public static void main(String[] args) throws FileNotFoundException {
         System.out.println();
         System.out.println(">>> Naive Bayes classification model over partitioned dataset usage example started.");
         // Start ignite grid.
         try (Ignite ignite = Ignition.start("examples/config/example-ignite.xml")) {
             System.out.println(">>> Ignite grid started.");
 
-            IgniteCache<Integer, double[]> dataCache = new SandboxMLCache(ignite)
-                .fillCacheWith(irisDatasetFirstAndSecondClasses);
+            IgniteCache<Integer, Vector> dataCache = new SandboxMLCache(ignite)
+                .fillCacheWith(MLSandboxDatasets.TWO_CLASSED_IRIS);
 
             System.out.println(">>> Create new naive Bayes classification trainer object.");
             GaussianNaiveBayesTrainer trainer = new GaussianNaiveBayesTrainer();
@@ -66,8 +65,8 @@
             GaussianNaiveBayesModel mdl = trainer.fit(
                 ignite,
                 dataCache,
-                (k, v) -> VectorUtils.of(Arrays.copyOfRange(v, 1, v.length)),
-                (k, v) -> v[0]
+                (k, v) -> v.copyOfRange(1, v.size()),
+                (k, v) -> v.get(0)
             );
 
             System.out.println(">>> Naive Bayes model: " + mdl);
@@ -78,11 +77,11 @@
             // Build confusion matrix. See https://en.wikipedia.org/wiki/Confusion_matrix
             int[][] confusionMtx = {{0, 0}, {0, 0}};
 
-            try (QueryCursor<Cache.Entry<Integer, double[]>> observations = dataCache.query(new ScanQuery<>())) {
-                for (Cache.Entry<Integer, double[]> observation : observations) {
-                    double[] val = observation.getValue();
-                    Vector inputs = VectorUtils.of(Arrays.copyOfRange(val, 1, val.length));
-                    double groundTruth = val[0];
+            try (QueryCursor<Cache.Entry<Integer, Vector>> observations = dataCache.query(new ScanQuery<>())) {
+                for (Cache.Entry<Integer, Vector> observation : observations) {
+                    Vector val = observation.getValue();
+                    Vector inputs = val.copyOfRange(1, val.size());
+                    double groundTruth = val.get(0);
 
                     double prediction = mdl.apply(inputs);
 
diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/regression/logistic/bagged/BaggedLogisticRegressionSGDTrainerExample.java b/examples/src/main/java/org/apache/ignite/examples/ml/regression/logistic/bagged/BaggedLogisticRegressionSGDTrainerExample.java
index baf513a..98745a4 100644
--- a/examples/src/main/java/org/apache/ignite/examples/ml/regression/logistic/bagged/BaggedLogisticRegressionSGDTrainerExample.java
+++ b/examples/src/main/java/org/apache/ignite/examples/ml/regression/logistic/bagged/BaggedLogisticRegressionSGDTrainerExample.java
@@ -30,7 +30,7 @@
 import org.apache.ignite.ml.nn.UpdatesStrategy;
 import org.apache.ignite.ml.optimization.updatecalculators.SimpleGDParameterUpdate;
 import org.apache.ignite.ml.optimization.updatecalculators.SimpleGDUpdateCalculator;
-import org.apache.ignite.ml.regressions.logistic.binomial.LogisticRegressionSGDTrainer;
+import org.apache.ignite.ml.regressions.logistic.LogisticRegressionSGDTrainer;
 import org.apache.ignite.ml.selection.cv.CrossValidation;
 import org.apache.ignite.ml.selection.scoring.metric.Accuracy;
 import org.apache.ignite.ml.trainers.DatasetTrainer;
@@ -81,8 +81,7 @@
                 0.6,
                 4,
                 3,
-                new OnMajorityPredictionsAggregator(),
-                123L);
+                new OnMajorityPredictionsAggregator());
 
             System.out.println(">>> Perform evaluation of the model.");
 
diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/regression/logistic/binary/LogisticRegressionSGDTrainerExample.java b/examples/src/main/java/org/apache/ignite/examples/ml/regression/logistic/binary/LogisticRegressionSGDTrainerExample.java
index 52ee330..8530045 100644
--- a/examples/src/main/java/org/apache/ignite/examples/ml/regression/logistic/binary/LogisticRegressionSGDTrainerExample.java
+++ b/examples/src/main/java/org/apache/ignite/examples/ml/regression/logistic/binary/LogisticRegressionSGDTrainerExample.java
@@ -31,8 +31,8 @@
 import org.apache.ignite.ml.nn.UpdatesStrategy;
 import org.apache.ignite.ml.optimization.updatecalculators.SimpleGDParameterUpdate;
 import org.apache.ignite.ml.optimization.updatecalculators.SimpleGDUpdateCalculator;
-import org.apache.ignite.ml.regressions.logistic.binomial.LogisticRegressionModel;
-import org.apache.ignite.ml.regressions.logistic.binomial.LogisticRegressionSGDTrainer;
+import org.apache.ignite.ml.regressions.logistic.LogisticRegressionModel;
+import org.apache.ignite.ml.regressions.logistic.LogisticRegressionSGDTrainer;
 
 /**
  * Run logistic regression model based on <a href="https://en.wikipedia.org/wiki/Stochastic_gradient_descent">
diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/regression/logistic/multiclass/LogRegressionMultiClassClassificationExample.java b/examples/src/main/java/org/apache/ignite/examples/ml/regression/logistic/multiclass/LogRegressionMultiClassClassificationExample.java
deleted file mode 100644
index 962fdac..0000000
--- a/examples/src/main/java/org/apache/ignite/examples/ml/regression/logistic/multiclass/LogRegressionMultiClassClassificationExample.java
+++ /dev/null
@@ -1,164 +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.examples.ml.regression.logistic.multiclass;
-
-import java.io.FileNotFoundException;
-import java.util.Arrays;
-import javax.cache.Cache;
-import org.apache.ignite.Ignite;
-import org.apache.ignite.IgniteCache;
-import org.apache.ignite.Ignition;
-import org.apache.ignite.cache.query.QueryCursor;
-import org.apache.ignite.cache.query.ScanQuery;
-import org.apache.ignite.examples.ml.util.MLSandboxDatasets;
-import org.apache.ignite.examples.ml.util.SandboxMLCache;
-import org.apache.ignite.ml.math.functions.IgniteBiFunction;
-import org.apache.ignite.ml.math.primitives.vector.Vector;
-import org.apache.ignite.ml.nn.UpdatesStrategy;
-import org.apache.ignite.ml.optimization.updatecalculators.SimpleGDParameterUpdate;
-import org.apache.ignite.ml.optimization.updatecalculators.SimpleGDUpdateCalculator;
-import org.apache.ignite.ml.preprocessing.minmaxscaling.MinMaxScalerTrainer;
-import org.apache.ignite.ml.regressions.logistic.multiclass.LogRegressionMultiClassModel;
-import org.apache.ignite.ml.regressions.logistic.multiclass.LogRegressionMultiClassTrainer;
-
-/**
- * Run Logistic Regression multi-class classification trainer ({@link LogRegressionMultiClassModel}) over distributed
- * dataset to build two models: one with minmaxscaling and one without minmaxscaling.
- * <p>
- * Code in this example launches Ignite grid and fills the cache with test data points (preprocessed
- * <a href="https://archive.ics.uci.edu/ml/datasets/Glass+Identification">Glass dataset</a>).</p>
- * <p>
- * After that it trains two logistic regression models based on the specified data - one model is with minmaxscaling
- * and one without minmaxscaling.</p>
- * <p>
- * Finally, this example loops over the test set of data points, applies the trained models to predict the target value,
- * compares prediction to expected outcome (ground truth), and builds
- * <a href="https://en.wikipedia.org/wiki/Confusion_matrix">confusion matrices</a>.</p>
- * <p>
- * You can change the test data used in this example and re-run it to explore this algorithm further.</p>
- */
-public class LogRegressionMultiClassClassificationExample {
-    /** Run example. */
-    public static void main(String[] args) throws FileNotFoundException {
-        System.out.println();
-        System.out.println(">>> Logistic Regression Multi-class classification model over cached dataset usage example started.");
-        // Start ignite grid.
-        try (Ignite ignite = Ignition.start("examples/config/example-ignite.xml")) {
-            System.out.println(">>> Ignite grid started.");
-
-            IgniteCache<Integer, Vector> dataCache = new SandboxMLCache(ignite)
-                .fillCacheWith(MLSandboxDatasets.GLASS_IDENTIFICATION);
-
-            LogRegressionMultiClassTrainer<?> trainer = new LogRegressionMultiClassTrainer<>()
-                .withUpdatesStgy(new UpdatesStrategy<>(
-                        new SimpleGDUpdateCalculator(0.2),
-                        SimpleGDParameterUpdate::sumLocal,
-                        SimpleGDParameterUpdate::avg
-                    ))
-                .withAmountOfIterations(100000)
-                .withAmountOfLocIterations(10)
-                .withBatchSize(100)
-                .withSeed(123L);
-
-            LogRegressionMultiClassModel mdl = trainer.fit(
-                ignite,
-                dataCache,
-                (k, v) -> v.copyOfRange(1, v.size()),
-                (k, v) -> v.get(0)
-            );
-
-            System.out.println(">>> SVM Multi-class model");
-            System.out.println(mdl.toString());
-
-            MinMaxScalerTrainer<Integer, Vector> normalizationTrainer = new MinMaxScalerTrainer<>();
-
-            IgniteBiFunction<Integer, Vector, Vector> preprocessor = normalizationTrainer.fit(
-                ignite,
-                dataCache,
-                (k, v) -> v.copyOfRange(1, v.size())
-            );
-
-            LogRegressionMultiClassModel mdlWithNormalization = trainer.fit(
-                ignite,
-                dataCache,
-                preprocessor,
-                (k, v) -> v.get(0)
-            );
-
-            System.out.println(">>> Logistic Regression Multi-class model with normalization");
-            System.out.println(mdlWithNormalization.toString());
-
-            System.out.println(">>> ----------------------------------------------------------------");
-            System.out.println(">>> | Prediction\t| Prediction with Normalization\t| Ground Truth\t|");
-            System.out.println(">>> ----------------------------------------------------------------");
-
-            int amountOfErrors = 0;
-            int amountOfErrorsWithNormalization = 0;
-            int totalAmount = 0;
-
-            // Build confusion matrix. See https://en.wikipedia.org/wiki/Confusion_matrix
-            int[][] confusionMtx = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
-            int[][] confusionMtxWithNormalization = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
-
-            try (QueryCursor<Cache.Entry<Integer, Vector>> observations = dataCache.query(new ScanQuery<>())) {
-                for (Cache.Entry<Integer, Vector> observation : observations) {
-                    Vector val = observation.getValue();
-                    Vector inputs = val.copyOfRange(1, val.size());
-                    double groundTruth = val.get(0);
-
-                    double prediction = mdl.apply(inputs);
-                    double predictionWithNormalization = mdlWithNormalization.apply(inputs);
-
-                    totalAmount++;
-
-                    // Collect data for model
-                    if(groundTruth != prediction)
-                        amountOfErrors++;
-
-                    int idx1 = (int)prediction == 1 ? 0 : ((int)prediction == 3 ? 1 : 2);
-                    int idx2 = (int)groundTruth == 1 ? 0 : ((int)groundTruth == 3 ? 1 : 2);
-
-                    confusionMtx[idx1][idx2]++;
-
-                    // Collect data for model with normalization
-                    if(groundTruth != predictionWithNormalization)
-                        amountOfErrorsWithNormalization++;
-
-                    idx1 = (int)predictionWithNormalization == 1 ? 0 : ((int)predictionWithNormalization == 3 ? 1 : 2);
-                    idx2 = (int)groundTruth == 1 ? 0 : ((int)groundTruth == 3 ? 1 : 2);
-
-                    confusionMtxWithNormalization[idx1][idx2]++;
-
-                    System.out.printf(">>> | %.4f\t\t| %.4f\t\t\t\t\t\t| %.4f\t\t|\n", prediction, predictionWithNormalization, groundTruth);
-                }
-                System.out.println(">>> ----------------------------------------------------------------");
-                System.out.println("\n>>> -----------------Logistic Regression model-------------");
-                System.out.println("\n>>> Absolute amount of errors " + amountOfErrors);
-                System.out.println("\n>>> Accuracy " + (1 - amountOfErrors / (double)totalAmount));
-                System.out.println("\n>>> Confusion matrix is " + Arrays.deepToString(confusionMtx));
-
-                System.out.println("\n>>> -----------------Logistic Regression model with Normalization-------------");
-                System.out.println("\n>>> Absolute amount of errors " + amountOfErrorsWithNormalization);
-                System.out.println("\n>>> Accuracy " + (1 - amountOfErrorsWithNormalization / (double)totalAmount));
-                System.out.println("\n>>> Confusion matrix is " + Arrays.deepToString(confusionMtxWithNormalization));
-
-                System.out.println(">>> Logistic Regression Multi-class classification model over cached dataset usage example completed.");
-            }
-        }
-    }
-}
diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/regression/logistic/multiclass/package-info.java b/examples/src/main/java/org/apache/ignite/examples/ml/regression/logistic/multiclass/package-info.java
deleted file mode 100644
index c7b7fe8..0000000
--- a/examples/src/main/java/org/apache/ignite/examples/ml/regression/logistic/multiclass/package-info.java
+++ /dev/null
@@ -1,22 +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 description. -->
- * ML multi-class logistic regression examples.
- */
-package org.apache.ignite.examples.ml.regression.logistic.multiclass;
diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/svm/binary/SVMBinaryClassificationExample.java b/examples/src/main/java/org/apache/ignite/examples/ml/svm/SVMBinaryClassificationExample.java
similarity index 90%
rename from examples/src/main/java/org/apache/ignite/examples/ml/svm/binary/SVMBinaryClassificationExample.java
rename to examples/src/main/java/org/apache/ignite/examples/ml/svm/SVMBinaryClassificationExample.java
index 679bd77..d9d1805 100644
--- a/examples/src/main/java/org/apache/ignite/examples/ml/svm/binary/SVMBinaryClassificationExample.java
+++ b/examples/src/main/java/org/apache/ignite/examples/ml/svm/SVMBinaryClassificationExample.java
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package org.apache.ignite.examples.ml.svm.binary;
+package org.apache.ignite.examples.ml.svm;
 
 import java.io.FileNotFoundException;
 import java.util.Arrays;
@@ -28,11 +28,11 @@
 import org.apache.ignite.examples.ml.util.MLSandboxDatasets;
 import org.apache.ignite.examples.ml.util.SandboxMLCache;
 import org.apache.ignite.ml.math.primitives.vector.Vector;
-import org.apache.ignite.ml.svm.SVMLinearBinaryClassificationModel;
-import org.apache.ignite.ml.svm.SVMLinearBinaryClassificationTrainer;
+import org.apache.ignite.ml.svm.SVMLinearClassificationModel;
+import org.apache.ignite.ml.svm.SVMLinearClassificationTrainer;
 
 /**
- * Run SVM binary-class classification model ({@link SVMLinearBinaryClassificationModel}) over distributed dataset.
+ * Run SVM binary-class classification model ({@link SVMLinearClassificationModel}) over distributed dataset.
  * <p>
  * Code in this example launches Ignite grid and fills the cache with test data points (based on the
  * <a href="https://en.wikipedia.org/wiki/Iris_flower_data_set"></a>Iris dataset</a>).</p>
@@ -57,9 +57,9 @@
             IgniteCache<Integer, Vector> dataCache = new SandboxMLCache(ignite)
                 .fillCacheWith(MLSandboxDatasets.TWO_CLASSED_IRIS);
 
-            SVMLinearBinaryClassificationTrainer trainer = new SVMLinearBinaryClassificationTrainer();
+            SVMLinearClassificationTrainer trainer = new SVMLinearClassificationTrainer();
 
-            SVMLinearBinaryClassificationModel mdl = trainer.fit(
+            SVMLinearClassificationModel mdl = trainer.fit(
                 ignite,
                 dataCache,
                 (k, v) -> v.copyOfRange(1, v.size()),
diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/svm/binary/package-info.java b/examples/src/main/java/org/apache/ignite/examples/ml/svm/binary/package-info.java
deleted file mode 100644
index 22c9ad7..0000000
--- a/examples/src/main/java/org/apache/ignite/examples/ml/svm/binary/package-info.java
+++ /dev/null
@@ -1,22 +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 description. -->
- * SVM Binary Classification Examples.
- */
-package org.apache.ignite.examples.ml.svm.binary;
\ No newline at end of file
diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/svm/multiclass/SVMMultiClassClassificationExample.java b/examples/src/main/java/org/apache/ignite/examples/ml/svm/multiclass/SVMMultiClassClassificationExample.java
deleted file mode 100644
index 987ac41..0000000
--- a/examples/src/main/java/org/apache/ignite/examples/ml/svm/multiclass/SVMMultiClassClassificationExample.java
+++ /dev/null
@@ -1,153 +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.examples.ml.svm.multiclass;
-
-import java.io.FileNotFoundException;
-import java.util.Arrays;
-import javax.cache.Cache;
-import org.apache.ignite.Ignite;
-import org.apache.ignite.IgniteCache;
-import org.apache.ignite.Ignition;
-import org.apache.ignite.cache.query.QueryCursor;
-import org.apache.ignite.cache.query.ScanQuery;
-import org.apache.ignite.examples.ml.util.MLSandboxDatasets;
-import org.apache.ignite.examples.ml.util.SandboxMLCache;
-import org.apache.ignite.ml.math.functions.IgniteBiFunction;
-import org.apache.ignite.ml.math.primitives.vector.Vector;
-import org.apache.ignite.ml.preprocessing.minmaxscaling.MinMaxScalerTrainer;
-import org.apache.ignite.ml.svm.SVMLinearMultiClassClassificationModel;
-import org.apache.ignite.ml.svm.SVMLinearMultiClassClassificationTrainer;
-
-/**
- * Run SVM multi-class classification trainer ({@link SVMLinearMultiClassClassificationModel}) over distributed dataset
- * to build two models: one with minmaxscaling and one without minmaxscaling.
- * <p>
- * Code in this example launches Ignite grid and fills the cache with test data points (preprocessed
- * <a href="https://archive.ics.uci.edu/ml/datasets/Glass+Identification">Glass dataset</a>).</p>
- * <p>
- * After that it trains two SVM multi-class models based on the specified data - one model is with minmaxscaling
- * and one without minmaxscaling.</p>
- * <p>
- * Finally, this example loops over the test set of data points, applies the trained models to predict what cluster
- * does this point belong to, compares prediction to expected outcome (ground truth), and builds
- * <a href="https://en.wikipedia.org/wiki/Confusion_matrix">confusion matrix</a>.</p>
- * <p>
- * You can change the test data used in this example and re-run it to explore this algorithm further.</p>
- * NOTE: the smallest 3rd class could be classified via linear SVM here.
- */
-public class SVMMultiClassClassificationExample {
-    /** Run example. */
-    public static void main(String[] args) throws FileNotFoundException {
-        System.out.println();
-        System.out.println(">>> SVM Multi-class classification model over cached dataset usage example started.");
-        // Start ignite grid.
-        try (Ignite ignite = Ignition.start("examples/config/example-ignite.xml")) {
-            System.out.println(">>> Ignite grid started.");
-
-            IgniteCache<Integer, Vector> dataCache = new SandboxMLCache(ignite)
-                .fillCacheWith(MLSandboxDatasets.GLASS_IDENTIFICATION);
-
-            SVMLinearMultiClassClassificationTrainer trainer = new SVMLinearMultiClassClassificationTrainer();
-
-            SVMLinearMultiClassClassificationModel mdl = trainer.fit(
-                ignite,
-                dataCache,
-                (k, v) -> v.copyOfRange(1, v.size()),
-                (k, v) -> v.get(0)
-            );
-
-            System.out.println(">>> SVM Multi-class model");
-            System.out.println(mdl.toString());
-
-            MinMaxScalerTrainer<Integer, Vector> minMaxScalerTrainer = new MinMaxScalerTrainer<>();
-
-            IgniteBiFunction<Integer, Vector, Vector> preprocessor = minMaxScalerTrainer.fit(
-                ignite,
-                dataCache,
-                (k, v) -> v.copyOfRange(1, v.size())
-            );
-
-            SVMLinearMultiClassClassificationModel mdlWithScaling = trainer.fit(
-                ignite,
-                dataCache,
-                preprocessor,
-                (k, v) -> v.get(0)
-            );
-
-            System.out.println(">>> SVM Multi-class model with MinMaxScaling");
-            System.out.println(mdlWithScaling.toString());
-
-            System.out.println(">>> ----------------------------------------------------------------");
-            System.out.println(">>> | Prediction\t| Prediction with MinMaxScaling\t| Ground Truth\t|");
-            System.out.println(">>> ----------------------------------------------------------------");
-
-            int amountOfErrors = 0;
-            int amountOfErrorsWithMinMaxScaling = 0;
-            int totalAmount = 0;
-
-            // Build confusion matrix. See https://en.wikipedia.org/wiki/Confusion_matrix
-            int[][] confusionMtx = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
-            int[][] confusionMtxWithMinMaxScaling = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
-
-            try (QueryCursor<Cache.Entry<Integer, Vector>> observations = dataCache.query(new ScanQuery<>())) {
-                for (Cache.Entry<Integer, Vector> observation : observations) {
-                    Vector val = observation.getValue();
-                    Vector inputs = val.copyOfRange(1, val.size());
-                    double groundTruth = val.get(0);
-
-                    double prediction = mdl.apply(inputs);
-                    double predictionWithMinMaxScaling = mdlWithScaling.apply(inputs);
-
-                    totalAmount++;
-
-                    // Collect data for model
-                    if(groundTruth != prediction)
-                        amountOfErrors++;
-
-                    int idx1 = (int)prediction == 1 ? 0 : ((int)prediction == 3 ? 1 : 2);
-                    int idx2 = (int)groundTruth == 1 ? 0 : ((int)groundTruth == 3 ? 1 : 2);
-
-                    confusionMtx[idx1][idx2]++;
-
-                    // Collect data for model with minmaxscaling
-                    if (groundTruth != predictionWithMinMaxScaling)
-                        amountOfErrorsWithMinMaxScaling++;
-
-                    idx1 = (int)predictionWithMinMaxScaling == 1 ? 0 : ((int)predictionWithMinMaxScaling == 3 ? 1 : 2);
-                    idx2 = (int)groundTruth == 1 ? 0 : ((int)groundTruth == 3 ? 1 : 2);
-
-                    confusionMtxWithMinMaxScaling[idx1][idx2]++;
-
-                    System.out.printf(">>> | %.4f\t\t| %.4f\t\t\t\t\t\t| %.4f\t\t|\n", prediction, predictionWithMinMaxScaling, groundTruth);
-                }
-                System.out.println(">>> ----------------------------------------------------------------");
-                System.out.println("\n>>> -----------------SVM model-------------");
-                System.out.println("\n>>> Absolute amount of errors " + amountOfErrors);
-                System.out.println("\n>>> Accuracy " + (1 - amountOfErrors / (double)totalAmount));
-                System.out.println("\n>>> Confusion matrix is " + Arrays.deepToString(confusionMtx));
-
-                System.out.println("\n>>> -----------------SVM model with MinMaxScaling-------------");
-                System.out.println("\n>>> Absolute amount of errors " + amountOfErrorsWithMinMaxScaling);
-                System.out.println("\n>>> Accuracy " + (1 - amountOfErrorsWithMinMaxScaling / (double)totalAmount));
-                System.out.println("\n>>> Confusion matrix is " + Arrays.deepToString(confusionMtxWithMinMaxScaling));
-
-                System.out.println(">>> Linear regression model over cache based dataset usage example completed.");
-            }
-        }
-    }
-}
diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/svm/multiclass/package-info.java b/examples/src/main/java/org/apache/ignite/examples/ml/svm/multiclass/package-info.java
deleted file mode 100644
index 8b685a4..0000000
--- a/examples/src/main/java/org/apache/ignite/examples/ml/svm/multiclass/package-info.java
+++ /dev/null
@@ -1,22 +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 description. -->
- * SVM Multi-class Classification Examples.
- */
-package org.apache.ignite.examples.ml.svm.multiclass;
diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/tree/randomforest/RandomForestRegressionExample.java b/examples/src/main/java/org/apache/ignite/examples/ml/tree/randomforest/RandomForestRegressionExample.java
index 3bf2c8e..a3c33cb 100644
--- a/examples/src/main/java/org/apache/ignite/examples/ml/tree/randomforest/RandomForestRegressionExample.java
+++ b/examples/src/main/java/org/apache/ignite/examples/ml/tree/randomforest/RandomForestRegressionExample.java
@@ -31,7 +31,7 @@
 import org.apache.ignite.examples.ml.util.SandboxMLCache;
 import org.apache.ignite.ml.composition.ModelsComposition;
 import org.apache.ignite.ml.dataset.feature.FeatureMeta;
-import org.apache.ignite.ml.environment.LearningEnvironment;
+import org.apache.ignite.ml.environment.LearningEnvironmentBuilder;
 import org.apache.ignite.ml.environment.logging.ConsoleLogger;
 import org.apache.ignite.ml.environment.logging.MLLogger;
 import org.apache.ignite.ml.environment.parallelism.ParallelismStrategy;
@@ -80,10 +80,9 @@
                 .withSubSampleSize(0.3)
                 .withSeed(0);
 
-            trainer.setEnvironment(LearningEnvironment.builder()
-                .withParallelismStrategy(ParallelismStrategy.Type.ON_DEFAULT_POOL)
-                .withLoggingFactory(ConsoleLogger.factory(MLLogger.VerboseLevel.LOW))
-                .build()
+            trainer.withEnvironmentBuilder(LearningEnvironmentBuilder.defaultBuilder()
+                .withParallelismStrategyTypeDependency(part -> ParallelismStrategy.Type.ON_DEFAULT_POOL)
+                .withLoggingFactoryDependency(part -> ConsoleLogger.factory(MLLogger.VerboseLevel.LOW))
             );
 
             System.out.println(">>> Configured trainer: " + trainer.getClass().getSimpleName());
diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/tutorial/Step_9_Go_to_LogReg.java b/examples/src/main/java/org/apache/ignite/examples/ml/tutorial/Step_9_Go_to_LogReg.java
index b98b0eb..2c6a820 100644
--- a/examples/src/main/java/org/apache/ignite/examples/ml/tutorial/Step_9_Go_to_LogReg.java
+++ b/examples/src/main/java/org/apache/ignite/examples/ml/tutorial/Step_9_Go_to_LogReg.java
@@ -32,8 +32,8 @@
 import org.apache.ignite.ml.preprocessing.imputing.ImputerTrainer;
 import org.apache.ignite.ml.preprocessing.minmaxscaling.MinMaxScalerTrainer;
 import org.apache.ignite.ml.preprocessing.normalization.NormalizationTrainer;
-import org.apache.ignite.ml.regressions.logistic.binomial.LogisticRegressionModel;
-import org.apache.ignite.ml.regressions.logistic.binomial.LogisticRegressionSGDTrainer;
+import org.apache.ignite.ml.regressions.logistic.LogisticRegressionModel;
+import org.apache.ignite.ml.regressions.logistic.LogisticRegressionSGDTrainer;
 import org.apache.ignite.ml.selection.cv.CrossValidation;
 import org.apache.ignite.ml.selection.scoring.evaluator.Evaluator;
 import org.apache.ignite.ml.selection.scoring.metric.Accuracy;
diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/util/SandboxMLCache.java b/examples/src/main/java/org/apache/ignite/examples/ml/util/SandboxMLCache.java
index a8431de..20b22ef 100644
--- a/examples/src/main/java/org/apache/ignite/examples/ml/util/SandboxMLCache.java
+++ b/examples/src/main/java/org/apache/ignite/examples/ml/util/SandboxMLCache.java
@@ -69,25 +69,6 @@
     /**
      * Fills cache with data and returns it.
      *
-     * @param data Data to fill the cache with.
-     * @return Filled Ignite Cache.
-     */
-    public IgniteCache<Integer, Vector> getVectors(double[][] data) {
-        CacheConfiguration<Integer, Vector> cacheConfiguration = new CacheConfiguration<>();
-        cacheConfiguration.setName("TEST_" + UUID.randomUUID());
-        cacheConfiguration.setAffinity(new RendezvousAffinityFunction(false, 10));
-
-        IgniteCache<Integer, Vector> cache = ignite.createCache(cacheConfiguration);
-
-        for (int i = 0; i < data.length; i++)
-            cache.put(i, VectorUtils.of(data[i]));
-
-        return cache;
-    }
-
-    /**
-     * Fills cache with data and returns it.
-     *
      * @param dataset The chosen dataset.
      * @return Filled Ignite Cache.
      * @throws FileNotFoundException If file not found.
diff --git a/examples/src/main/java/org/apache/ignite/examples/util/IrisDataset.java b/examples/src/main/java/org/apache/ignite/examples/util/IrisDataset.java
deleted file mode 100644
index 53080e8..0000000
--- a/examples/src/main/java/org/apache/ignite/examples/util/IrisDataset.java
+++ /dev/null
@@ -1,129 +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.examples.util;
-
-/** Contains data from the <a href="https://en.wikipedia.org/wiki/Iris_flower_data_set"></a>Iris dataset</a>. */
-public final class IrisDataset {
-
-    /** The 1st and 2nd classes from the Iris dataset. */
-    public static final double[][] irisDatasetFirstAndSecondClasses = {
-        {0, 5.1, 3.5, 1.4, 0.2},
-        {0, 4.9, 3, 1.4, 0.2},
-        {0, 4.7, 3.2, 1.3, 0.2},
-        {0, 4.6, 3.1, 1.5, 0.2},
-        {0, 5, 3.6, 1.4, 0.2},
-        {0, 5.4, 3.9, 1.7, 0.4},
-        {0, 4.6, 3.4, 1.4, 0.3},
-        {0, 5, 3.4, 1.5, 0.2},
-        {0, 4.4, 2.9, 1.4, 0.2},
-        {0, 4.9, 3.1, 1.5, 0.1},
-        {0, 5.4, 3.7, 1.5, 0.2},
-        {0, 4.8, 3.4, 1.6, 0.2},
-        {0, 4.8, 3, 1.4, 0.1},
-        {0, 4.3, 3, 1.1, 0.1},
-        {0, 5.8, 4, 1.2, 0.2},
-        {0, 5.7, 4.4, 1.5, 0.4},
-        {0, 5.4, 3.9, 1.3, 0.4},
-        {0, 5.1, 3.5, 1.4, 0.3},
-        {0, 5.7, 3.8, 1.7, 0.3},
-        {0, 5.1, 3.8, 1.5, 0.3},
-        {0, 5.4, 3.4, 1.7, 0.2},
-        {0, 5.1, 3.7, 1.5, 0.4},
-        {0, 4.6, 3.6, 1, 0.2},
-        {0, 5.1, 3.3, 1.7, 0.5},
-        {0, 4.8, 3.4, 1.9, 0.2},
-        {0, 5, 3, 1.6, 0.2},
-        {0, 5, 3.4, 1.6, 0.4},
-        {0, 5.2, 3.5, 1.5, 0.2},
-        {0, 5.2, 3.4, 1.4, 0.2},
-        {0, 4.7, 3.2, 1.6, 0.2},
-        {0, 4.8, 3.1, 1.6, 0.2},
-        {0, 5.4, 3.4, 1.5, 0.4},
-        {0, 5.2, 4.1, 1.5, 0.1},
-        {0, 5.5, 4.2, 1.4, 0.2},
-        {0, 4.9, 3.1, 1.5, 0.1},
-        {0, 5, 3.2, 1.2, 0.2},
-        {0, 5.5, 3.5, 1.3, 0.2},
-        {0, 4.9, 3.1, 1.5, 0.1},
-        {0, 4.4, 3, 1.3, 0.2},
-        {0, 5.1, 3.4, 1.5, 0.2},
-        {0, 5, 3.5, 1.3, 0.3},
-        {0, 4.5, 2.3, 1.3, 0.3},
-        {0, 4.4, 3.2, 1.3, 0.2},
-        {0, 5, 3.5, 1.6, 0.6},
-        {0, 5.1, 3.8, 1.9, 0.4},
-        {0, 4.8, 3, 1.4, 0.3},
-        {0, 5.1, 3.8, 1.6, 0.2},
-        {0, 4.6, 3.2, 1.4, 0.2},
-        {0, 5.3, 3.7, 1.5, 0.2},
-        {0, 5, 3.3, 1.4, 0.2},
-        {1, 7, 3.2, 4.7, 1.4},
-        {1, 6.4, 3.2, 4.5, 1.5},
-        {1, 6.9, 3.1, 4.9, 1.5},
-        {1, 5.5, 2.3, 4, 1.3},
-        {1, 6.5, 2.8, 4.6, 1.5},
-        {1, 5.7, 2.8, 4.5, 1.3},
-        {1, 6.3, 3.3, 4.7, 1.6},
-        {1, 4.9, 2.4, 3.3, 1},
-        {1, 6.6, 2.9, 4.6, 1.3},
-        {1, 5.2, 2.7, 3.9, 1.4},
-        {1, 5, 2, 3.5, 1},
-        {1, 5.9, 3, 4.2, 1.5},
-        {1, 6, 2.2, 4, 1},
-        {1, 6.1, 2.9, 4.7, 1.4},
-        {1, 5.6, 2.9, 3.6, 1.3},
-        {1, 6.7, 3.1, 4.4, 1.4},
-        {1, 5.6, 3, 4.5, 1.5},
-        {1, 5.8, 2.7, 4.1, 1},
-        {1, 6.2, 2.2, 4.5, 1.5},
-        {1, 5.6, 2.5, 3.9, 1.1},
-        {1, 5.9, 3.2, 4.8, 1.8},
-        {1, 6.1, 2.8, 4, 1.3},
-        {1, 6.3, 2.5, 4.9, 1.5},
-        {1, 6.1, 2.8, 4.7, 1.2},
-        {1, 6.4, 2.9, 4.3, 1.3},
-        {1, 6.6, 3, 4.4, 1.4},
-        {1, 6.8, 2.8, 4.8, 1.4},
-        {1, 6.7, 3, 5, 1.7},
-        {1, 6, 2.9, 4.5, 1.5},
-        {1, 5.7, 2.6, 3.5, 1},
-        {1, 5.5, 2.4, 3.8, 1.1},
-        {1, 5.5, 2.4, 3.7, 1},
-        {1, 5.8, 2.7, 3.9, 1.2},
-        {1, 6, 2.7, 5.1, 1.6},
-        {1, 5.4, 3, 4.5, 1.5},
-        {1, 6, 3.4, 4.5, 1.6},
-        {1, 6.7, 3.1, 4.7, 1.5},
-        {1, 6.3, 2.3, 4.4, 1.3},
-        {1, 5.6, 3, 4.1, 1.3},
-        {1, 5.5, 2.5, 4, 1.3},
-        {1, 5.5, 2.6, 4.4, 1.2},
-        {1, 6.1, 3, 4.6, 1.4},
-        {1, 5.8, 2.6, 4, 1.2},
-        {1, 5, 2.3, 3.3, 1},
-        {1, 5.6, 2.7, 4.2, 1.3},
-        {1, 5.7, 3, 4.2, 1.2},
-        {1, 5.7, 2.9, 4.2, 1.3},
-        {1, 6.2, 2.9, 4.3, 1.3},
-        {1, 5.1, 2.5, 3, 1.1},
-        {1, 5.7, 2.8, 4.1, 1.3},
-    };
-
-    /** */
-    private IrisDataset() {
-    }
-}
diff --git a/idea/ignite_inspections.xml b/idea/ignite_inspections.xml
deleted file mode 100644
index 9695fca..0000000
--- a/idea/ignite_inspections.xml
+++ /dev/null
@@ -1,772 +0,0 @@
-<profile version="1.0">
-  <option name="myName" value="ignite_inspections" />
-  <inspection_tool class="AbstractMethodCallInConstructor" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="AccessorLikeMethodIsEmptyParen" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AccessorLikeMethodIsUnit" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintAddJavascriptInterface" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintAllowAllHostnameVerifier" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintAlwaysShowAction" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintAppCompatMethod" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintAuthLeak" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintBadHostnameVerifier" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintBatteryLife" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintCommitPrefEdits" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintCommitTransaction" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintCustomViewStyleable" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintCutPasteId" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintDefaultLocale" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintDrawAllocation" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintExportedContentProvider" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintExportedPreferenceActivity" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintExportedReceiver" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintExportedService" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintFloatMath" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintGetInstance" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintGifUsage" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintGoogleAppIndexingUrlError" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintGoogleAppIndexingWarning" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintGrantAllUris" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintHandlerLeak" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintIconColors" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintIconDensities" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintIconDipSize" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintIconDuplicates" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintIconDuplicatesConfig" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintIconExtension" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintIconLauncherShape" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintIconLocation" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintIconMissingDensityFolder" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintIconMixedNinePatch" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintIconNoDpi" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintIconXmlAndPng" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintInconsistentLayout" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintInflateParams" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintInlinedApi" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintInvalidUsesTagAttribute" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintJavascriptInterface" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintLocalSuppress" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintLogTagMismatch" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintLongLogTag" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintMergeRootFrame" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintMissingIntentFilterForMediaSearch" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintMissingMediaBrowserServiceIntentFilter" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintMissingOnPlayFromSearch" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintMissingSuperCall" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintNewApi" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintOverdraw" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintOverride" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintOverrideAbstract" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintPackageManagerGetSignatures" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintParcelClassLoader" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintParcelCreator" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintPendingBindings" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintPluralsCandidate" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintPrivateResource" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintRecycle" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintRecyclerView" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintRegistered" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintRequiredSize" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintRtlCompat" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintRtlEnabled" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintRtlHardcoded" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintRtlSymmetry" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintSQLiteString" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintSSLCertificateSocketFactoryCreateSocket" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintSSLCertificateSocketFactoryGetInsecure" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintSdCardPath" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintSecureRandom" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintServiceCast" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintSetJavaScriptEnabled" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintSetTextI18n" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintSetWorldReadable" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintSetWorldWritable" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintShiftFlags" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintShortAlarm" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintShowToast" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintSimpleDateFormat" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintStringFormatCount" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintStringFormatInvalid" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintStringFormatMatches" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintSupportAnnotationUsage" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintSuspiciousImport" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintSwitchIntDef" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintTrustAllX509TrustManager" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintUniqueConstants" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintUnlocalizedSms" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintUnprotectedSMSBroadcastReceiver" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintUnsafeDynamicallyLoadedCode" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintUnsafeNativeCodeLocation" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintUnsafeProtectedBroadcastReceiver" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintUnusedAttribute" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintUseSparseArrays" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintUseValueOf" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintValidFragment" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintViewConstructor" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintViewHolder" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintViewTag" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintWorldReadableFiles" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintWorldWriteableFiles" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintWrongCall" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidKLintWrongViewCast" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintAaptCrash" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintAccidentalOctal" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintAdapterViewChildren" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintAddJavascriptInterface" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintAllowAllHostnameVerifier" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintAllowBackup" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintAlwaysShowAction" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintAppCompatMethod" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintAppCompatResource" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintAssert" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintAuthLeak" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintBadHostnameVerifier" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintBatteryLife" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintButtonCase" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintButtonOrder" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintButtonStyle" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintByteOrderMark" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintCommitPrefEdits" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintCommitTransaction" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintContentDescription" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintCustomViewStyleable" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintCutPasteId" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintDefaultLocale" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintDeprecated" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintDeviceAdmin" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintDisableBaselineAlignment" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintDrawAllocation" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintDuplicateActivity" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintDuplicateDefinition" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintDuplicateIds" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintDuplicateIncludedIds" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintDuplicateUsesFeature" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintEnforceUTF8" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintExportedContentProvider" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintExportedPreferenceActivity" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintExportedReceiver" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintExportedService" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintExtraText" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintExtraTranslation" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintFloatMath" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintFullBackupContent" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintGetInstance" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintGifUsage" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintGoogleAppIndexingUrlError" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintGoogleAppIndexingWarning" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintGradleCompatible" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintGradleDependency" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintGradleDeprecated" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintGradleDynamicVersion" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintGradleGetter" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintGradleIdeError" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintGradleOverrides" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintGradlePath" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintGradlePluginVersion" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintGrantAllUris" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintGridLayout" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintHandlerLeak" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintHardcodedDebugMode" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintHardcodedText" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintHardwareIds" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintIconColors" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintIconDensities" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintIconDipSize" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintIconDuplicates" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintIconDuplicatesConfig" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintIconExtension" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintIconLauncherShape" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintIconLocation" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintIconMissingDensityFolder" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintIconMixedNinePatch" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintIconNoDpi" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintIconXmlAndPng" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintIllegalResourceRef" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintImpliedQuantity" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintInOrMmUsage" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintIncludeLayoutParam" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintInconsistentArrays" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintInconsistentLayout" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintInefficientWeight" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintInflateParams" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintInlinedApi" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintInnerclassSeparator" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintInvalidId" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintInvalidResourceFolder" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintInvalidUsesTagAttribute" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintJavascriptInterface" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintLabelFor" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintLibraryCustomView" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintLocalSuppress" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintLocaleFolder" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintLogTagMismatch" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintLongLogTag" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintManifestOrder" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintManifestResource" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintMenuTitle" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintMergeRootFrame" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintMipmapIcons" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintMissingApplicationIcon" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintMissingConstraints" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintMissingId" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintMissingIntentFilterForMediaSearch" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintMissingLeanbackLauncher" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintMissingLeanbackSupport" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintMissingMediaBrowserServiceIntentFilter" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintMissingOnPlayFromSearch" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintMissingPrefix" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintMissingQuantity" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintMissingSuperCall" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintMissingTranslation" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintMissingTvBanner" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintMissingVersion" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintMockLocation" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintMultipleUsesSdk" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintNestedScrolling" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintNestedWeights" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintNewApi" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintNfcTechWhitespace" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintNotInterpolated" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintNotSibling" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintObsoleteLayoutParam" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintOldTargetApi" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintOrientation" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintOverdraw" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintOverride" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintOverrideAbstract" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintPackageManagerGetSignatures" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintPackagedPrivateKey" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintParcelClassLoader" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintParcelCreator" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintPendingBindings" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintPermissionImpliesUnsupportedHardware" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintPluralsCandidate" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintPrivateResource" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintProguard" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintProguardSplit" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintPropertyEscape" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintProtectedPermissions" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintPxUsage" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintRecycle" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintRecyclerView" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintReferenceType" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintRegistered" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintRelativeOverlap" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintRequiredSize" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintResAuto" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintResourceCycle" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintResourceName" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintRtlCompat" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintRtlEnabled" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintRtlHardcoded" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintRtlSymmetry" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintSQLiteString" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintSSLCertificateSocketFactoryCreateSocket" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintSSLCertificateSocketFactoryGetInsecure" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintScrollViewCount" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintScrollViewSize" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintSdCardPath" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintSecureRandom" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintServiceCast" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintSetJavaScriptEnabled" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintSetTextI18n" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintSetWorldReadable" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintSetWorldWritable" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintShiftFlags" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintShortAlarm" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintShowToast" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintSignatureOrSystemPermissions" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintSimpleDateFormat" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintSmallSp" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintSpUsage" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintStateListReachable" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintStaticFieldLeak" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintStringFormatCount" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintStringFormatInvalid" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintStringFormatMatches" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintStringShouldBeInt" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintSupportAnnotationUsage" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintSuspicious0dp" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintSuspiciousImport" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintSwitchIntDef" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintTextFields" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintTextViewEdits" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintTooDeepLayout" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintTooManyViews" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintTrustAllX509TrustManager" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintTypographyDashes" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintTypographyEllipsis" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintTypographyFractions" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintTypographyOther" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintTypos" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintUniqueConstants" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintUniquePermission" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintUnknownId" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintUnknownIdInLayout" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintUnlocalizedSms" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintUnprotectedSMSBroadcastReceiver" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintUnsafeDynamicallyLoadedCode" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintUnsafeNativeCodeLocation" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintUnsafeProtectedBroadcastReceiver" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintUnsupportedTvHardware" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintUnusedAttribute" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintUnusedQuantity" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintUnusedResources" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintUseAlpha2" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintUseCompoundDrawables" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintUseSparseArrays" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintUseValueOf" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintUselessLeaf" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintUselessParent" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintUsesMinSdkAttributes" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintUsingHttp" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintValidFragment" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintValidRestrictions" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintVectorDrawableCompat" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintVectorRaster" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintViewConstructor" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintViewHolder" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintViewTag" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintWearableBindListener" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintWebViewLayout" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintWorldReadableFiles" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintWorldWriteableFiles" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintWrongCall" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintWrongCase" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintWrongFolder" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintWrongRegion" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AndroidLintWrongViewCast" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AntDuplicateTargetsInspection" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AntMissingPropertiesFileInspection" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="AntResolveInspection" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="ApparentRefinementOfResultType" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="AppliedTypeLambdaCanBeSimplified" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="ArrayCreationWithoutNewKeyword" enabled="false" level="INFORMATION" enabled_by_default="false" />
-  <inspection_tool class="AssertAsName" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="AssignmentToCatchBlockParameter" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="AssignmentToDateFieldFromParameter" enabled="true" level="WARNING" enabled_by_default="true">
-    <option name="ignorePrivateMethods" value="true" />
-  </inspection_tool>
-  <inspection_tool class="BadOddness" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="BigDecimalEquals" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="BooleanMethodIsAlwaysInverted" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="BreakStatementWithLabel" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="BusyWait" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="CStyleArrayDeclaration" enabled="false" level="INFORMATION" enabled_by_default="false" />
-  <inspection_tool class="CallToStringConcatCanBeReplacedByOperator" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="CaseClassParam" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="ChainedPackage" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="ClassMayBeInterface" enabled="false" level="INFORMATION" enabled_by_default="false" />
-  <inspection_tool class="ClassNameDiffersFromFileName" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="ClassNameSameAsAncestorName" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="CloneCallsConstructors" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="CloneInNonCloneableClass" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="CloneableImplementsClone" enabled="true" level="WARNING" enabled_by_default="true">
-    <option name="m_ignoreCloneableDueToInheritance" value="true" />
-  </inspection_tool>
-  <inspection_tool class="CollectionContainsUrl" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="CollectionsFieldAccessReplaceableByMethodCall" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="ComparableImplementedButEqualsNotOverridden" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="ComparatorNotSerializable" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="ComparingDiffCollectionKinds" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="ComparingUnrelatedTypes" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="ComparisonOfShortAndChar" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="ComparisonToNaN" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="ConditionSignal" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="ConstantConditions" enabled="false" level="WARNING" enabled_by_default="false">
-    <option name="SUGGEST_NULLABLE_ANNOTATIONS" value="true" />
-    <option name="DONT_REPORT_TRUE_ASSERT_STATEMENTS" value="true" />
-  </inspection_tool>
-  <inspection_tool class="ConstantValueVariableUse" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="ContinueStatementWithLabel" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="ControlFlowStatementWithoutBraces" enabled="false" level="INFORMATION" enabled_by_default="false" />
-  <inspection_tool class="Convert2Lambda" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="ConvertExpressionToSAM" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="ConvertNullInitializerToUnderscore" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="ConvertibleToMethodValue" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="CorrespondsUnsorted" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="CovariantCompareTo" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="CovariantEquals" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="DangerousCatchAll" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="DanglingJavadoc" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="DefaultNotLastCaseInSwitch" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="DeprecatedIsStillUsed" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="DeprecatedViewBound" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="DialogTitleCapitalization" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="DivideByZero" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="DollarSignInName" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="DottyDeprecatedWith" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="DropTakeToSlice" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="DuplicateBooleanBranch" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="DuplicateCondition" enabled="false" level="WARNING" enabled_by_default="false">
-    <option name="ignoreMethodCalls" value="false" />
-  </inspection_tool>
-  <inspection_tool class="DuplicateThrows" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="EmptyCheck" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="EmptyInitializer" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="EmptyParenMethodAccessedAsParameterless" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="EmptyParenMethodOverridenAsParameterless" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="EmptySynchronizedStatement" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="EnumAsName" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="EnumSwitchStatementWhichMissesCases" enabled="true" level="WARNING" enabled_by_default="true">
-    <option name="ignoreSwitchStatementsWithDefault" value="true" />
-  </inspection_tool>
-  <inspection_tool class="EqualityToSameElements" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="EqualsCalledOnEnumConstant" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="EqualsHashCodeCalledOnUrl" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="EqualsWhichDoesntCheckParameterClass" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="ErrorRethrown" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="ExceptionNameDoesntEndWithException" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="ExistsEquals" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="ExtendsUtilityClass" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="ExternalizableWithSerializationMethods" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="FieldAccessedSynchronizedAndUnsynchronized" enabled="true" level="WARNING" enabled_by_default="true">
-    <option name="countGettersAndSetters" value="false" />
-  </inspection_tool>
-  <inspection_tool class="FieldCanBeLocal" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="FieldFromDelayedInit" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="FieldMayBeStatic" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="FilterEmptyCheck" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="FilterHeadOption" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="FilterOtherContains" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="FilterSize" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="FinalizeNotProtected" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="FindAndMapToApply" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="FindEmptyCheck" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="FloatLiteralEndingWithDecimalPoint" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="FloatingPointEquality" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="FoldTrueAnd" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="ForCanBeForeach" enabled="false" level="WARNING" enabled_by_default="false">
-    <option name="REPORT_INDEXED_LOOP" value="true" />
-    <option name="ignoreUntypedCollections" value="false" />
-  </inspection_tool>
-  <inspection_tool class="ForwardReference" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="FunctionTupleSyntacticSugar" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="GetGetOrElse" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="GetOrElseNull" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="HashCodeUsesVar" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
-  <inspection_tool class="HeadOrLastOption" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="HoconIncludeResolution" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="HtmlPresentationalElement" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="IfElseToOption" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="IfMayBeConditional" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="IfStatementWithIdenticalBranches" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="IgnoreResultOfCall" enabled="false" level="WARNING" enabled_by_default="false">
-    <option name="m_reportAllNonLibraryCalls" value="false" />
-    <option name="callCheckString" value="java.io.InputStream,read,java.io.InputStream,skip,java.lang.StringBuffer,toString,java.lang.StringBuilder,toString,java.lang.String,.*,java.math.BigInteger,.*,java.math.BigDecimal,.*,java.net.InetAddress,.*,java.io.File,.*,java.lang.Object,equals|hashCode" />
-  </inspection_tool>
-  <inspection_tool class="InjectionNotApplicable" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="InnerClassMayBeStatic" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="InstanceofThis" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="IntLiteralMayBeLongLiteral" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="IntegerDivisionInFloatingPointContext" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="IteratorHasNextCallsIteratorNext" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="IteratorNextDoesNotThrowNoSuchElementException" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="JavaAccessorMethodCalledAsEmptyParen" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="JavaAccessorMethodOverridenAsEmptyParen" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="JavaFxColorRgb" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="JavaFxDefaultTag" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="JavaFxEventHandler" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="JavaFxRedundantPropertyValue" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="JavaFxResourcePropertyValue" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="JavaFxUnresolvedFxIdReference" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="JavaFxUnusedImports" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="JavaLangImport" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="JavaMutatorMethodAccessedAsParameterless" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="JavaMutatorMethodOverridenAsParameterless" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="JsonDuplicatePropertyKeys" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="JsonStandardCompliance" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="KindProjectorSimplifyTypeProjection" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="KindProjectorUseCorrectLambdaKeyword" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="LabeledStatement" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="LanguageFeature" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="LanguageMismatch" enabled="false" level="WARNING" enabled_by_default="false">
-    <option name="CHECK_NON_ANNOTATED_REFERENCES" value="true" />
-  </inspection_tool>
-  <inspection_tool class="LastIndexToLast" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="LengthOneStringInIndexOf" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="ListIndexOfReplaceableByContains" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="LiteralAsArgToStringEquals" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="LoopVariableNotUpdated" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="LossyEncoding" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="MapFlatten" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="MapGetGet" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="MapGetOrElseBoolean" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="MapKeys" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="MapReplaceableByEnumMap" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="MapToBooleanContains" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="MapValues" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="MatchToPartialFunction" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="MethodNameSameAsParentName" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="MethodNamesDifferOnlyByCase" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="MethodOverridesPackageLocalMethod" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="MethodOverridesPrivateMethod" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="MethodOverridesStaticMethod" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="MismatchedCollectionQueryUpdate" enabled="false" level="WEAK WARNING" enabled_by_default="false">
-    <option name="queryNames">
-      <value />
-    </option>
-    <option name="updateNames">
-      <value />
-    </option>
-    <option name="ignoredClasses">
-      <value />
-    </option>
-  </inspection_tool>
-  <inspection_tool class="MissingDeprecatedAnnotation" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="MissingOverrideAnnotation" enabled="true" level="WARNING" enabled_by_default="true">
-    <option name="ignoreObjectMethods" value="true" />
-    <option name="ignoreAnonymousClassMethods" value="false" />
-  </inspection_tool>
-  <inspection_tool class="MissortedModifiers" enabled="true" level="WARNING" enabled_by_default="true">
-    <option name="m_requireAnnotationsFirst" value="false" />
-  </inspection_tool>
-  <inspection_tool class="MisspelledCompareTo" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="MisspelledEquals" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="MisspelledHashcode" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="MisspelledToString" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="MultipleArgListsInAnnotation" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="MultipleRepositoryUrls" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="MutatorLikeMethodIsParameterless" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="NakedNotify" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="NameBooleanParameters" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="NoReturnTypeForImplicitDef" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="NonExceptionNameEndsWithException" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="NonFinalStaticVariableUsedInClassInitialization" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="NonProtectedConstructorInAbstractClass" enabled="true" level="WARNING" enabled_by_default="true">
-    <option name="m_ignoreNonPublicClasses" value="false" />
-  </inspection_tool>
-  <inspection_tool class="NonSerializableObjectBoundToHttpSession" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="NonSerializableWithSerialVersionUIDField" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="NonSerializableWithSerializationMethods" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="NonSynchronizedMethodOverridesSynchronizedMethod" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="NonThreadSafeLazyInitialization" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="NotImplementedCode" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="NotifyCalledOnCondition" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="NotifyNotInSynchronizedContext" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="NotifyWithoutCorrespondingWait" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="NullableProblems" enabled="true" level="WARNING" enabled_by_default="true">
-    <option name="REPORT_NULLABLE_METHOD_OVERRIDES_NOTNULL" value="true" />
-    <option name="REPORT_NOT_ANNOTATED_METHOD_OVERRIDES_NOTNULL" value="false" />
-    <option name="REPORT_NOTNULL_PARAMETER_OVERRIDES_NULLABLE" value="true" />
-    <option name="REPORT_NOT_ANNOTATED_PARAMETER_OVERRIDES_NOTNULL" value="true" />
-    <option name="REPORT_NOT_ANNOTATED_GETTER" value="true" />
-    <option name="REPORT_NOT_ANNOTATED_SETTER_PARAMETER" value="true" />
-    <option name="REPORT_ANNOTATION_NOT_PROPAGATED_TO_OVERRIDERS" value="false" />
-    <option name="REPORT_NULLS_PASSED_TO_NON_ANNOTATED_METHOD" value="true" />
-  </inspection_tool>
-  <inspection_tool class="ObjectNotify" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="ObsoleteCollection" enabled="true" level="WARNING" enabled_by_default="true">
-    <option name="ignoreRequiredObsoleteCollectionTypes" value="false" />
-  </inspection_tool>
-  <inspection_tool class="OptionEqualsSome" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="OverlyStrongTypeCast" enabled="true" level="WARNING" enabled_by_default="true">
-    <option name="ignoreInMatchingInstanceof" value="false" />
-  </inspection_tool>
-  <inspection_tool class="OverriddenMethodCallDuringObjectConstruction" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="PackageVisibleInnerClass" enabled="true" level="WARNING" enabled_by_default="false">
-    <scope name="Production" level="WARNING" enabled="true">
-      <option name="ignoreEnums" value="false" />
-      <option name="ignoreInterfaces" value="false" />
-    </scope>
-    <option name="ignoreEnums" value="false" />
-    <option name="ignoreInterfaces" value="false" />
-  </inspection_tool>
-  <inspection_tool class="ParameterNameDiffersFromOverriddenParameter" enabled="false" level="WARNING" enabled_by_default="false">
-    <option name="m_ignoreSingleCharacterNames" value="false" />
-    <option name="m_ignoreOverridesOfLibraryMethods" value="true" />
-  </inspection_tool>
-  <inspection_tool class="ParameterlessMemberOverridenAsEmptyParen" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="PointlessIndexOfComparison" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="ProtectedMemberInFinalClass" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="PublicField" enabled="true" level="WARNING" enabled_by_default="false">
-    <scope name="Production" level="WARNING" enabled="true">
-      <option name="ignoreEnums" value="false" />
-      <option name="ignorableAnnotations">
-        <value />
-      </option>
-    </scope>
-    <option name="ignoreEnums" value="false" />
-    <option name="ignorableAnnotations">
-      <value />
-    </option>
-  </inspection_tool>
-  <inspection_tool class="PublicFieldAccessedInSynchronizedContext" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="PublicInnerClass" enabled="true" level="WARNING" enabled_by_default="false">
-    <scope name="Production" level="WARNING" enabled="true">
-      <option name="ignoreEnums" value="false" />
-      <option name="ignoreInterfaces" value="false" />
-    </scope>
-    <option name="ignoreEnums" value="false" />
-    <option name="ignoreInterfaces" value="false" />
-  </inspection_tool>
-  <inspection_tool class="RangeToIndices" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="ReadObjectAndWriteObjectPrivate" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="ReadObjectInitialization" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="ReadResolveAndWriteReplaceProtected" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="RedundantBlock" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="RedundantCollectionConversion" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="RedundantDefaultArgument" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="RedundantFieldInitialization" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="RedundantHeadOrLastOption" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="RedundantImplements" enabled="true" level="WARNING" enabled_by_default="true">
-    <option name="ignoreSerializable" value="false" />
-    <option name="ignoreCloneable" value="false" />
-  </inspection_tool>
-  <inspection_tool class="RedundantImport" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="RedundantMethodOverride" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="RedundantNewCaseClass" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="RedundantSuppression" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="RedundantThrowsDeclaration" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="ReferenceMustBePrefixed" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="RemoveRedundantReturn" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="ReplaceAssignmentWithOperatorAssignment" enabled="true" level="WARNING" enabled_by_default="true">
-    <option name="ignoreLazyOperators" value="true" />
-    <option name="ignoreObscureOperators" value="false" />
-  </inspection_tool>
-  <inspection_tool class="ReplaceToWithUntil" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="ReplaceWithFlatten" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="RequiredAttributes" enabled="false" level="WARNING" enabled_by_default="false">
-    <option name="myAdditionalRequiredHtmlAttributes" value="" />
-  </inspection_tool>
-  <inspection_tool class="ResultOfObjectAllocationIgnored" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="ResultSetIndexZero" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="ReturnOfDateField" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="ReverseIterator" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="ReverseMap" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="ReverseTakeReverse" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="SafeLock" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="SafeVarargsDetector" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="SameElementsToEquals" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="SamePackageImport" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="SameParameterValue" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="ScalaDefaultFileTemplate" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="ScalaDefaultFileTemplateUsage" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="ScalaDeprecatedIdentifier" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="ScalaDeprecation" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="ScalaDocInlinedTag" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="ScalaDocMissingParameterDescription" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="ScalaDocUnbalancedHeader" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="ScalaDocUnclosedTagWithoutParser" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="ScalaDocUnknownParameter" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="ScalaDocUnknownTag" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="ScalaFileName" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="ScalaMalformedFormatString" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="ScalaPackageName" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="ScalaRedundantCast" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="ScalaRedundantConversion" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="ScalaStyle" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="ScalaUnnecessaryParentheses" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="ScalaUnnecessarySemicolon" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="ScalaUnreachableCode" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="ScalaUnusedSymbol" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
-  <inspection_tool class="ScalaUselessExpression" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
-  <inspection_tool class="ScalaXmlUnmatchedTag" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="SerialPersistentFieldsWithWrongSignature" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="SerialVersionUIDNotStaticFinal" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="SignalWithoutCorrespondingAwait" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="SimplifiableFoldOrReduce" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="SimplifiableIfStatement" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="SimplifyBoolean" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="SimplifyBooleanMatch" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="SingleImport" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="SizeReplaceableByIsEmpty" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="SizeToLength" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="SleepWhileHoldingLock" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="SortFilter" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="SpellCheckingInspection" enabled="false" level="WEAK WARNING" enabled_by_default="false">
-    <option name="processCode" value="true" />
-    <option name="processLiterals" value="true" />
-    <option name="processComments" value="true" />
-  </inspection_tool>
-  <inspection_tool class="StringBufferToStringInConcatenation" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="StringEqualsEmptyString" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="SubtractionInCompareTo" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="SynchronizeOnLock" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="SynchronizedOnLiteralObject" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="SystemRunFinalizersOnExit" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="TextLabelInSwitchStatement" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="ThreadDeathRethrown" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="ThreadRun" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="ThreadStartInConstruction" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="ThreadStopSuspendResume" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="ThreadYield" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="ThrowableInstanceNeverThrown" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="ThrowableResultOfMethodCallIgnored" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="ToSetAndBack" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="TransientFieldInNonSerializableClass" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="TransientFieldNotInitialized" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="TrivialStringConcatenation" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="TypeAnnotation" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="TypeCheckCanBeMatch" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="TypeParameterExtendsFinalClass" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="TypeParameterShadow" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="UNCHECKED_WARNING" enabled="true" level="WARNING" enabled_by_default="true">
-    <option name="IGNORE_UNCHECKED_ASSIGNMENT" value="false" />
-    <option name="IGNORE_UNCHECKED_GENERICS_ARRAY_CREATION" value="true" />
-    <option name="IGNORE_UNCHECKED_CALL" value="false" />
-    <option name="IGNORE_UNCHECKED_CAST" value="true" />
-    <option name="IGNORE_UNCHECKED_OVERRIDING" value="false" />
-  </inspection_tool>
-  <inspection_tool class="UNUSED_SYMBOL" enabled="true" level="WARNING" enabled_by_default="true">
-    <option name="LOCAL_VARIABLE" value="true" />
-    <option name="FIELD" value="true" />
-    <option name="METHOD" value="false" />
-    <option name="CLASS" value="false" />
-    <option name="PARAMETER" value="true" />
-    <option name="REPORT_PARAMETER_FOR_PUBLIC_METHODS" value="false" />
-  </inspection_tool>
-  <inspection_tool class="UnaryPlus" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="UnconditionalWait" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="UnitInMap" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="UnitMethodIsParameterless" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="UnknownLanguage" enabled="false" level="ERROR" enabled_by_default="false" />
-  <inspection_tool class="UnnecessarilyQualifiedStaticUsage" enabled="true" level="WARNING" enabled_by_default="true">
-    <option name="m_ignoreStaticFieldAccesses" value="false" />
-    <option name="m_ignoreStaticMethodCalls" value="false" />
-    <option name="m_ignoreStaticAccessFromStaticContext" value="false" />
-  </inspection_tool>
-  <inspection_tool class="UnnecessaryAnnotationParentheses" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="UnnecessaryCallToStringValueOf" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="UnnecessaryConstructor" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="UnnecessaryFinalOnLocalVariable" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="UnnecessaryFinalOnParameter" enabled="true" level="WARNING" enabled_by_default="true">
-    <option name="onlyWarnOnAbstractMethods" value="false" />
-  </inspection_tool>
-  <inspection_tool class="UnnecessaryFullyQualifiedName" enabled="false" level="WARNING" enabled_by_default="false">
-    <option name="m_ignoreJavadoc" value="true" />
-    <option name="ignoreInModuleStatements" value="true" />
-  </inspection_tool>
-  <inspection_tool class="UnnecessaryInterfaceModifier" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="UnnecessaryJavaDocLink" enabled="true" level="WARNING" enabled_by_default="true">
-    <option name="ignoreInlineLinkToSuper" value="false" />
-  </inspection_tool>
-  <inspection_tool class="UnnecessaryPartialFunction" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="UnnecessaryQualifierForThis" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="UnnecessarySuperConstructor" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="UnnecessarySuperQualifier" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="UnnecessaryThis" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="UnnecessaryUnaryMinus" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="UnusedCatchParameter" enabled="true" level="WARNING" enabled_by_default="true">
-    <option name="m_ignoreCatchBlocksWithComments" value="false" />
-    <option name="m_ignoreTestCases" value="false" />
-  </inspection_tool>
-  <inspection_tool class="UnusedLibrary" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="UnusedReturnValue" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="UpperCaseFieldNameNotConstant" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="Use of postfix method call" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="VarCouldBeVal" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
-  <inspection_tool class="VariablePatternShadow" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="WaitCalledOnCondition" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="WaitNotInLoop" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="WaitNotInSynchronizedContext" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="WaitWhileHoldingTwoLocks" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="WaitWithoutCorrespondingNotify" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="WeakerAccess" enabled="false" level="WARNING" enabled_by_default="false">
-    <option name="SUGGEST_PACKAGE_LOCAL_FOR_MEMBERS" value="true" />
-    <option name="SUGGEST_PACKAGE_LOCAL_FOR_TOP_CLASSES" value="true" />
-    <option name="SUGGEST_PRIVATE_FOR_INNERS" value="false" />
-  </inspection_tool>
-  <inspection_tool class="ZeroIndexToHead" enabled="false" level="WARNING" enabled_by_default="false" />
-  <inspection_tool class="ZeroLengthArrayInitialization" enabled="true" level="WARNING" enabled_by_default="true" />
-  <inspection_tool class="ZipWithIndex" enabled="false" level="WARNING" enabled_by_default="false" />
-</profile>
\ No newline at end of file
diff --git a/modules/clients/src/test/java/org/apache/ignite/internal/client/ClientReconnectionSelfTest.java b/modules/clients/src/test/java/org/apache/ignite/internal/client/ClientReconnectionSelfTest.java
index f1085b3..b1cd2d5 100644
--- a/modules/clients/src/test/java/org/apache/ignite/internal/client/ClientReconnectionSelfTest.java
+++ b/modules/clients/src/test/java/org/apache/ignite/internal/client/ClientReconnectionSelfTest.java
@@ -21,6 +21,8 @@
 import java.util.ArrayList;
 import java.util.Collection;
 import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.client.impl.connection.GridClientConnectionResetException;
 import org.apache.ignite.internal.util.typedef.X;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
@@ -50,6 +52,11 @@
         super.afterTest();
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * @return Client for test.
      * @throws GridClientException In case of error.
diff --git a/modules/clients/src/test/java/org/apache/ignite/internal/client/ClientTcpTaskExecutionAfterTopologyRestartSelfTest.java b/modules/clients/src/test/java/org/apache/ignite/internal/client/ClientTcpTaskExecutionAfterTopologyRestartSelfTest.java
index 4b63fff..7dac20e 100644
--- a/modules/clients/src/test/java/org/apache/ignite/internal/client/ClientTcpTaskExecutionAfterTopologyRestartSelfTest.java
+++ b/modules/clients/src/test/java/org/apache/ignite/internal/client/ClientTcpTaskExecutionAfterTopologyRestartSelfTest.java
@@ -20,6 +20,8 @@
 import java.util.Collections;
 import org.apache.ignite.configuration.ConnectorConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
 
 /**
@@ -51,6 +53,11 @@
         stopAllGrids();
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * @throws Exception If failed.
      */
diff --git a/modules/clients/src/test/java/org/apache/ignite/internal/client/integration/ClientAbstractMultiNodeSelfTest.java b/modules/clients/src/test/java/org/apache/ignite/internal/client/integration/ClientAbstractMultiNodeSelfTest.java
index 7ccb9c3..024e9c0 100644
--- a/modules/clients/src/test/java/org/apache/ignite/internal/client/integration/ClientAbstractMultiNodeSelfTest.java
+++ b/modules/clients/src/test/java/org/apache/ignite/internal/client/integration/ClientAbstractMultiNodeSelfTest.java
@@ -37,6 +37,8 @@
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.ConnectorConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.IgniteKernal;
 import org.apache.ignite.internal.client.GridClient;
 import org.apache.ignite.internal.client.GridClientCompute;
@@ -251,6 +253,11 @@
         }
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * @throws Exception If failed.
      */
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 4c127b6..b18e4d5 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
@@ -18,6 +18,7 @@
 package org.apache.ignite.internal.jdbc2;
 
 import java.io.Serializable;
+import java.math.BigDecimal;
 import java.sql.Connection;
 import java.sql.DatabaseMetaData;
 import java.sql.DriverManager;
@@ -28,6 +29,7 @@
 import java.sql.SQLException;
 import java.sql.Statement;
 import java.sql.Types;
+import java.sql.Date;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -53,6 +55,8 @@
 
 import static java.sql.Types.INTEGER;
 import static java.sql.Types.VARCHAR;
+import static java.sql.Types.DECIMAL;
+import static java.sql.Types.DATE;
 import static org.apache.ignite.IgniteJdbcDriver.CFG_URL_PREFIX;
 import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL;
 import static org.apache.ignite.cache.CacheMode.PARTITIONED;
@@ -90,7 +94,10 @@
                     .setNotNullFields(new HashSet<>(Arrays.asList("age", "name")))
             )),
             cacheConfiguration("org").setQueryEntities(Arrays.asList(
-                new QueryEntity(AffinityKey.class, Organization.class))));
+                new QueryEntity(AffinityKey.class, Organization.class))),
+
+            cacheConfiguration("metaTest").setQueryEntities(Arrays.asList(
+                new QueryEntity(AffinityKey.class, MetaTest.class))));
 
         TcpDiscoverySpi disco = new TcpDiscoverySpi();
 
@@ -172,6 +179,40 @@
     /**
      * @throws Exception If failed.
      */
+    public void testDecimalAndDateTypeMetaData() throws Exception {
+        try (Connection conn = DriverManager.getConnection(BASE_URL)) {
+            Statement stmt = conn.createStatement();
+
+            ResultSet rs = stmt.executeQuery(
+                    "select t.decimal, t.date from \"metaTest\".MetaTest as t");
+
+            assert rs != null;
+
+            ResultSetMetaData meta = rs.getMetaData();
+
+            assert meta != null;
+
+            assert meta.getColumnCount() == 2;
+
+            assert "METATEST".equalsIgnoreCase(meta.getTableName(1));
+            assert "DECIMAL".equalsIgnoreCase(meta.getColumnName(1));
+            assert "DECIMAL".equalsIgnoreCase(meta.getColumnLabel(1));
+            assert meta.getColumnType(1) == DECIMAL;
+            assert "DECIMAL".equals(meta.getColumnTypeName(1));
+            assert "java.math.BigDecimal".equals(meta.getColumnClassName(1));
+
+            assert "METATEST".equalsIgnoreCase(meta.getTableName(2));
+            assert "DATE".equalsIgnoreCase(meta.getColumnName(2));
+            assert "DATE".equalsIgnoreCase(meta.getColumnLabel(2));
+            assert meta.getColumnType(2) == DATE;
+            assert "DATE".equals(meta.getColumnTypeName(2));
+            assert "java.sql.Date".equals(meta.getColumnClassName(2));
+        }
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
     public void testGetTables() throws Exception {
         try (Connection conn = DriverManager.getConnection(BASE_URL)) {
             DatabaseMetaData meta = conn.getMetaData();
@@ -455,7 +496,7 @@
         try (Connection conn = DriverManager.getConnection(BASE_URL)) {
             ResultSet rs = conn.getMetaData().getSchemas();
 
-            Set<String> expectedSchemas = new HashSet<>(Arrays.asList("pers", "org"));
+            Set<String> expectedSchemas = new HashSet<>(Arrays.asList("pers", "org", "metaTest"));
 
             Set<String> schemas = new HashSet<>();
 
@@ -541,4 +582,31 @@
             this.name = name;
         }
     }
+
+    /**
+     * Meta Test.
+     */
+    private static class MetaTest implements Serializable {
+        /** ID. */
+        @QuerySqlField
+        private final int id;
+
+        /** Date. */
+        @QuerySqlField
+        private final Date date;
+
+        /** decimal. */
+        @QuerySqlField
+        private final BigDecimal decimal;
+
+        /**
+         * @param id ID.
+         * @param date Date.
+         */
+        private MetaTest(int id, Date date, BigDecimal decimal) {
+            this.id = id;
+            this.date = date;
+            this.decimal = decimal;
+        }
+    }
 }
diff --git a/modules/clients/src/test/java/org/apache/ignite/jdbc/JdbcMetadataSelfTest.java b/modules/clients/src/test/java/org/apache/ignite/jdbc/JdbcMetadataSelfTest.java
index 87c1202..0613de7 100644
--- a/modules/clients/src/test/java/org/apache/ignite/jdbc/JdbcMetadataSelfTest.java
+++ b/modules/clients/src/test/java/org/apache/ignite/jdbc/JdbcMetadataSelfTest.java
@@ -18,12 +18,14 @@
 package org.apache.ignite.jdbc;
 
 import java.io.Serializable;
+import java.math.BigDecimal;
 import java.sql.Connection;
 import java.sql.DatabaseMetaData;
 import java.sql.DriverManager;
 import java.sql.ResultSet;
 import java.sql.ResultSetMetaData;
 import java.sql.Statement;
+import java.sql.Date;
 import java.util.ArrayList;
 import java.util.Collection;
 import org.apache.ignite.IgniteCache;
@@ -40,8 +42,10 @@
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
 
 import static java.sql.Types.INTEGER;
-import static java.sql.Types.OTHER;
 import static java.sql.Types.VARCHAR;
+import static java.sql.Types.DECIMAL;
+import static java.sql.Types.OTHER;
+import static java.sql.Types.DATE;
 import static org.apache.ignite.cache.CacheMode.PARTITIONED;
 import static org.apache.ignite.cache.CacheWriteSynchronizationMode.FULL_SYNC;
 
@@ -103,6 +107,8 @@
         personCache.put(new AffinityKey<>("p1", "o1"), new Person("John White", 25, 1));
         personCache.put(new AffinityKey<>("p2", "o1"), new Person("Joe Black", 35, 1));
         personCache.put(new AffinityKey<>("p3", "o2"), new Person("Mike Green", 40, 2));
+
+        jcache(grid(0), cacheConfiguration(), "metaTest", AffinityKey.class, MetaTest.class);
     }
 
     /**
@@ -140,6 +146,40 @@
     /**
      * @throws Exception If failed.
      */
+    public void testDecimalAndDateTypeMetaData() throws Exception {
+        try (Connection conn = DriverManager.getConnection(URL)) {
+            Statement stmt = conn.createStatement();
+
+            ResultSet rs = stmt.executeQuery(
+                    "select t.decimal, t.date from \"metaTest\".MetaTest as t");
+
+            assert rs != null;
+
+            ResultSetMetaData meta = rs.getMetaData();
+
+            assert meta != null;
+
+            assert meta.getColumnCount() == 2;
+
+            assert "METATEST".equalsIgnoreCase(meta.getTableName(1));
+            assert "DECIMAL".equalsIgnoreCase(meta.getColumnName(1));
+            assert "DECIMAL".equalsIgnoreCase(meta.getColumnLabel(1));
+            assert meta.getColumnType(1) == DECIMAL;
+            assert "DECIMAL".equals(meta.getColumnTypeName(1));
+            assert "java.math.BigDecimal".equals(meta.getColumnClassName(1));
+
+            assert "METATEST".equalsIgnoreCase(meta.getTableName(2));
+            assert "DATE".equalsIgnoreCase(meta.getColumnName(2));
+            assert "DATE".equalsIgnoreCase(meta.getColumnLabel(2));
+            assert meta.getColumnType(2) == DATE;
+            assert "DATE".equals(meta.getColumnTypeName(2));
+            assert "java.sql.Date".equals(meta.getColumnClassName(2));
+        }
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
     public void testGetTables() throws Exception {
         try (Connection conn = DriverManager.getConnection(URL)) {
             DatabaseMetaData meta = conn.getMetaData();
@@ -337,4 +377,31 @@
             this.name = name;
         }
     }
+
+    /**
+     * Meta Test.
+     */
+    private static class MetaTest implements Serializable {
+        /** ID. */
+        @QuerySqlField
+        private final int id;
+
+        /** Date. */
+        @QuerySqlField
+        private final Date date;
+
+        /** decimal. */
+        @QuerySqlField
+        private final BigDecimal decimal;
+
+        /**
+         * @param id ID.
+         * @param date Date.
+         */
+        private MetaTest(int id, Date date, BigDecimal decimal) {
+            this.id = id;
+            this.date = date;
+            this.decimal = decimal;
+        }
+    }
 }
diff --git a/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinAbstractDmlStatementSelfTest.java b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinAbstractDmlStatementSelfTest.java
index 405f21a..862e841 100644
--- a/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinAbstractDmlStatementSelfTest.java
+++ b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinAbstractDmlStatementSelfTest.java
@@ -57,6 +57,11 @@
     }
 
     /** {@inheritDoc} */
+    @Override protected void afterTestsStopped() {
+        stopAllGrids();
+    }
+
+    /** {@inheritDoc} */
     @Override protected void beforeTest() throws Exception {
         ignite(0).getOrCreateCache(cacheConfig());
 
diff --git a/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinAbstractSelfTest.java b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinAbstractSelfTest.java
index 6d5f59a..9635420 100644
--- a/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinAbstractSelfTest.java
+++ b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinAbstractSelfTest.java
@@ -29,6 +29,8 @@
 import java.util.Collections;
 import java.util.List;
 import java.util.concurrent.Callable;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.IgniteEx;
 import org.apache.ignite.internal.processors.odbc.ClientListenerProcessor;
 import org.apache.ignite.internal.processors.port.GridPortRecord;
@@ -41,6 +43,11 @@
  */
 @SuppressWarnings("ThrowableNotThrown")
 public class JdbcThinAbstractSelfTest extends GridCommonAbstractTest {
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * @param r Runnable to check support.
      */
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 2a4c799..8eeac18 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
@@ -17,22 +17,12 @@
 
 package org.apache.ignite.jdbc.thin;
 
-import org.apache.ignite.cache.CacheAtomicityMode;
-import org.apache.ignite.cache.CacheMode;
-import org.apache.ignite.cache.QueryEntity;
-import org.apache.ignite.configuration.CacheConfiguration;
-import org.apache.ignite.configuration.NearCacheConfiguration;
-import org.apache.ignite.internal.processors.bulkload.BulkLoadCsvFormat;
-import org.apache.ignite.internal.processors.bulkload.BulkLoadCsvParser;
-import org.apache.ignite.internal.processors.query.QueryUtils;
-import org.apache.ignite.lang.IgniteClosure;
-import org.apache.ignite.testframework.GridTestUtils;
-
 import java.nio.ByteBuffer;
 import java.nio.charset.Charset;
 import java.nio.charset.CodingErrorAction;
 import java.nio.charset.UnsupportedCharsetException;
 import java.sql.BatchUpdateException;
+import java.sql.Connection;
 import java.sql.PreparedStatement;
 import java.sql.ResultSet;
 import java.sql.SQLException;
@@ -41,6 +31,17 @@
 import java.util.Collections;
 import java.util.Objects;
 import java.util.concurrent.Callable;
+import org.apache.ignite.cache.CacheAtomicityMode;
+import org.apache.ignite.cache.CacheMode;
+import org.apache.ignite.cache.QueryEntity;
+import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.configuration.NearCacheConfiguration;
+import org.apache.ignite.internal.IgniteEx;
+import org.apache.ignite.internal.processors.bulkload.BulkLoadCsvFormat;
+import org.apache.ignite.internal.processors.bulkload.BulkLoadCsvParser;
+import org.apache.ignite.internal.processors.query.QueryUtils;
+import org.apache.ignite.lang.IgniteClosure;
+import org.apache.ignite.testframework.GridTestUtils;
 
 import static org.apache.ignite.cache.CacheMode.PARTITIONED;
 import static org.apache.ignite.cache.CacheWriteSynchronizationMode.FULL_SYNC;
@@ -410,6 +411,32 @@
     }
 
     /**
+     * Test imports CSV file into a table on not affinity node and checks the created entries using SELECT statement.
+     *
+     * @throws SQLException If failed.
+     */
+    public void testBulkLoadToNonAffinityNode() throws Exception {
+        IgniteEx client = startGrid(getConfiguration("client").setClientMode(true));
+
+        try (Connection con = connect(client, null)) {
+            con.setSchema('"' + DEFAULT_CACHE_NAME + '"');
+
+            try (Statement stmt = con.createStatement()) {
+                int updatesCnt = stmt.executeUpdate(
+                    "copy from '" + BULKLOAD_UTF8_CSV_FILE + "' into " + TBL_NAME +
+                        " (_key, age, firstName, lastName)" +
+                        " format csv");
+
+                assertEquals(2, updatesCnt);
+
+                checkNationalCacheContents(TBL_NAME);
+            }
+        }
+
+        stopGrid(client.name());
+    }
+
+    /**
      * Imports two-entry CSV file with UTF-8 characters into a table using packet size of one byte
      * (thus splitting each two-byte UTF-8 character into two packets)
      * and checks the created entries using SELECT statement.
diff --git a/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinMetadataSelfTest.java b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinMetadataSelfTest.java
index 9759965..df67666 100644
--- a/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinMetadataSelfTest.java
+++ b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinMetadataSelfTest.java
@@ -53,8 +53,10 @@
 import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
 
 import static java.sql.Types.INTEGER;
-import static java.sql.Types.OTHER;
 import static java.sql.Types.VARCHAR;
+import static java.sql.Types.DECIMAL;
+import static java.sql.Types.DATE;
+import static java.sql.Types.OTHER;
 import static org.apache.ignite.cache.CacheMode.PARTITIONED;
 import static org.apache.ignite.cache.CacheWriteSynchronizationMode.FULL_SYNC;
 
@@ -158,6 +160,7 @@
             stmt.execute("CREATE INDEX IDX ON TEST (ID ASC)");
             stmt.execute("CREATE TABLE TEST_DECIMAL_COLUMN (ID INT primary key, DEC_COL DECIMAL(8, 3))");
             stmt.execute("CREATE TABLE TEST_DECIMAL_COLUMN_PRECISION (ID INT primary key, DEC_COL DECIMAL(8))");
+            stmt.execute("CREATE TABLE TEST_DECIMAL_DATE_COLUMN_META (ID INT primary key, DEC_COL DECIMAL(8), DATE_COL DATE)");
         }
     }
 
@@ -200,6 +203,40 @@
     /**
      * @throws Exception If failed.
      */
+    public void testDecimalAndDateTypeMetaData() throws Exception {
+        try (Connection conn = DriverManager.getConnection(URL)) {
+            Statement stmt = conn.createStatement();
+
+            ResultSet rs = stmt.executeQuery(
+                    "select t.dec_col, t.date_col from TEST_DECIMAL_DATE_COLUMN_META as t");
+
+            assert rs != null;
+
+            ResultSetMetaData meta = rs.getMetaData();
+
+            assert meta != null;
+
+            assert meta.getColumnCount() == 2;
+
+            assert "TEST_DECIMAL_DATE_COLUMN_META".equalsIgnoreCase(meta.getTableName(1));
+            assert "DEC_COL".equalsIgnoreCase(meta.getColumnName(1));
+            assert "DEC_COL".equalsIgnoreCase(meta.getColumnLabel(1));
+            assert meta.getColumnType(1) == DECIMAL;
+            assert "DECIMAL".equals(meta.getColumnTypeName(1));
+            assert "java.math.BigDecimal".equals(meta.getColumnClassName(1));
+
+            assert "TEST_DECIMAL_DATE_COLUMN_META".equalsIgnoreCase(meta.getTableName(2));
+            assert "DATE_COL".equalsIgnoreCase(meta.getColumnName(2));
+            assert "DATE_COL".equalsIgnoreCase(meta.getColumnLabel(2));
+            assert meta.getColumnType(2) == DATE;
+            assert "DATE".equals(meta.getColumnTypeName(2));
+            assert "java.sql.Date".equals(meta.getColumnClassName(2));
+        }
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
     public void testGetTables() throws Exception {
         try (Connection conn = DriverManager.getConnection(URL)) {
             DatabaseMetaData meta = conn.getMetaData();
@@ -261,7 +298,8 @@
                 "PUBLIC.TEST",
                 "PUBLIC.Quoted",
                 "PUBLIC.TEST_DECIMAL_COLUMN",
-                "PUBLIC.TEST_DECIMAL_COLUMN_PRECISION"));
+                "PUBLIC.TEST_DECIMAL_COLUMN_PRECISION",
+                "PUBLIC.TEST_DECIMAL_DATE_COLUMN_META"));
 
             Set<String> actualTbls = new HashSet<>(expectedTbls.size());
 
@@ -413,7 +451,10 @@
                 "PUBLIC.TEST_DECIMAL_COLUMN.ID.null",
                 "PUBLIC.TEST_DECIMAL_COLUMN.DEC_COL.null.8.3",
                 "PUBLIC.TEST_DECIMAL_COLUMN_PRECISION.ID.null",
-                "PUBLIC.TEST_DECIMAL_COLUMN_PRECISION.DEC_COL.null.8"
+                "PUBLIC.TEST_DECIMAL_COLUMN_PRECISION.DEC_COL.null.8",
+                "PUBLIC.TEST_DECIMAL_DATE_COLUMN_META.ID.null",
+                "PUBLIC.TEST_DECIMAL_DATE_COLUMN_META.DEC_COL.null.8",
+                "PUBLIC.TEST_DECIMAL_DATE_COLUMN_META.DATE_COL.null"
             ));
 
             Set<String> actualCols = new HashSet<>(expectedCols.size());
@@ -566,7 +607,8 @@
                 "PUBLIC.TEST.PK_PUBLIC_TEST.NAME",
                 "PUBLIC.Quoted.PK_PUBLIC_Quoted.Id",
                 "PUBLIC.TEST_DECIMAL_COLUMN.ID.ID",
-                "PUBLIC.TEST_DECIMAL_COLUMN_PRECISION.ID.ID"));
+                "PUBLIC.TEST_DECIMAL_COLUMN_PRECISION.ID.ID",
+                "PUBLIC.TEST_DECIMAL_DATE_COLUMN_META.ID.ID"));
 
             Set<String> actualPks = new HashSet<>(expectedPks.size());
 
diff --git a/modules/compatibility/src/test/java/org/apache/ignite/compatibility/persistence/IgnitePKIndexesMigrationToUnwrapPkTest.java b/modules/compatibility/src/test/java/org/apache/ignite/compatibility/persistence/IgnitePKIndexesMigrationToUnwrapPkTest.java
index da77dd8..60b6464 100644
--- a/modules/compatibility/src/test/java/org/apache/ignite/compatibility/persistence/IgnitePKIndexesMigrationToUnwrapPkTest.java
+++ b/modules/compatibility/src/test/java/org/apache/ignite/compatibility/persistence/IgnitePKIndexesMigrationToUnwrapPkTest.java
@@ -60,8 +60,8 @@
     }
 
     /** {@inheritDoc} */
-    @Override @NotNull protected Set<String> getExcluded(Collection<Dependency> dependencies) {
-        Set<String> excluded = super.getExcluded(dependencies);
+    @Override protected Set<String> getExcluded(String ver, Collection<Dependency> dependencies) {
+        Set<String> excluded = super.getExcluded(ver, dependencies);
 
         excluded.add("h2");
 
diff --git a/modules/compatibility/src/test/java/org/apache/ignite/compatibility/persistence/PersistenceBasicCompatibilityTest.java b/modules/compatibility/src/test/java/org/apache/ignite/compatibility/persistence/PersistenceBasicCompatibilityTest.java
index f27caa3..a94c459 100644
--- a/modules/compatibility/src/test/java/org/apache/ignite/compatibility/persistence/PersistenceBasicCompatibilityTest.java
+++ b/modules/compatibility/src/test/java/org/apache/ignite/compatibility/persistence/PersistenceBasicCompatibilityTest.java
@@ -101,6 +101,33 @@
     /**
      * Tests opportunity to read data from previous Ignite DB version.
      *
+     * @throws Exception If failed.
+     */
+    public void testNodeStartByOldVersionPersistenceData_2_4() throws Exception {
+        doTestStartupWithOldVersion("2.4.0");
+    }
+
+    /**
+     * Tests opportunity to read data from previous Ignite DB version.
+     *
+     * @throws Exception If failed.
+     */
+    public void testNodeStartByOldVersionPersistenceData_2_5() throws Exception {
+        doTestStartupWithOldVersion("2.5.0");
+    }
+
+    /**
+     * Tests opportunity to read data from previous Ignite DB version.
+     *
+     * @throws Exception If failed.
+     */
+    public void testNodeStartByOldVersionPersistenceData_2_6() throws Exception {
+        doTestStartupWithOldVersion("2.6.0");
+    }
+
+    /**
+     * Tests opportunity to read data from previous Ignite DB version.
+     *
      * @param igniteVer 3-digits version of ignite
      * @throws Exception If failed.
      */
diff --git a/modules/compatibility/src/test/java/org/apache/ignite/compatibility/testframework/junits/IgniteCompatibilityAbstractTest.java b/modules/compatibility/src/test/java/org/apache/ignite/compatibility/testframework/junits/IgniteCompatibilityAbstractTest.java
index 2d73bd8..826edba 100644
--- a/modules/compatibility/src/test/java/org/apache/ignite/compatibility/testframework/junits/IgniteCompatibilityAbstractTest.java
+++ b/modules/compatibility/src/test/java/org/apache/ignite/compatibility/testframework/junits/IgniteCompatibilityAbstractTest.java
@@ -153,7 +153,8 @@
             @Override protected String params(IgniteConfiguration cfg, boolean resetDiscovery) throws Exception {
                 return cfgCloPath + " " + igniteInstanceName + " "
                     + getId() + " "
-                    + (rmJvmInstance == null ? getId() : ((IgniteProcessProxy)rmJvmInstance).getId())
+                    + (rmJvmInstance == null ? getId() : ((IgniteProcessProxy)rmJvmInstance).getId()) + " "
+                    + ver
                     + (cloPath == null ? "" : " " + cloPath);
             }
 
@@ -169,7 +170,7 @@
 
                 final Collection<Dependency> dependencies = getDependencies(ver);
 
-                Set<String> excluded = getExcluded(dependencies);
+                Set<String> excluded = getExcluded(ver, dependencies);
 
                 StringBuilder pathBuilder = new StringBuilder();
 
@@ -247,10 +248,15 @@
     }
 
     /**
+     * These dependencies will not be translated from current code dependencies into separate node's classpath.
+     *
+     * Include here all dependencies which will be set up manually, leave all version independent dependencies.
+     *
+     * @param ver Ignite version.
      * @param dependencies Dependencies to filter.
      * @return Set of paths to exclude.
      */
-    @NotNull protected Set<String> getExcluded(Collection<Dependency> dependencies) {
+    protected Set<String> getExcluded(String ver, Collection<Dependency> dependencies) {
         Set<String> excluded = new HashSet<>();
 
         for (Dependency dependency : dependencies) {
diff --git a/modules/compatibility/src/test/java/org/apache/ignite/compatibility/testframework/junits/IgniteCompatibilityNodeRunner.java b/modules/compatibility/src/test/java/org/apache/ignite/compatibility/testframework/junits/IgniteCompatibilityNodeRunner.java
index 165cb4c..5421850 100644
--- a/modules/compatibility/src/test/java/org/apache/ignite/compatibility/testframework/junits/IgniteCompatibilityNodeRunner.java
+++ b/modules/compatibility/src/test/java/org/apache/ignite/compatibility/testframework/junits/IgniteCompatibilityNodeRunner.java
@@ -36,6 +36,7 @@
 import org.apache.ignite.internal.util.typedef.X;
 import org.apache.ignite.internal.util.typedef.internal.U;
 import org.apache.ignite.lang.IgniteInClosure;
+import org.apache.ignite.lang.IgniteProductVersion;
 import org.apache.ignite.testframework.GridTestUtils;
 import org.apache.ignite.testframework.junits.multijvm.IgniteNodeRunner;
 import org.jetbrains.annotations.NotNull;
@@ -59,7 +60,8 @@
      * args[2] - required - id of the starting node;
      * args[3] - required - sync-id of a node for synchronization of startup. Must be equals
      * to arg[2] in case of starting the first node in the Ignite cluster;
-     * args[4] - optional - path to closure for actions after node startup.
+     * args[4] - required - expected Ignite's version to check at startup;
+     * args[5] - optional - path to closure for actions after node startup.
      * </pre>
      *
      * @param args Command-line arguments.
@@ -73,7 +75,7 @@
 
             if (args.length < 3) {
                 throw new IllegalArgumentException("At least four arguments expected:" +
-                    " [path/to/closure/file] [ignite-instance-name] [node-id] [sync-node-id] [optional/path/to/closure/file]");
+                    " [path/to/closure/file] [ignite-instance-name] [node-id] [sync-node-id] [node-ver] [optional/path/to/closure/file]");
             }
 
             final Thread watchdog = delayedDumpClasspath();
@@ -86,6 +88,7 @@
 
             final UUID nodeId = UUID.fromString(args[2]);
             final UUID syncNodeId = UUID.fromString(args[3]);
+            final IgniteProductVersion expNodeVer = IgniteProductVersion.fromString(args[4]);
 
             // Ignite instance name and id must be set according to arguments
             // it's used for nodes managing: start, stop etc.
@@ -96,11 +99,14 @@
 
             assert ignite.cluster().node(syncNodeId) != null : "Node has not joined [id=" + nodeId + "]";
 
+            assert ignite.cluster().localNode().version().compareToIgnoreTimestamp(expNodeVer) == 0 : "Node is of unexpected " +
+                "version: [act=" + ignite.cluster().localNode().version() + ", exp=" + expNodeVer + ']';
+
             // It needs to set private static field 'ignite' of the IgniteNodeRunner class via reflection
             GridTestUtils.setFieldValue(new IgniteNodeRunner(), "ignite", ignite);
 
-            if (args.length == 5) {
-                IgniteInClosure<Ignite> clo = readClosureFromFileAndDelete(args[4]);
+            if (args.length == 6) {
+                IgniteInClosure<Ignite> clo = readClosureFromFileAndDelete(args[5]);
 
                 clo.apply(ignite);
             }
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 d581e75..9979ee1 100644
--- a/modules/core/src/main/java/org/apache/ignite/IgniteSystemProperties.java
+++ b/modules/core/src/main/java/org/apache/ignite/IgniteSystemProperties.java
@@ -260,6 +260,13 @@
     public static final String IGNITE_TX_DEADLOCK_DETECTION_TIMEOUT = "IGNITE_TX_DEADLOCK_DETECTION_TIMEOUT";
 
     /**
+     * System property to enable pending transaction tracker.
+     * Affects impact of {@link IgniteSystemProperties#IGNITE_DISABLE_WAL_DURING_REBALANCING} property:
+     * if this property is set, WAL anyway won't be disabled during rebalancing triggered by baseline topology change.
+     */
+    public static final String IGNITE_PENDING_TX_TRACKER_ENABLED = "IGNITE_PENDING_TX_TRACKER_ENABLED";
+
+    /**
      * System property to override multicast group taken from configuration.
      * Used for testing purposes.
      */
@@ -1045,6 +1052,16 @@
     public static final String IGNITE_DEFAULT_DATA_STORAGE_PAGE_SIZE = "IGNITE_DEFAULT_DATA_STORAGE_PAGE_SIZE";
 
     /**
+     * When set to {@code true}, cache metrics are not included into the discovery metrics update message (in this
+     * case message contains only cluster metrics). By default cache metrics are included into the message and
+     * calculated each time the message is sent.
+     * <p>
+     * Cache metrics sending can also be turned off by disabling statistics per each cache, but in this case some cache
+     * metrics will be unavailable via JMX too.
+     */
+    public static final String IGNITE_DISCOVERY_DISABLE_CACHE_METRICS_UPDATE = "IGNITE_DISCOVERY_DISABLE_CACHE_METRICS_UPDATE";
+
+    /**
      * 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 284a4cb..f777980 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
@@ -102,7 +102,6 @@
 import org.apache.ignite.internal.binary.BinaryUtils;
 import org.apache.ignite.internal.cluster.ClusterGroupAdapter;
 import org.apache.ignite.internal.cluster.IgniteClusterEx;
-import org.apache.ignite.internal.managers.encryption.GridEncryptionManager;
 import org.apache.ignite.internal.managers.GridManager;
 import org.apache.ignite.internal.managers.checkpoint.GridCheckpointManager;
 import org.apache.ignite.internal.managers.collision.GridCollisionManager;
@@ -110,6 +109,7 @@
 import org.apache.ignite.internal.managers.deployment.GridDeploymentManager;
 import org.apache.ignite.internal.managers.discovery.DiscoveryLocalJoinData;
 import org.apache.ignite.internal.managers.discovery.GridDiscoveryManager;
+import org.apache.ignite.internal.managers.encryption.GridEncryptionManager;
 import org.apache.ignite.internal.managers.eventstorage.GridEventStorageManager;
 import org.apache.ignite.internal.managers.failover.GridFailoverManager;
 import org.apache.ignite.internal.managers.indexing.GridIndexingManager;
@@ -129,8 +129,8 @@
 import org.apache.ignite.internal.processors.cache.binary.CacheObjectBinaryProcessorImpl;
 import org.apache.ignite.internal.processors.cache.mvcc.MvccProcessorImpl;
 import org.apache.ignite.internal.processors.cache.persistence.DataRegion;
-import org.apache.ignite.internal.processors.cache.persistence.GridCacheDatabaseSharedManager;
 import org.apache.ignite.internal.processors.cache.persistence.DataStorageMXBeanImpl;
+import org.apache.ignite.internal.processors.cache.persistence.GridCacheDatabaseSharedManager;
 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;
@@ -202,9 +202,9 @@
 import org.apache.ignite.marshaller.MarshallerExclusions;
 import org.apache.ignite.marshaller.MarshallerUtils;
 import org.apache.ignite.marshaller.jdk.JdkMarshaller;
-import org.apache.ignite.mxbean.FailureHandlingMxBean;
 import org.apache.ignite.mxbean.ClusterMetricsMXBean;
 import org.apache.ignite.mxbean.DataStorageMXBean;
+import org.apache.ignite.mxbean.FailureHandlingMxBean;
 import org.apache.ignite.mxbean.IgniteMXBean;
 import org.apache.ignite.mxbean.StripedExecutorMXBean;
 import org.apache.ignite.mxbean.ThreadPoolMXBean;
@@ -275,6 +275,7 @@
 import static org.apache.ignite.internal.IgniteNodeAttributes.ATTR_SPI_CLASS;
 import static org.apache.ignite.internal.IgniteNodeAttributes.ATTR_TX_CONFIG;
 import static org.apache.ignite.internal.IgniteNodeAttributes.ATTR_USER_NAME;
+import static org.apache.ignite.internal.IgniteNodeAttributes.ATTR_VALIDATE_CACHE_REQUESTS;
 import static org.apache.ignite.internal.IgniteVersionUtils.ACK_VER_STR;
 import static org.apache.ignite.internal.IgniteVersionUtils.BUILD_TSTAMP_STR;
 import static org.apache.ignite.internal.IgniteVersionUtils.COPYRIGHT;
@@ -1088,6 +1089,14 @@
 
             IgniteInternalFuture<Boolean> transitionWaitFut = joinData.transitionWaitFuture();
 
+            // Notify discovery manager the first to make sure that topology is discovered.
+            // Active flag is not used in managers, so it is safe to pass true.
+            ctx.discovery().onKernalStart(true);
+
+            // Notify IO manager the second so further components can send and receive messages.
+            // Must notify the IO manager before transition state await to make sure IO connection can be established.
+            ctx.io().onKernalStart(true);
+
             boolean active;
 
             if (transitionWaitFut != null) {
@@ -1101,12 +1110,6 @@
             else
                 active = joinData.active();
 
-            // Notify discovery manager the first to make sure that topology is discovered.
-            ctx.discovery().onKernalStart(active);
-
-            // Notify IO manager the second so further components can send and receive messages.
-            ctx.io().onKernalStart(active);
-
             boolean recon = false;
 
             // Callbacks.
@@ -1564,6 +1567,8 @@
 
         add(ATTR_CONSISTENCY_CHECK_SKIPPED, getBoolean(IGNITE_SKIP_CONFIGURATION_CONSISTENCY_CHECK));
 
+        add(ATTR_VALIDATE_CACHE_REQUESTS, Boolean.TRUE);
+
         if (cfg.getConsistentId() != null)
             add(ATTR_NODE_CONSISTENT_ID, cfg.getConsistentId());
 
@@ -3005,7 +3010,9 @@
     @Override public <K, V> IgniteBiTuple<IgniteCache<K, V>, Boolean> getOrCreateCache0(
         CacheConfiguration<K, V> cacheCfg, boolean sql) {
         A.notNull(cacheCfg, "cacheCfg");
-        CU.validateNewCacheName(cacheCfg.getName());
+        String cacheName = cacheCfg.getName();
+
+        CU.validateNewCacheName(cacheName);
 
         guard();
 
@@ -3014,18 +3021,18 @@
 
             Boolean res = false;
 
-            if (ctx.cache().cache(cacheCfg.getName()) == null) {
+            if (ctx.cache().cache(cacheName) == null) {
                 res =
                     sql ? ctx.cache().dynamicStartSqlCache(cacheCfg).get() :
                         ctx.cache().dynamicStartCache(cacheCfg,
-                            cacheCfg.getName(),
+                            cacheName,
                             null,
                             false,
                             true,
                             true).get();
             }
 
-            return new IgniteBiTuple<>((IgniteCache<K, V>)ctx.cache().publicJCache(cacheCfg.getName()), res);
+            return new IgniteBiTuple<>(ctx.cache().publicJCache(cacheName), res);
         }
         catch (IgniteCheckedException e) {
             throw CU.convertToCacheException(e);
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/IgniteNodeAttributes.java b/modules/core/src/main/java/org/apache/ignite/internal/IgniteNodeAttributes.java
index 24a71a8..7db7fde 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/IgniteNodeAttributes.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/IgniteNodeAttributes.java
@@ -202,6 +202,9 @@
     /** Internal attribute name constant. */
     public static final String ATTR_DYNAMIC_CACHE_START_ROLLBACK_SUPPORTED = ATTR_PREFIX + ".dynamic.cache.start.rollback.supported";
 
+    /** Internal attribute indicates that incoming cache requests should be validated on primary node as well. */
+    public static final String ATTR_VALIDATE_CACHE_REQUESTS = ATTR_CACHE + ".validate.cache.requests";
+
     /**
      * Enforces singleton.
      */
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 6367eef..07e7b10 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
@@ -77,6 +77,30 @@
     /** Ping interval for grid client. See {@link GridClientConfiguration#pingInterval}. */
     private long pingInterval;
 
+    /** SSL Protocol. */
+    private String sslProtocol;
+
+    /** SSL Key Algorithm. */
+    private String sslKeyAlgorithm;
+
+    /** Keystore. */
+    private String sslKeyStorePath;
+
+    /** Keystore Type. */
+    private String sslKeyStoreType;
+
+    /** Keystore Password. */
+    private char[] sslKeyStorePassword;
+
+    /** Truststore. */
+    private String sslTrustStorePath;
+
+    /** Truststore Type. */
+    private String sslTrustStoreType;
+
+    /** Truststore Password. */
+    private char[] sslTrustStorePassword;
+
     /**
      * @param cmd Command.
      * @param host Host.
@@ -92,10 +116,20 @@
      * @param pingTimeout Ping timeout. See {@link GridClientConfiguration#pingTimeout}.
      * @param pingInterval Ping interval. See {@link GridClientConfiguration#pingInterval}.
      * @param autoConfirmation Auto confirmation flag.
+     * @param sslProtocol SSL Protocol.
+     * @param sslKeyAlgorithm SSL Key Algorithm.
+     * @param sslKeyStorePath Keystore.
+     * @param sslKeyStorePassword Keystore Password.
+     * @param sslKeyStoreType Keystore Type.
+     * @param sslTrustStorePath Truststore.
+     * @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,
-        Long pingTimeout, Long pingInterval, boolean autoConfirmation) {
+        Long pingTimeout, Long pingInterval, boolean autoConfirmation, String sslProtocol, String sslKeyAlgorithm,
+        String sslKeyStorePath, char[] sslKeyStorePassword, String sslKeyStoreType,
+        String sslTrustStorePath, char[] sslTrustStorePassword, String sslTrustStoreType) {
         this.cmd = cmd;
         this.host = host;
         this.port = port;
@@ -110,6 +144,14 @@
         this.pingTimeout = pingTimeout;
         this.pingInterval = pingInterval;
         this.autoConfirmation = autoConfirmation;
+        this.sslProtocol = sslProtocol;
+        this.sslKeyAlgorithm = sslKeyAlgorithm;
+        this.sslKeyStorePath = sslKeyStorePath;
+        this.sslKeyStoreType = sslKeyStoreType;
+        this.sslKeyStorePassword = sslKeyStorePassword;
+        this.sslTrustStorePath = sslTrustStorePath;
+        this.sslTrustStoreType = sslTrustStoreType;
+        this.sslTrustStorePassword = sslTrustStorePassword;
     }
 
     /**
@@ -227,4 +269,60 @@
     public boolean autoConfirmation() {
         return autoConfirmation;
     }
+
+    /**
+     * @return SSL protocol
+     */
+    public String sslProtocol() {
+        return sslProtocol;
+    }
+
+    /**
+     * @return SSL Key Algorithm
+     */
+    public String sslKeyAlgorithm() {
+        return sslKeyAlgorithm;
+    }
+
+    /**
+     * @return Keystore
+     */
+    public String sslKeyStorePath() {
+        return sslKeyStorePath;
+    }
+
+    /**
+     * @return Keystore type
+     */
+    public String sslKeyStoreType() {
+        return sslKeyStoreType;
+    }
+
+    /**
+     * @return Keystore password
+     */
+    public char[] sslKeyStorePassword() {
+        return sslKeyStorePassword;
+    }
+
+    /**
+     * @return Truststore
+     */
+    public String sslTrustStorePath() {
+        return sslTrustStorePath;
+    }
+
+    /**
+     * @return Truststore type
+     */
+    public String sslTrustStoreType() {
+        return sslTrustStoreType;
+    }
+
+    /**
+     * @return Truststore password
+     */
+    public char[] sslTrustStorePassword() {
+        return sslTrustStorePassword;
+    }
 }
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 e9a4281..da6495f 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
@@ -54,6 +54,7 @@
 import org.apache.ignite.internal.client.GridClientNode;
 import org.apache.ignite.internal.client.GridServerUnreachableException;
 import org.apache.ignite.internal.client.impl.connection.GridClientConnectionResetException;
+import org.apache.ignite.internal.client.ssl.GridSslBasicContextFactory;
 import org.apache.ignite.internal.commandline.cache.CacheArguments;
 import org.apache.ignite.internal.commandline.cache.CacheCommand;
 import org.apache.ignite.internal.commandline.cache.distribution.CacheDistributionTask;
@@ -100,6 +101,7 @@
 import org.apache.ignite.internal.visor.tx.VisorTxTask;
 import org.apache.ignite.internal.visor.tx.VisorTxTaskArg;
 import org.apache.ignite.internal.visor.tx.VisorTxTaskResult;
+import org.apache.ignite.internal.visor.verify.CacheFilterEnum;
 import org.apache.ignite.internal.visor.verify.IndexIntegrityCheckIssue;
 import org.apache.ignite.internal.visor.verify.IndexValidationIssue;
 import org.apache.ignite.internal.visor.verify.ValidateIndexesPartitionResult;
@@ -124,6 +126,7 @@
 import org.apache.ignite.plugin.security.SecurityCredentials;
 import org.apache.ignite.plugin.security.SecurityCredentialsBasicProvider;
 import org.apache.ignite.plugin.security.SecurityCredentialsProvider;
+import org.apache.ignite.ssl.SslContextFactory;
 
 import static org.apache.ignite.IgniteSystemProperties.IGNITE_ENABLE_EXPERIMENTAL_COMMAND;
 import static org.apache.ignite.internal.IgniteVersionUtils.ACK_VER_STR;
@@ -193,9 +196,38 @@
     /** */
     private static final String CMD_SKIP_ZEROS = "--skipZeros";
 
+    /** Cache filter. */
+    private static final String CACHE_FILTER = "--cacheFilter";
+
     /** */
     private static final String CMD_USER_ATTRIBUTES = "--user-attributes";
 
+    // SSL configuration section
+
+    /** */
+    private static final String CMD_SSL_PROTOCOL = "--ssl-protocol";
+
+    /** */
+    private static final String CMD_SSL_KEY_ALGORITHM = "--ssl-key-algorithm";
+
+    /** */
+    private static final String CMD_KEYSTORE = "--keystore";
+
+    /** */
+    private static final String CMD_KEYSTORE_PASSWORD = "--keystore-password";
+
+    /** */
+    private static final String CMD_KEYSTORE_TYPE = "--keystore-type";
+
+    /** */
+    private static final String CMD_TRUSTSTORE = "--truststore";
+
+    /** */
+    private static final String CMD_TRUSTSTORE_PASSWORD = "--truststore-password";
+
+    /** */
+    private static final String CMD_TRUSTSTORE_TYPE = "--truststore-type";
+
     /** List of optional auxiliary commands. */
     private static final Set<String> AUX_COMMANDS = new HashSet<>();
 
@@ -208,6 +240,14 @@
         AUX_COMMANDS.add(CMD_AUTO_CONFIRMATION);
         AUX_COMMANDS.add(CMD_PING_INTERVAL);
         AUX_COMMANDS.add(CMD_PING_TIMEOUT);
+        AUX_COMMANDS.add(CMD_SSL_PROTOCOL);
+        AUX_COMMANDS.add(CMD_SSL_KEY_ALGORITHM);
+        AUX_COMMANDS.add(CMD_KEYSTORE);
+        AUX_COMMANDS.add(CMD_KEYSTORE_PASSWORD);
+        AUX_COMMANDS.add(CMD_KEYSTORE_TYPE);
+        AUX_COMMANDS.add(CMD_TRUSTSTORE);
+        AUX_COMMANDS.add(CMD_TRUSTSTORE_PASSWORD);
+        AUX_COMMANDS.add(CMD_TRUSTSTORE_TYPE);
     }
 
     /** Broadcast uuid. */
@@ -316,7 +356,13 @@
     private static final String UTILITY_NAME = "control.sh";
 
     /** Common options. */
-    private static final String COMMON_OPTIONS = String.join(" ", op(CMD_HOST, "HOST_OR_IP"), op(CMD_PORT, "PORT"), op(CMD_USER, "USER"), op(CMD_PASSWORD, "PASSWORD"), op(CMD_PING_INTERVAL, "PING_INTERVAL"), op(CMD_PING_TIMEOUT, "PING_TIMEOUT"));
+    private static final String COMMON_OPTIONS = String.join(" ", op(CMD_HOST, "HOST_OR_IP"),
+        op(CMD_PORT, "PORT"), op(CMD_USER, "USER"), op(CMD_PASSWORD, "PASSWORD"),
+        op(CMD_PING_INTERVAL, "PING_INTERVAL"), op(CMD_PING_TIMEOUT, "PING_TIMEOUT"),
+        op(CMD_SSL_PROTOCOL, "SSL_PROTOCOL"), op(CMD_SSL_KEY_ALGORITHM, "SSL_KEY_ALGORITHM"),
+        op(CMD_KEYSTORE, "KEYSTORE"), op(CMD_KEYSTORE_TYPE, "KEYSTORE_TYPE"),
+        op(CMD_KEYSTORE_PASSWORD, "KEYSTORE_PASSWORD"), op(CMD_TRUSTSTORE, "TRUSTSTORE"),
+        op(CMD_TRUSTSTORE_TYPE, "TRUSTSTORE_TYPE"), op(CMD_TRUSTSTORE_PASSWORD, "TRUSTSTORE_PASSWORD"));
 
     /** Utility name with common options. */
     private static final String UTILITY_NAME_WITH_COMMON_OPTIONS = String.join(" ", UTILITY_NAME, COMMON_OPTIONS);
@@ -767,10 +813,14 @@
         nl();
         log(i("Subcommands:"));
 
-        usageCache(LIST, "regexPattern", "[groups|seq]", "[nodeId]", op(CONFIG), op(OUTPUT_FORMAT, MULTI_LINE.text()));
-        usageCache(CONTENTION, "minQueueSize", "[nodeId]", "[maxPrint]");
-        usageCache(IDLE_VERIFY, op(CMD_DUMP), op(CMD_SKIP_ZEROS), "[cache1,...,cacheN]");
-        usageCache(VALIDATE_INDEXES, "[cache1,...,cacheN]", "[nodeId]", op(or(VI_CHECK_FIRST + " N", VI_CHECK_THROUGH + " K")));
+        usageCache(LIST, "regexPattern", op(or("groups","seq")), op("nodeId"), op(CONFIG), op(OUTPUT_FORMAT, MULTI_LINE
+            .text()));
+        usageCache(CONTENTION, "minQueueSize", op("nodeId"), op("maxPrint"));
+        usageCache(IDLE_VERIFY, op(CMD_DUMP), op(CMD_SKIP_ZEROS), "[cache1,...,cacheN]",
+            op(CACHE_FILTER, or(CacheFilterEnum.ALL.toString(), CacheFilterEnum.SYSTEM.toString(), CacheFilterEnum.PERSISTENT.toString(),
+                CacheFilterEnum.NOT_PERSISTENT.toString())));
+        usageCache(VALIDATE_INDEXES, "[cache1,...,cacheN]", op("nodeId"), op(or(VI_CHECK_FIRST + " N",
+            VI_CHECK_THROUGH + " K")));
         usageCache(DISTRIBUTION, or("nodeId", NULL), "[cacheName1,...,cacheNameN]", op(CMD_USER_ATTRIBUTES, "attName1,...,attrNameN"));
         usageCache(RESET_LOST_PARTITIONS, "cacheName1,...,cacheNameN");
         nl();
@@ -1091,7 +1141,7 @@
         String path = executeTask(
             client,
             VisorIdleVerifyDumpTask.class,
-            new VisorIdleVerifyDumpTaskArg(cacheArgs.caches(), cacheArgs.isSkipZeros())
+            new VisorIdleVerifyDumpTaskArg(cacheArgs.caches(), cacheArgs.isSkipZeros(), cacheArgs.getCacheFilterEnum())
         );
 
         log("VisorIdleVerifyDumpTask successfully written output to '" + path + "'");
@@ -1776,6 +1826,22 @@
 
         VisorTxTaskArg txArgs = null;
 
+        String sslProtocol = SslContextFactory.DFLT_SSL_PROTOCOL;
+
+        String sslKeyAlgorithm = SslContextFactory.DFLT_KEY_ALGORITHM;
+
+        String sslKeyStorePath = null;
+
+        String sslKeyStoreType = SslContextFactory.DFLT_STORE_TYPE;
+
+        char sslKeyStorePassword[] = null;
+
+        String sslTrustStorePath = null;
+
+        String sslTrustStoreType = SslContextFactory.DFLT_STORE_TYPE;
+
+        char sslTrustStorePassword[] = null;
+
         while (hasNextArg()) {
             String str = nextArg("").toLowerCase();
 
@@ -1888,6 +1954,46 @@
 
                         break;
 
+                    case CMD_SSL_PROTOCOL:
+                        sslProtocol = nextArg("Expected SSL protocol");
+
+                        break;
+
+                    case CMD_SSL_KEY_ALGORITHM:
+                        sslKeyAlgorithm = nextArg("Expected SSL key algorithm");
+
+                        break;
+
+                    case CMD_KEYSTORE:
+                        sslKeyStorePath = nextArg("Expected keystore path");
+
+                        break;
+
+                    case CMD_KEYSTORE_PASSWORD:
+                        sslKeyStorePassword = nextArg("Expected keystore password").toCharArray();
+
+                        break;
+
+                    case CMD_KEYSTORE_TYPE:
+                        sslKeyStoreType = nextArg("Expected keystore type");
+
+                        break;
+
+                    case CMD_TRUSTSTORE:
+                        sslTrustStorePath = nextArg("Expected truststore path");
+
+                        break;
+
+                    case CMD_TRUSTSTORE_PASSWORD:
+                        sslTrustStorePassword = nextArg("Expected truststore password").toCharArray();
+
+                        break;
+
+                    case CMD_TRUSTSTORE_TYPE:
+                        sslTrustStoreType = nextArg("Expected truststore type");
+
+                        break;
+
                     case CMD_AUTO_CONFIRMATION:
                         autoConfirmation = true;
 
@@ -1910,7 +2016,9 @@
         Command cmd = commands.get(0);
 
         return new Arguments(cmd, host, port, user, pwd, baselineAct, baselineArgs, txArgs, cacheArgs, walAct, walArgs,
-            pingTimeout, pingInterval, autoConfirmation);
+            pingTimeout, pingInterval, autoConfirmation,
+            sslProtocol, sslKeyAlgorithm, sslKeyStorePath, sslKeyStorePassword, sslKeyStoreType,
+            sslTrustStorePath, sslTrustStorePassword, sslTrustStoreType);
     }
 
     /**
@@ -1949,6 +2057,12 @@
                         cacheArgs.dump(true);
                     else if (CMD_SKIP_ZEROS.equals(nextArg))
                         cacheArgs.skipZeros(true);
+                    else if (CACHE_FILTER.equals(nextArg)) {
+                        String filter = nextArg("The cache filter should be specified. The following values can be " +
+                            "used: " + Arrays.toString(CacheFilterEnum.values()) + '.').toUpperCase();
+
+                        cacheArgs.setCacheFilterEnum(CacheFilterEnum.valueOf(filter));
+                    }
                     else
                         parseCacheNames(nextArg, cacheArgs);
                 }
@@ -2435,6 +2549,10 @@
                 log(i("PORT=" + DFLT_PORT, 2));
                 log(i("PING_INTERVAL=" + DFLT_PING_INTERVAL, 2));
                 log(i("PING_TIMEOUT=" + DFLT_PING_TIMEOUT, 2));
+                log(i("SSL_PROTOCOL=" + SslContextFactory.DFLT_SSL_PROTOCOL, 2));
+                log(i("SSL_KEY_ALGORITHM=" + SslContextFactory.DFLT_KEY_ALGORITHM, 2));
+                log(i("KEYSTORE_TYPE=" + SslContextFactory.DFLT_STORE_TYPE, 2));
+                log(i("TRUSTSTORE_TYPE=" + SslContextFactory.DFLT_STORE_TYPE, 2));
                 nl();
 
                 log("Exit codes:");
@@ -2481,8 +2599,7 @@
 
                     if (securityCredential == null) {
                         securityCredential = new SecurityCredentialsBasicProvider(
-                            new SecurityCredentials(args.getUserName(), args.getPassword())
-                        );
+                            new SecurityCredentials(args.getUserName(), args.getPassword()));
 
                         clientCfg.setSecurityCredentialsProvider(securityCredential);
                     }
@@ -2491,6 +2608,34 @@
                     credential.setPassword(args.getPassword());
                 }
 
+                if (!F.isEmpty(args.sslKeyStorePath())) {
+                    GridSslBasicContextFactory factory = new GridSslBasicContextFactory();
+
+                    factory.setProtocol(args.sslProtocol());
+
+                    factory.setKeyAlgorithm(args.sslKeyAlgorithm());
+
+                    factory.setKeyStoreFilePath(args.sslKeyStorePath());
+
+                    if (args.sslKeyStorePassword() != null)
+                        factory.setKeyStorePassword(args.sslKeyStorePassword());
+
+                    factory.setKeyStoreType(args.sslKeyStoreType());
+
+                    if (F.isEmpty(args.sslTrustStorePath()))
+                        factory.setTrustManagers(GridSslBasicContextFactory.getDisabledTrustManager());
+                    else {
+                        factory.setTrustStoreFilePath(args.sslTrustStorePath());
+
+                        if (args.sslTrustStorePassword() != null)
+                            factory.setTrustStorePassword(args.sslTrustStorePassword());
+
+                        factory.setTrustStoreType(args.sslTrustStoreType());
+                    }
+
+                    clientCfg.setSslContextFactory(factory);
+                }
+
                 try (GridClient client = GridClientFactory.start(clientCfg)) {
                     switch (args.command()) {
                         case ACTIVATE:
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/commandline/cache/CacheArguments.java b/modules/core/src/main/java/org/apache/ignite/internal/commandline/cache/CacheArguments.java
index e92b627..9372391 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/commandline/cache/CacheArguments.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/commandline/cache/CacheArguments.java
@@ -19,6 +19,7 @@
 import java.util.Set;
 import java.util.UUID;
 import org.apache.ignite.internal.commandline.OutputFormat;
+import org.apache.ignite.internal.visor.verify.CacheFilterEnum;
 import org.apache.ignite.internal.visor.verify.VisorViewCacheCmd;
 import org.jetbrains.annotations.Nullable;
 
@@ -71,6 +72,23 @@
     /** Full config flag. */
     private boolean fullConfig;
 
+    /** Cache filter. */
+    private CacheFilterEnum cacheFilterEnum = CacheFilterEnum.ALL;
+
+    /**
+     * @return Gets filter of caches, which will by checked.
+     */
+    public CacheFilterEnum getCacheFilterEnum() {
+        return cacheFilterEnum;
+    }
+
+    /**
+     * @param cacheFilterEnum Cache filter.
+     */
+    public void setCacheFilterEnum(CacheFilterEnum cacheFilterEnum) {
+        this.cacheFilterEnum = cacheFilterEnum;
+    }
+
     /**
      * @return Full config flag.
      */
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/JdbcUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/JdbcUtils.java
index 77ef267..7bb1d8b 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/JdbcUtils.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/JdbcUtils.java
@@ -17,6 +17,7 @@
 
 package org.apache.ignite.internal.jdbc;
 
+import java.math.BigDecimal;
 import java.sql.SQLException;
 import java.sql.Time;
 import java.sql.Timestamp;
@@ -44,7 +45,7 @@
 import static java.sql.Types.TIMESTAMP;
 import static java.sql.Types.TINYINT;
 import static java.sql.Types.VARCHAR;
-
+import static java.sql.Types.DECIMAL;
 /**
  * Utility methods for JDBC driver.
  *
@@ -189,8 +190,10 @@
             return TIME;
         else if (Timestamp.class.getName().equals(cls))
             return TIMESTAMP;
-        else if (Date.class.getName().equals(cls))
+        else if (Date.class.getName().equals(cls) || java.sql.Date.class.getName().equals(cls))
             return DATE;
+        else if (BigDecimal.class.getName().equals(cls))
+            return DECIMAL;
         else
             return OTHER;
     }
@@ -224,8 +227,10 @@
             return "TIME";
         else if (Timestamp.class.getName().equals(cls))
             return "TIMESTAMP";
-        else if (Date.class.getName().equals(cls))
+        else if (Date.class.getName().equals(cls) || java.sql.Date.class.getName().equals(cls))
             return "DATE";
+        else if (BigDecimal.class.getName().equals(cls))
+            return "DECIMAL";
         else
             return "OTHER";
     }
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinUtils.java
index f896e7f..c129370 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinUtils.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinUtils.java
@@ -17,6 +17,7 @@
 
 package org.apache.ignite.internal.jdbc.thin;
 
+import java.math.BigDecimal;
 import java.sql.Time;
 import java.sql.Timestamp;
 import java.sql.Types;
@@ -35,6 +36,8 @@
 import static java.sql.Types.TIMESTAMP;
 import static java.sql.Types.TINYINT;
 import static java.sql.Types.VARCHAR;
+import static java.sql.Types.DECIMAL;
+
 import static org.apache.ignite.internal.jdbc.thin.ConnectionPropertiesImpl.PROP_PREFIX;
 
 /**
@@ -79,8 +82,10 @@
             return TIME;
         else if (Timestamp.class.getName().equals(cls))
             return TIMESTAMP;
-        else if (Date.class.getName().equals(cls))
+        else if (Date.class.getName().equals(cls) || java.sql.Date.class.getName().equals(cls))
             return DATE;
+        else if (BigDecimal.class.getName().equals(cls))
+            return DECIMAL;
         else
             return OTHER;
     }
@@ -114,8 +119,10 @@
             return "TIME";
         else if (Timestamp.class.getName().equals(cls))
             return "TIMESTAMP";
-        else if (Date.class.getName().equals(cls))
+        else if (Date.class.getName().equals(cls) || java.sql.Date.class.getName().equals(cls))
             return "DATE";
+        else if (BigDecimal.class.getName().equals(cls))
+            return "DECIMAL";
         else
             return "OTHER";
     }
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 cda6ba0..80881d7 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
@@ -17,6 +17,7 @@
 
 package org.apache.ignite.internal.jdbc2;
 
+import java.math.BigDecimal;
 import java.net.URL;
 import java.sql.SQLException;
 import java.sql.Time;
@@ -41,7 +42,7 @@
 import static java.sql.Types.TIMESTAMP;
 import static java.sql.Types.TINYINT;
 import static java.sql.Types.VARCHAR;
-
+import static java.sql.Types.DECIMAL;
 /**
  * Utility methods for JDBC driver.
  */
@@ -77,6 +78,8 @@
             return TIMESTAMP;
         else if (Date.class.getName().equals(cls) || java.sql.Date.class.getName().equals(cls))
             return DATE;
+        else if (BigDecimal.class.getName().equals(cls))
+            return DECIMAL;
         else
             return OTHER;
     }
@@ -112,6 +115,8 @@
             return "TIMESTAMP";
         else if (Date.class.getName().equals(cls) || java.sql.Date.class.getName().equals(cls))
             return "DATE";
+        else if (BigDecimal.class.getName().equals(cls))
+            return "DECIMAL";
         else
             return "OTHER";
     }
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/managers/deployment/GridDeploymentCommunication.java b/modules/core/src/main/java/org/apache/ignite/internal/managers/deployment/GridDeploymentCommunication.java
index fdbe9b9..d79346d 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/managers/deployment/GridDeploymentCommunication.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/managers/deployment/GridDeploymentCommunication.java
@@ -204,9 +204,9 @@
             // since it was already performed before (and was successful).
             if (!(ldr instanceof GridDeploymentClassLoader)) {
                 // First check for @GridNotPeerDeployable annotation.
-                try {
-                    String clsName = req.resourceName().replace('/', '.');
+                String clsName = req.resourceName().replace('/', '.');
 
+                try {
                     int idx = clsName.indexOf(".class");
 
                     if (idx >= 0)
@@ -228,8 +228,10 @@
                         return;
                     }
                 }
-                catch (ClassNotFoundException ignore) {
-                    // Safely ignore it here - resource wasn't a class name.
+                catch (LinkageError | ClassNotFoundException e) {
+                    U.warn(log, "Failed to resolve class: " + clsName, e);
+                    // Defined errors can be safely ignored here, because of resource which is able to be not a class name.
+                    // Unsuccessful response will be sent below if the resource failed to be loaded.
                 }
             }
 
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/managers/discovery/GridDiscoveryManager.java b/modules/core/src/main/java/org/apache/ignite/internal/managers/discovery/GridDiscoveryManager.java
index 9a0ca92..5abe63c 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/managers/discovery/GridDiscoveryManager.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/managers/discovery/GridDiscoveryManager.java
@@ -48,6 +48,7 @@
 import org.apache.ignite.IgniteClientDisconnectedException;
 import org.apache.ignite.IgniteException;
 import org.apache.ignite.IgniteInterruptedException;
+import org.apache.ignite.IgniteSystemProperties;
 import org.apache.ignite.cache.CacheMetrics;
 import org.apache.ignite.cache.CacheMode;
 import org.apache.ignite.cluster.BaselineNode;
@@ -764,8 +765,6 @@
                     // Current version.
                     discoCache = discoCache();
 
-                final DiscoCache discoCache0 = discoCache;
-
                 // If this is a local join event, just save it and do not notify listeners.
                 if (locJoinEvt) {
                     if (gridStartTime == 0)
@@ -853,7 +852,7 @@
                             try {
                                 fut.get();
 
-                                discoWrk.addEvent(type, nextTopVer, node, discoCache0, topSnapshot, null);
+                                discoWrk.addEvent(EVT_CLIENT_NODE_RECONNECTED, nextTopVer, node, discoCache, topSnapshot, null);
                             }
                             catch (IgniteException ignore) {
                                 // No-op.
@@ -1093,6 +1092,10 @@
      */
     public DiscoveryMetricsProvider createMetricsProvider() {
         return new DiscoveryMetricsProvider() {
+            /** Disable cache metrics update. */
+            private final boolean disableCacheMetricsUpdate = IgniteSystemProperties.getBoolean(
+                IgniteSystemProperties.IGNITE_DISCOVERY_DISABLE_CACHE_METRICS_UPDATE, false);
+
             /** */
             private final long startTime = U.currentTimeMillis();
 
@@ -1104,6 +1107,9 @@
             /** {@inheritDoc} */
             @Override public Map<Integer, CacheMetrics> cacheMetrics() {
                 try {
+                    if (disableCacheMetricsUpdate)
+                        return Collections.emptyMap();
+
                     /** Caches should not be accessed while state transition is in progress. */
                     if (ctx.state().clusterState().transition())
                         return Collections.emptyMap();
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheAffinitySharedManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheAffinitySharedManager.java
index 164f970..f6c2de8 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheAffinitySharedManager.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheAffinitySharedManager.java
@@ -361,7 +361,7 @@
     void onCacheGroupCreated(CacheGroupContext grp) {
         if (!grpHolders.containsKey(grp.groupId())) {
             cctx.io().addCacheGroupHandler(grp.groupId(), GridDhtAffinityAssignmentResponse.class,
-                (IgniteBiInClosure<UUID, GridDhtAffinityAssignmentResponse>) this::processAffinityAssignmentResponse);
+                (IgniteBiInClosure<UUID, GridDhtAffinityAssignmentResponse>)this::processAffinityAssignmentResponse);
         }
     }
 
@@ -430,10 +430,12 @@
                 DynamicCacheChangeRequest changeReq = startReqs.get(desc.cacheName());
 
                 return new StartCacheInfo(
+                    desc.cacheConfiguration(),
                     desc,
                     changeReq.nearCacheConfiguration(),
                     topVer,
-                    changeReq.disabledAfterStart()
+                    changeReq.disabledAfterStart(),
+                    true
                 );
             })
             .collect(Collectors.toList());
@@ -875,7 +877,7 @@
 
         final ExchangeDiscoveryEvents evts = fut.context().events();
 
-        long time = System.currentTimeMillis();
+        long time = U.currentTimeMillis();
 
         Map<StartCacheInfo, DynamicCacheChangeRequest> startCacheInfos = new LinkedHashMap<>();
 
@@ -926,6 +928,8 @@
                     req
                 );
             }
+            else
+                cctx.kernalContext().cache().initQueryStructuresForNotStartedCache(cacheDesc);
         }
 
         Map<StartCacheInfo, IgniteCheckedException> failedCaches = cctx.cache().prepareStartCachesIfPossible(startCacheInfos.keySet());
@@ -957,14 +961,14 @@
         }
 
         if (log.isInfoEnabled())
-            log.info("Caches starting performed in " + (System.currentTimeMillis() - time) + " ms.");
+            log.info("Caches starting performed in " + (U.currentTimeMillis() - time) + " ms.");
 
-        time = System.currentTimeMillis();
+        time = U.currentTimeMillis();
 
         initAffinityOnCacheGroupsStart(fut, exchActions, crd);
 
         if (log.isInfoEnabled())
-            log.info("Affinity initialization for started caches performed in " + (System.currentTimeMillis() - time) + " ms.");
+            log.info("Affinity initialization for started caches performed in " + (U.currentTimeMillis() - time) + " ms.");
     }
 
     /**
@@ -1528,9 +1532,9 @@
 
         assert F.isEmpty(affReq) || (!F.isEmpty(receivedAff) && receivedAff.size() >= affReq.size())
             : ("Requested and received affinity are different " +
-                "[requestedCnt=" + (affReq != null ? affReq.size() : "none") +
-                ", receivedCnt=" + (receivedAff != null ? receivedAff.size() : "none") +
-                ", msg=" + msg + "]");
+            "[requestedCnt=" + (affReq != null ? affReq.size() : "none") +
+            ", receivedCnt=" + (receivedAff != null ? receivedAff.size() : "none") +
+            ", msg=" + msg + "]");
 
         final Map<Long, ClusterNode> nodesByOrder = new ConcurrentHashMap<>();
 
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/ClusterCachesInfo.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/ClusterCachesInfo.java
index 6718cf3..8ca14a6 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/ClusterCachesInfo.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/ClusterCachesInfo.java
@@ -1281,6 +1281,7 @@
 
         if (joinDiscoData != null) {
             List<T2<DynamicCacheDescriptor, NearCacheConfiguration>> locJoinStartCaches = new ArrayList<>();
+            List<DynamicCacheDescriptor> locJoinInitCaches = new ArrayList<>();
             locCfgsForActivation = new HashMap<>();
 
             boolean active = ctx.state().clusterState().active();
@@ -1329,10 +1330,13 @@
                     else
                         locCfgsForActivation.put(desc.cacheName(), new T2<>(desc.cacheConfiguration(), nearCfg));
                 }
+                else
+                    locJoinInitCaches.add(desc);
             }
 
             locJoinCachesCtx = new LocalJoinCachesContext(
                 locJoinStartCaches,
+                locJoinInitCaches,
                 new HashMap<>(registeredCacheGrps),
                 new HashMap<>(registeredCaches));
         }
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheConcurrentMapImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheConcurrentMapImpl.java
index a463500..938fd72 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheConcurrentMapImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheConcurrentMapImpl.java
@@ -55,6 +55,8 @@
     @Nullable @Override public GridCacheMapEntry getEntry(GridCacheContext ctx, KeyCacheObject key) {
         CacheMapHolder hld = entriesMapIfExists(ctx.cacheIdBoxed());
 
+        key = (KeyCacheObject)ctx.kernalContext().cacheObjects().prepareForCache(key, ctx);
+
         return hld != null ? hld.map.get(key) : null;
     }
 
@@ -89,7 +91,7 @@
 
         try {
             while (!done) {
-                GridCacheMapEntry entry = hld != null ? hld.map.get(key) : null;
+                GridCacheMapEntry entry = hld != null ? hld.map.get(ctx.kernalContext().cacheObjects().prepareForCache(key, ctx)) : null;
                 created = null;
                 doomed = null;
 
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 1a8cf88..50db168 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
@@ -30,6 +30,7 @@
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.UUID;
 import java.util.concurrent.Callable;
 import java.util.concurrent.CountDownLatch;
@@ -2244,24 +2245,32 @@
      */
     @Nullable public ClusterNode selectAffinityNodeBalanced(
         List<ClusterNode> affNodes,
+        Set<ClusterNode> invalidNodes,
         int partitionId,
         boolean canRemap
     ) {
         if (!readLoadBalancingEnabled) {
             if (!canRemap) {
+                // Find next available node if we can not wait next topology version.
                 for (ClusterNode node : affNodes) {
-                    if (ctx.discovery().alive(node))
+                    if (ctx.discovery().alive(node) && !invalidNodes.contains(node))
                         return node;
                 }
 
                 return null;
             }
-            else
-                return affNodes.get(0);
+            else {
+                ClusterNode first = affNodes.get(0);
+
+                return !invalidNodes.contains(first) ? first : null;
+            }
         }
 
-        if (!readFromBackup)
-            return affNodes.get(0);
+        if (!readFromBackup){
+            ClusterNode first = affNodes.get(0);
+
+            return !invalidNodes.contains(first) ? first : null;
+        }
 
         assert locMacs != null;
 
@@ -2270,7 +2279,7 @@
         ClusterNode n0 = null;
 
         for (ClusterNode node : affNodes) {
-            if ((canRemap || discovery().alive(node) && isOwner(node, partitionId))) {
+            if ((canRemap || discovery().alive(node)) && !invalidNodes.contains(node)) {
                 if (locMacs.equals(node.attribute(ATTR_MACS)))
                     return node;
 
@@ -2285,16 +2294,6 @@
     }
 
     /**
-     *  Check that node is owner for partition.
-     * @param node Cluster node.
-     * @param partitionId Partition ID.
-     * @return {@code}
-     */
-    private boolean isOwner(ClusterNode node, int partitionId) {
-        return topology().partitionState(node.id(), partitionId) == OWNING;
-    }
-
-    /**
      * Prepare affinity field for builder (if possible).
      *
      * @param buider Builder.
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheContextInfo.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheContextInfo.java
new file mode 100644
index 0000000..e72d183
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheContextInfo.java
@@ -0,0 +1,179 @@
+/*
+ * 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.cache;
+
+import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.internal.GridKernalContext;
+import org.apache.ignite.internal.util.tostring.GridToStringExclude;
+import org.apache.ignite.internal.util.typedef.internal.CU;
+import org.apache.ignite.lang.IgniteUuid;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * Cache context information. Required to support query infrastructure for not started caches on non affinity nodes.
+ */
+@GridToStringExclude
+public class GridCacheContextInfo<K, V> {
+    /** Full cache context. Can be {@code null} in case a cache is not started. */
+    @Nullable private volatile GridCacheContext gridCacheContext;
+
+    /** Cache is client or not. */
+    private final boolean clientCache;
+
+    /** Kernal context. */
+    private final GridKernalContext ctx;
+
+    /** Dynamic cache deployment ID. */
+    private final IgniteUuid dynamicDeploymentId;
+
+    /** Cache configuration. */
+    private final CacheConfiguration config;
+
+    /** Cache group ID. */
+    private final int groupId;
+
+    /** Cache ID. */
+    private final int cacheId;
+
+    /**
+     * Constructor of full cache context.
+     *
+     * @param gridCacheContext Cache context.
+     * @param clientCache Client cache or not.
+     */
+    public GridCacheContextInfo(GridCacheContext<K, V> gridCacheContext, boolean clientCache) {
+        this.gridCacheContext = gridCacheContext;
+        this.ctx = gridCacheContext.kernalContext();
+        this.config = gridCacheContext.config();
+        this.dynamicDeploymentId = gridCacheContext.dynamicDeploymentId();
+        this.groupId = gridCacheContext.groupId();
+        this.cacheId = gridCacheContext.cacheId();
+        this.clientCache = clientCache;
+    }
+
+    /**
+     * Constructor of not started cache context.
+     *
+     * @param cacheDesc Cache descriptor.
+     * @param ctx Kernal context.
+     */
+    public GridCacheContextInfo(DynamicCacheDescriptor cacheDesc, GridKernalContext ctx) {
+        this.config = cacheDesc.cacheConfiguration();
+        this.dynamicDeploymentId = cacheDesc.deploymentId();
+        this.groupId = cacheDesc.groupId();
+        this.ctx = ctx;
+        this.clientCache = true;
+
+        this.cacheId = CU.cacheId(config.getName());
+
+    }
+
+    /**
+     * @return Cache configuration.
+     */
+    public CacheConfiguration config() {
+        return isCacheContextInited() ? gridCacheContext.config() : config;
+    }
+
+    /**
+     * @return Cache name.
+     */
+    public String name() {
+        return isCacheContextInited() ? gridCacheContext.name() : config.getName();
+    }
+
+    /**
+     * @return {@code true} in case cache use custom affinity mapper.
+     */
+    public boolean customAffinityMapper() {
+        return isCacheContextInited() && gridCacheContext.customAffinityMapper();
+    }
+
+    /**
+     * @return Cache group id.
+     */
+    public int groupId() {
+        return isCacheContextInited() ? gridCacheContext.groupId() : groupId;
+    }
+
+    /**
+     * @return Cache id.
+     */
+    public int cacheId() {
+        return isCacheContextInited() ? gridCacheContext.cacheId() : cacheId;
+    }
+
+    /**
+     * @return {@code true} in case affinity node.
+     */
+    public boolean affinityNode() {
+        return isCacheContextInited() && gridCacheContext.affinityNode();
+    }
+
+    /**
+     * @return Cache context. {@code null} for not started cache.
+     */
+    @Nullable public GridCacheContext gridCacheContext() {
+        return gridCacheContext;
+    }
+
+    /**
+     * @return Dynamic deployment ID.
+     */
+    public IgniteUuid dynamicDeploymentId() {
+        return dynamicDeploymentId;
+    }
+
+    /**
+     * Set real cache context in case cache has been fully initted and start.
+     *
+     * @param gridCacheCtx Initted cache context.
+     */
+    public void initCacheContext(GridCacheContext<?, ?> gridCacheCtx) {
+        assert this.gridCacheContext == null : this.gridCacheContext;
+        assert gridCacheCtx != null;
+
+        this.gridCacheContext = gridCacheCtx;
+    }
+
+    /**
+     * @return {@code true} For client cache.
+     */
+    public boolean isClientCache() {
+        return clientCache;
+    }
+
+    /**
+     * @return Kernal context.
+     */
+    public GridKernalContext context() {
+        return ctx;
+    }
+
+    /**
+     * @return {@code true} If Cache context is initted.
+     */
+    public boolean isCacheContextInited() {
+        return gridCacheContext != null;
+    }
+
+    /** {@inheritDoc} */
+    @Override public String toString() {
+        return "GridCacheContextInfo: " + name() + " " + (isCacheContextInited() ? "started" : "not started");
+    }
+}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCachePartitionExchangeManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCachePartitionExchangeManager.java
index 38cbe46..8428cc2 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCachePartitionExchangeManager.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCachePartitionExchangeManager.java
@@ -437,9 +437,11 @@
 
                                     return;
                                 }
+                                else
+                                    U.error(log, "Unsupported message type: " + m.getClass().getName());
                             }
 
-                            U.error(log, "Unsupported message type: " + m.getClass().getName());
+                            U.warn(log, "Cache group with id=" + m.groupId() + " is stopped or absent");
                         }
                         finally {
                             leaveBusy();
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCachePreloader.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCachePreloader.java
index d629e94..6ac26c9 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCachePreloader.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCachePreloader.java
@@ -192,4 +192,14 @@
      * Dumps debug information.
      */
     public void dumpDebugInfo();
+
+    /**
+     *  Pause preloader.
+     */
+    public void pause();
+
+    /**
+     * Resume preloader.
+     */
+    public void resume();
 }
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCachePreloaderAdapter.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCachePreloaderAdapter.java
index c5e4a81..f16305c 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCachePreloaderAdapter.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCachePreloaderAdapter.java
@@ -181,4 +181,14 @@
     @Override public void dumpDebugInfo() {
         // No-op.
     }
+
+    /** {@inheritDoc} */
+    @Override public void pause() {
+        // No-op
+    }
+
+    /** {@inheritDoc} */
+    @Override public void resume() {
+        // No-op
+    }
 }
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 8a54852..375dd12 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
@@ -73,6 +73,7 @@
 import org.apache.ignite.internal.binary.BinaryContext;
 import org.apache.ignite.internal.binary.BinaryMarshaller;
 import org.apache.ignite.internal.binary.GridBinaryMarshaller;
+import org.apache.ignite.internal.managers.communication.GridIoPolicy;
 import org.apache.ignite.internal.managers.discovery.DiscoveryCustomMessage;
 import org.apache.ignite.internal.pagemem.store.IgnitePageStoreManager;
 import org.apache.ignite.internal.pagemem.wal.IgniteWriteAheadLogManager;
@@ -756,10 +757,10 @@
         addCacheOnJoinFromConfig(caches, templates);
 
         CacheJoinNodeDiscoveryData discoData = new CacheJoinNodeDiscoveryData(
-                IgniteUuid.randomUuid(),
-                caches,
-                templates,
-                startAllCachesOnClientStart()
+            IgniteUuid.randomUuid(),
+            caches,
+            templates,
+            startAllCachesOnClientStart()
         );
 
         cachesInfo.onStart(discoData);
@@ -1250,16 +1251,16 @@
 
                 if (cache.context().userCache()) {
                     // Re-create cache structures inside indexing in order to apply recent schema changes.
-                    GridCacheContext cctx = cache.context();
+                    GridCacheContextInfo cacheInfo = new GridCacheContextInfo(cache.context(), false);
 
-                    DynamicCacheDescriptor desc = cacheDescriptor(cctx.name());
+                    DynamicCacheDescriptor desc = cacheDescriptor(cacheInfo.name());
 
-                    assert desc != null : cctx.name();
+                    assert desc != null : cacheInfo.name();
 
                     boolean rmvIdx = !cache.context().group().persistenceEnabled();
 
-                    ctx.query().onCacheStop0(cctx, rmvIdx);
-                    ctx.query().onCacheStart0(cctx, desc.schema(), desc.sql());
+                    ctx.query().onCacheStop0(cacheInfo, rmvIdx);
+                    ctx.query().onCacheStart0(cacheInfo, desc.schema(), desc.sql());
                 }
             }
         }
@@ -1285,6 +1286,20 @@
     }
 
     /**
+     * Initialize query infrastructure for not started cache.
+     *
+     * @param cacheDesc Cache descriptor.
+     * @throws IgniteCheckedException If failed.
+     */
+    public void initQueryStructuresForNotStartedCache(DynamicCacheDescriptor cacheDesc) throws IgniteCheckedException {
+        QuerySchema schema = cacheDesc.schema() != null ? cacheDesc.schema() : new QuerySchema();
+
+        GridCacheContextInfo cacheInfo = new GridCacheContextInfo(cacheDesc, ctx);
+
+        ctx.query().onCacheStart(cacheInfo, schema, cacheDesc.sql());
+    }
+
+    /**
      * @param cache Cache to stop.
      * @param cancel Cancel flag.
      * @param destroy Destroy data flag. Setting to <code>true</code> will remove all cache data.
@@ -1308,7 +1323,9 @@
 
             cache.stop();
 
-            ctx.kernalContext().query().onCacheStop(ctx, !cache.context().group().persistenceEnabled() || destroy);
+            GridCacheContextInfo cacheInfo = new GridCacheContextInfo(ctx, false);
+
+            ctx.kernalContext().query().onCacheStop(cacheInfo, !cache.context().group().persistenceEnabled() || destroy);
 
             if (isNearEnabled(ctx)) {
                 GridDhtCacheAdapter dht = ctx.near().dht();
@@ -1770,7 +1787,6 @@
     }
 
     /**
-     *
      * @param reqs Cache requests to start.
      * @param fut Completable future.
      */
@@ -1785,7 +1801,6 @@
     }
 
     /**
-     *
      * @param reqs Cache requests to start.
      * @param initVer Init exchange version.
      * @param doneVer Finish excahnge vertison.
@@ -1956,7 +1971,7 @@
         AffinityTopologyVersion exchTopVer,
         LocalJoinCachesContext locJoinCtx
     ) throws IgniteCheckedException {
-        long time = System.currentTimeMillis();
+        long time = U.currentTimeMillis();
 
         if (locJoinCtx == null)
             return new GridFinishedFuture<>();
@@ -1968,12 +1983,22 @@
             .map(cacheInfo -> new StartCacheInfo(cacheInfo.get1(), cacheInfo.get2(), exchTopVer, false))
             .collect(Collectors.toList());
 
+        locJoinCtx.initCaches()
+            .forEach(cacheDesc -> {
+                try {
+                    initQueryStructuresForNotStartedCache(cacheDesc);
+                }
+                catch (Exception e) {
+                    log.error("Can't initialize query structures for not started cache [cacheName=" + cacheDesc.cacheName() + "]");
+                }
+            });
+
         prepareStartCaches(startCacheInfos);
 
         context().exchange().exchangerUpdateHeartbeat();
 
         if (log.isInfoEnabled())
-            log.info("Starting caches on local join performed in " + (System.currentTimeMillis() - time) + " ms.");
+            log.info("Starting caches on local join performed in " + (U.currentTimeMillis() - time) + " ms.");
 
         return res;
     }
@@ -2034,7 +2059,8 @@
      * @return Caches which was failed.
      * @throws IgniteCheckedException if failed.
      */
-    Map<StartCacheInfo, IgniteCheckedException> prepareStartCachesIfPossible(Collection<StartCacheInfo> startCacheInfos) throws IgniteCheckedException {
+    Map<StartCacheInfo, IgniteCheckedException> prepareStartCachesIfPossible(
+        Collection<StartCacheInfo> startCacheInfos) throws IgniteCheckedException {
         HashMap<StartCacheInfo, IgniteCheckedException> failedCaches = new HashMap<>();
 
         prepareStartCaches(startCacheInfos, (data, operation) -> {
@@ -2074,7 +2100,8 @@
                             cacheInfo.getCacheDescriptor(),
                             cacheInfo.getReqNearCfg(),
                             cacheInfo.getExchangeTopVer(),
-                            cacheInfo.isDisabledAfterStart()
+                            cacheInfo.isDisabledAfterStart(),
+                            cacheInfo.isClientCache()
                         );
 
                         return null;
@@ -2087,10 +2114,8 @@
         else {
             Map<StartCacheInfo, GridCacheContext> cacheContexts = new ConcurrentHashMap<>();
 
-            int parallelismLvl = sharedCtx.kernalContext().config().getSystemThreadPoolSize();
-
             // Reserve at least 2 threads for system operations.
-            parallelismLvl = Math.max(1, parallelismLvl - 2);
+            int parallelismLvl = U.availableThreadCount(ctx, GridIoPolicy.SYSTEM_POOL, 2);
 
             doInParallel(
                 parallelismLvl,
@@ -2136,11 +2161,11 @@
                 cacheStartFailHandler.handle(
                     startCacheInfo,
                     cacheInfo -> {
-                        GridCacheContext<?, ?> cctx = cacheContexts.get(cacheInfo);
+                        GridCacheContext cctx = cacheContexts.get(cacheInfo);
 
                         if (!cctx.isRecoveryMode()) {
                             ctx.query().onCacheStart(
-                                cctx,
+                                new GridCacheContextInfo(cctx, cacheInfo.isClientCache()),
                                 cacheInfo.getCacheDescriptor().schema() != null
                                     ? cacheInfo.getCacheDescriptor().schema()
                                     : new QuerySchema(),
@@ -2196,14 +2221,15 @@
         DynamicCacheDescriptor desc,
         @Nullable NearCacheConfiguration reqNearCfg,
         AffinityTopologyVersion exchTopVer,
-        boolean disabledAfterStart
+        boolean disabledAfterStart,
+        boolean clientCache
     ) throws IgniteCheckedException {
         GridCacheContext cacheCtx = prepareCacheContext(startCfg, desc, reqNearCfg, exchTopVer, disabledAfterStart);
 
         if (cacheCtx.isRecoveryMode())
             finishRecovery(exchTopVer, cacheCtx);
         else {
-            ctx.query().onCacheStart(cacheCtx, desc.schema() != null ? desc.schema() : new QuerySchema(), desc.sql());
+            ctx.query().onCacheStart(new GridCacheContextInfo(cacheCtx, clientCache), desc.schema() != null ? desc.schema() : new QuerySchema(), desc.sql());
 
             onCacheStarted(cacheCtx);
         }
@@ -2275,6 +2301,7 @@
 
     /**
      * Stops cache under checkpoint lock.
+     *
      * @param cctx Cache context.
      */
     private void stopCacheSafely(GridCacheContext<?, ?> cctx) {
@@ -2299,7 +2326,9 @@
      * @param cacheContext Cache context.
      * @throws IgniteCheckedException If failed.
      */
-    private void finishRecovery(AffinityTopologyVersion cacheStartVer, GridCacheContext<?, ?> cacheContext) throws IgniteCheckedException {
+    private void finishRecovery(AffinityTopologyVersion cacheStartVer,
+        GridCacheContext<?, ?> cacheContext) throws IgniteCheckedException {
+
         CacheGroupContext groupContext = cacheContext.group();
 
         // Take cluster-wide cache descriptor and try to update local cache and cache group parameters.
@@ -2324,9 +2353,9 @@
     }
 
     /**
-     * Stops all caches and groups, that was recovered, but not activated on node join.
-     * Such caches can remain only if it was filtered by node filter on current node.
-     * It's impossible to check whether current node is affinity node for given cache before join to topology.
+     * Stops all caches and groups, that was recovered, but not activated on node join. Such caches can remain only if
+     * it was filtered by node filter on current node. It's impossible to check whether current node is affinity node
+     * for given cache before join to topology.
      */
     public void shutdownNotFinishedRecoveryCaches() {
         for (GridCacheAdapter cacheAdapter : caches.values()) {
@@ -2562,17 +2591,18 @@
 
         grp.onCacheStarted(cacheCtx);
 
-        ctx.query().onCacheStart(cacheCtx, desc.schema() != null ? desc.schema() : new QuerySchema(), desc.sql());
+        ctx.query().onCacheStart(new GridCacheContextInfo(cacheCtx, false),
+            desc.schema() != null ? desc.schema() : new QuerySchema(), desc.sql());
 
         if (log.isInfoEnabled()) {
             log.info("Started cache in recovery mode [name=" + cfg.getName() +
-                    ", id=" + cacheCtx.cacheId() +
-                    (cfg.getGroupName() != null ? ", group=" + cfg.getGroupName() : "") +
-                    ", dataRegionName=" + dataRegion +
-                    ", mode=" + cfg.getCacheMode() +
-                    ", atomicity=" + cfg.getAtomicityMode() +
-                    ", backups=" + cfg.getBackups() +
-                    ", mvcc=" + cacheCtx.mvccEnabled() + ']');
+                ", id=" + cacheCtx.cacheId() +
+                (cfg.getGroupName() != null ? ", group=" + cfg.getGroupName() : "") +
+                ", dataRegionName=" + dataRegion +
+                ", mode=" + cfg.getCacheMode() +
+                ", atomicity=" + cfg.getAtomicityMode() +
+                ", backups=" + cfg.getBackups() +
+                ", mvcc=" + cacheCtx.mvccEnabled() + ']');
         }
 
         return cacheCtx;
@@ -2764,6 +2794,9 @@
 
             return ctx;
         }
+        else
+            //Try to unregister query structures for not started caches.
+            ctx.query().onCacheStop(cacheName);
 
         return null;
     }
@@ -2874,7 +2907,9 @@
      * @param exchActions Change requests.
      */
     private void processCacheStopRequestOnExchangeDone(ExchangeActions exchActions) {
-        // Force checkpoint if there is any cache stop request
+        // Reserve at least 2 threads for system operations.
+        int parallelismLvl = U.availableThreadCount(ctx, GridIoPolicy.SYSTEM_POOL, 2);
+
         if (!exchActions.cacheStopRequests().isEmpty()) {
             try {
                 sharedCtx.database().waitForCheckpoint("caches stop");
@@ -2884,63 +2919,88 @@
             }
         }
 
-        for (ExchangeActions.CacheActionData action : exchActions.cacheStopRequests()) {
-            CacheGroupContext gctx = cacheGrps.get(action.descriptor().groupId());
+        List<IgniteBiTuple<CacheGroupContext, Boolean>> grpToStop = exchActions.cacheGroupsToStop().stream()
+                .filter(a -> cacheGrps.containsKey(a.descriptor().groupId()))
+                .map(a -> F.t(cacheGrps.get(a.descriptor().groupId()), a.destroy()))
+                .collect(Collectors.toList());
 
-            // Cancel all operations blocking gateway
-            if (gctx != null) {
-                final String msg = "Failed to wait for topology update, cache group is stopping.";
+        Map<Integer, List<ExchangeActions.CacheActionData>> cachesToStop = exchActions.cacheStopRequests().stream()
+                .collect(Collectors.groupingBy(action -> action.descriptor().groupId()));
 
-                // If snapshot operation in progress we must throw CacheStoppedException
-                // for correct cache proxy restart. For more details see
-                // IgniteCacheProxy.cacheException()
-                gctx.affinity().cancelFutures(new CacheStoppedException(msg));
-            }
+        try {
+            doInParallel(
+                    parallelismLvl,
+                    sharedCtx.kernalContext().getSystemExecutorService(),
+                    cachesToStop.entrySet(),
+                    cachesToStopByGrp -> {
+                        CacheGroupContext gctx = cacheGrps.get(cachesToStopByGrp.getKey());
 
-            stopGateway(action.request());
+                        if (gctx != null)
+                            gctx.preloader().pause();
 
-            sharedCtx.database().checkpointReadLock();
+                        try {
 
-            try {
-                prepareCacheStop(action.request().cacheName(), action.request().destroy());
-            }
-            finally {
-                sharedCtx.database().checkpointReadUnlock();
-            }
+                            if (gctx != null) {
+                                final String msg = "Failed to wait for topology update, cache group is stopping.";
+
+                                // If snapshot operation in progress we must throw CacheStoppedException
+                                // for correct cache proxy restart. For more details see
+                                // IgniteCacheProxy.cacheException()
+                                gctx.affinity().cancelFutures(new CacheStoppedException(msg));
+                            }
+
+                            for (ExchangeActions.CacheActionData action: cachesToStopByGrp.getValue()) {
+                                stopGateway(action.request());
+
+                                sharedCtx.database().checkpointReadLock();
+
+                                try {
+                                    prepareCacheStop(action.request().cacheName(), action.request().destroy());
+                                }
+                                finally {
+                                    sharedCtx.database().checkpointReadUnlock();
+                                }
+                            }
+                        }
+                        finally {
+                            if (gctx != null)
+                                gctx.preloader().resume();
+                        }
+
+                        return null;
+                    }
+            );
+        }
+        catch (IgniteCheckedException e) {
+            String msg = "Failed to stop caches";
+
+            log.error(msg, e);
+
+            throw new IgniteException(msg, e);
         }
 
         sharedCtx.database().checkpointReadLock();
 
         try {
             // Do not invoke checkpoint listeners for groups are going to be destroyed to prevent metadata corruption.
-            for (ExchangeActions.CacheGroupActionData action : exchActions.cacheGroupsToStop()) {
-                Integer groupId = action.descriptor().groupId();
-                CacheGroupContext grp = cacheGrps.get(groupId);
+            grpToStop.forEach(grp -> {
+                CacheGroupContext gctx = grp.getKey();
 
-                if (grp != null && grp.persistenceEnabled() && sharedCtx.database() instanceof GridCacheDatabaseSharedManager) {
+                if (gctx != null && gctx.persistenceEnabled() && sharedCtx.database() instanceof GridCacheDatabaseSharedManager) {
                     GridCacheDatabaseSharedManager mngr = (GridCacheDatabaseSharedManager)sharedCtx.database();
-                    mngr.removeCheckpointListener((DbCheckpointListener)grp.offheap());
+                    mngr.removeCheckpointListener((DbCheckpointListener)gctx.offheap());
                 }
-            }
+            });
         }
         finally {
             sharedCtx.database().checkpointReadUnlock();
         }
 
-        List<IgniteBiTuple<CacheGroupContext, Boolean>> stoppedGroups = new ArrayList<>();
-
-        for (ExchangeActions.CacheGroupActionData action : exchActions.cacheGroupsToStop()) {
-            Integer groupId = action.descriptor().groupId();
-
-            if (cacheGrps.containsKey(groupId)) {
-                stoppedGroups.add(F.t(cacheGrps.get(groupId), action.destroy()));
-
-                stopCacheGroup(groupId);
-            }
-        }
+        for (IgniteBiTuple<CacheGroupContext, Boolean> grp : grpToStop)
+            stopCacheGroup(grp.get1().groupId());
 
         if (!sharedCtx.kernalContext().clientNode())
-            sharedCtx.database().onCacheGroupsStopped(stoppedGroups);
+            sharedCtx.database().onCacheGroupsStopped(grpToStop);
 
         if (exchActions.deactivate())
             sharedCtx.deactivate();
@@ -3728,7 +3788,8 @@
      * @param disabledAfterStart If true, cache proxies will be only activated after {@link #restartProxies()}.
      * @return Future that will be completed when all caches are deployed.
      */
-    public IgniteInternalFuture<Boolean> dynamicStartCaches(Collection<CacheConfiguration> ccfgList, boolean failIfExists,
+    public IgniteInternalFuture<Boolean> dynamicStartCaches(Collection<CacheConfiguration> ccfgList,
+        boolean failIfExists,
         boolean checkThreadTx, boolean disabledAfterStart) {
         return dynamicStartCachesByStoredConf(
             ccfgList.stream().map(StoredCacheData::new).collect(Collectors.toList()),
@@ -4737,9 +4798,9 @@
      */
     public Collection<DynamicCacheDescriptor> persistentCaches() {
         return cachesInfo.registeredCaches().values()
-                .stream()
-                .filter(desc -> isPersistentCache(desc.cacheConfiguration(), ctx.config().getDataStorageConfiguration()))
-                .collect(Collectors.toList());
+            .stream()
+            .filter(desc -> isPersistentCache(desc.cacheConfiguration(), ctx.config().getDataStorageConfiguration()))
+            .collect(Collectors.toList());
     }
 
     /**
@@ -4747,9 +4808,9 @@
      */
     public Collection<CacheGroupDescriptor> persistentGroups() {
         return cachesInfo.registeredCacheGroups().values()
-                .stream()
-                .filter(CacheGroupDescriptor::persistenceEnabled)
-                .collect(Collectors.toList());
+            .stream()
+            .filter(CacheGroupDescriptor::persistenceEnabled)
+            .collect(Collectors.toList());
     }
 
     /**
@@ -4990,32 +5051,6 @@
     }
 
     /**
-     * Starts client caches that do not exist yet.
-     *
-     * @throws IgniteCheckedException In case of error.
-     */
-    public void createMissingQueryCaches() throws IgniteCheckedException {
-        for (Map.Entry<String, DynamicCacheDescriptor> e : cachesInfo.registeredCaches().entrySet()) {
-            DynamicCacheDescriptor desc = e.getValue();
-
-            if (isMissingQueryCache(desc))
-                dynamicStartCache(null, desc.cacheConfiguration().getName(), null, false, true, true).get();
-        }
-    }
-
-    /**
-     * Whether cache defined by provided descriptor is not yet started and has queries enabled.
-     *
-     * @param desc Descriptor.
-     * @return {@code True} if this is missing query cache.
-     */
-    private boolean isMissingQueryCache(DynamicCacheDescriptor desc) {
-        CacheConfiguration ccfg = desc.cacheConfiguration();
-
-        return !caches.containsKey(ccfg.getName()) && QueryUtils.isEnabled(ccfg);
-    }
-
-    /**
      * Registers MBean for cache components.
      *
      * @param obj Cache component.
@@ -5439,7 +5474,10 @@
      * Recovery lifecycle for caches.
      */
     private class CacheRecoveryLifecycle implements MetastorageLifecycleListener, DatabaseLifecycleListener {
-        /** Set of QuerySchema's saved on recovery. It's needed if cache query schema has changed after node joined to topology.*/
+        /**
+         * Set of QuerySchema's saved on recovery. It's needed if cache query schema has changed after node joined to
+         * topology.
+         */
         private final Map<Integer, QuerySchema> querySchemas = new ConcurrentHashMap<>();
 
         /** {@inheritDoc} */
@@ -5457,13 +5495,16 @@
         }
 
         /** {@inheritDoc} */
-        @Override public void beforeBinaryMemoryRestore(IgniteCacheDatabaseSharedManager mgr) throws IgniteCheckedException {
+        @Override public void beforeBinaryMemoryRestore(
+            IgniteCacheDatabaseSharedManager mgr) throws IgniteCheckedException {
             for (DynamicCacheDescriptor cacheDescriptor : persistentCaches())
                 preparePageStore(cacheDescriptor, true);
         }
 
         /** {@inheritDoc} */
-        @Override public void afterBinaryMemoryRestore(GridCacheDatabaseSharedManager.RestoreBinaryState binaryState) throws IgniteCheckedException {
+        @Override public void afterBinaryMemoryRestore(
+            IgniteCacheDatabaseSharedManager mgr,
+            GridCacheDatabaseSharedManager.RestoreBinaryState restoreState) throws IgniteCheckedException {
             for (DynamicCacheDescriptor cacheDescriptor : persistentCaches()) {
                 startCacheInRecoveryMode(cacheDescriptor);
 
@@ -5472,8 +5513,10 @@
         }
 
         /** {@inheritDoc} */
-        @Override public void afterLogicalUpdatesApplied(GridCacheDatabaseSharedManager.RestoreLogicalState logicalState) throws IgniteCheckedException {
-            restorePartitionStates(cacheGroups(), logicalState.partitionRecoveryStates());
+        @Override public void afterLogicalUpdatesApplied(
+            IgniteCacheDatabaseSharedManager mgr,
+            GridCacheDatabaseSharedManager.RestoreLogicalState restoreState) throws IgniteCheckedException {
+            restorePartitionStates(cacheGroups(), restoreState.partitionRecoveryStates());
         }
 
         /**
@@ -5508,7 +5551,7 @@
      *
      * @param <T> Type of started data.
      */
-    private static interface StartCacheFailHandler<T, R> {
+    private interface StartCacheFailHandler<T, R> {
         /**
          * Handle of fail.
          *
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheUtils.java
index 12b6566..ebc1d11 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheUtils.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheUtils.java
@@ -1317,7 +1317,7 @@
 
         if (e instanceof CachePartialUpdateCheckedException)
             return new CachePartialUpdateException((CachePartialUpdateCheckedException)e);
-        else if (e instanceof ClusterTopologyServerNotFoundException)
+        else if (e.hasCause(ClusterTopologyServerNotFoundException.class))
             return new CacheServerNotFoundException(e.getMessage(), e);
         else if (e instanceof SchemaOperationException)
             return new CacheException(e.getMessage(), e);
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 cdc44a5..ed3697a 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
@@ -588,17 +588,18 @@
     /**
      * @param cacheId Cache ID.
      * @param idxName Index name.
+     * @param segment Segment.
      * @return Root page for index tree.
      * @throws IgniteCheckedException If failed.
      */
-    public RootPage rootPageForIndex(int cacheId, String idxName) throws IgniteCheckedException;
+    public RootPage rootPageForIndex(int cacheId, String idxName, int segment) throws IgniteCheckedException;
 
     /**
      * @param cacheId Cache ID.
      * @param idxName Index name.
      * @throws IgniteCheckedException If failed.
      */
-    public void dropRootPageForIndex(int cacheId, String idxName) throws IgniteCheckedException;
+    public void dropRootPageForIndex(int cacheId, String idxName, int segment) throws IgniteCheckedException;
 
     /**
      * @param idxName Index name.
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 e15009e..ca14f68 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
@@ -1142,14 +1142,14 @@
     }
 
     /** {@inheritDoc} */
-    @Override public RootPage rootPageForIndex(int cacheId, String idxName) throws IgniteCheckedException {
+    @Override public RootPage rootPageForIndex(int cacheId, String idxName, int segment) throws IgniteCheckedException {
         long pageId = allocateForTree();
 
         return new RootPage(new FullPageId(pageId, grp.groupId()), true);
     }
 
     /** {@inheritDoc} */
-    @Override public void dropRootPageForIndex(int cacheId, String idxName) throws IgniteCheckedException {
+    @Override public void dropRootPageForIndex(int cacheId, String idxName, int segment) throws IgniteCheckedException {
         // No-op.
     }
 
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/LocalJoinCachesContext.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/LocalJoinCachesContext.java
index f41df60..650d398 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/LocalJoinCachesContext.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/LocalJoinCachesContext.java
@@ -17,7 +17,6 @@
 
 package org.apache.ignite.internal.processors.cache;
 
-import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
@@ -36,7 +35,13 @@
 public class LocalJoinCachesContext {
     /** */
     @GridToStringInclude
-    private List<T2<DynamicCacheDescriptor, NearCacheConfiguration>> locJoinStartCaches = Collections.emptyList();
+    private List<T2<DynamicCacheDescriptor, NearCacheConfiguration>> locJoinStartCaches;
+
+    /**
+     *
+     */
+    @GridToStringInclude
+    private List<DynamicCacheDescriptor> locJoinInitCaches;
 
     /** */
     @GridToStringInclude
@@ -48,15 +53,18 @@
 
     /**
      * @param locJoinStartCaches Local caches to start on join.
+     * @param locJoinInitCaches Local caches to initialize query infrastructure without start of caches.
      * @param cacheGrpDescs Cache group descriptors captured during join.
      * @param cacheDescs Cache descriptors captured during join.
      */
     public LocalJoinCachesContext(
         List<T2<DynamicCacheDescriptor, NearCacheConfiguration>> locJoinStartCaches,
+        List<DynamicCacheDescriptor> locJoinInitCaches,
         Map<Integer, CacheGroupDescriptor> cacheGrpDescs,
         Map<String, DynamicCacheDescriptor> cacheDescs
     ) {
         this.locJoinStartCaches = locJoinStartCaches;
+        this.locJoinInitCaches = locJoinInitCaches;
         this.cacheGrpDescs = cacheGrpDescs;
         this.cacheDescs = cacheDescs;
     }
@@ -69,6 +77,13 @@
     }
 
     /**
+     * @return Cache descriptors to initialize query infrastructure without start of caches.
+     */
+    public List<DynamicCacheDescriptor> initCaches() {
+        return locJoinInitCaches;
+    }
+
+    /**
      * @return Group descriptors.
      */
     public Map<Integer, CacheGroupDescriptor> cacheGroupDescriptors() {
@@ -96,13 +111,22 @@
             if (cacheNames.contains(desc.cacheName()))
                 it.remove();
         }
+
+        Iterator<DynamicCacheDescriptor> iter = locJoinInitCaches.iterator();
+
+        for (; iter.hasNext(); ) {
+            DynamicCacheDescriptor desc = iter.next();
+
+            if (cacheNames.contains(desc.cacheName()))
+                iter.remove();
+        }
     }
 
     /**
      * @return {@code True} if the context is empty.
      */
     public boolean isEmpty() {
-        return F.isEmpty(locJoinStartCaches) && F.isEmpty(cacheGrpDescs) && F.isEmpty(cacheDescs);
+        return F.isEmpty(locJoinStartCaches) && F.isEmpty(locJoinInitCaches) && F.isEmpty(cacheGrpDescs) && F.isEmpty(cacheDescs);
     }
 
     /** {@inheritDoc} */
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/StartCacheInfo.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/StartCacheInfo.java
index a5aea26..7a73b3e 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/StartCacheInfo.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/StartCacheInfo.java
@@ -42,6 +42,9 @@
     /** Disable started cache after start or not. */
     private final boolean disabledAfterStart;
 
+    /** Cache is client or not. */
+    private final boolean clientCache;
+
     /**
      * @param desc Cache configuration for start.
      * @param reqNearCfg Near cache configuration for start.
@@ -64,11 +67,26 @@
     public StartCacheInfo(CacheConfiguration conf, DynamicCacheDescriptor desc,
         NearCacheConfiguration reqNearCfg,
         AffinityTopologyVersion exchTopVer, boolean disabledAfterStart) {
+        this(conf, desc, reqNearCfg, exchTopVer, disabledAfterStart, false);
+    }
+
+    /**
+     * @param conf Cache configuration for start.
+     * @param desc Cache descriptor for start.
+     * @param reqNearCfg Near cache configuration for start.
+     * @param exchTopVer Exchange topology version in which starting happened.
+     * @param disabledAfterStart Disable started cache after start or not.
+     * @param clientCache {@code true} in case starting cache on client node.
+     */
+    public StartCacheInfo(CacheConfiguration conf, DynamicCacheDescriptor desc,
+        NearCacheConfiguration reqNearCfg,
+        AffinityTopologyVersion exchTopVer, boolean disabledAfterStart, boolean clientCache) {
         startedConf = conf;
         this.desc = desc;
         this.reqNearCfg = reqNearCfg;
         this.exchTopVer = exchTopVer;
         this.disabledAfterStart = disabledAfterStart;
+        this.clientCache = clientCache;
     }
 
     /**
@@ -106,6 +124,13 @@
         return disabledAfterStart;
     }
 
+    /**
+     * @return Start cache on client or not.
+     */
+    public boolean isClientCache() {
+        return clientCache;
+    }
+
     /** {@inheritDoc} */
     @Override public String toString() {
         return S.toString(StartCacheInfo.class, this);
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/WalStateManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/WalStateManager.java
index d17f20f..0bcd07da 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/WalStateManager.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/WalStateManager.java
@@ -387,9 +387,12 @@
      * in OWNING state if such feature is enabled.
      *
      * @param topVer Topology version.
+     * @param changedBaseline The exchange is caused by Baseline Topology change.
      */
-    public void changeLocalStatesOnExchangeDone(AffinityTopologyVersion topVer) {
-        if (!IgniteSystemProperties.getBoolean(IgniteSystemProperties.IGNITE_DISABLE_WAL_DURING_REBALANCING, false))
+    public void changeLocalStatesOnExchangeDone(AffinityTopologyVersion topVer, boolean changedBaseline) {
+        if (changedBaseline
+            && IgniteSystemProperties.getBoolean(IgniteSystemProperties.IGNITE_PENDING_TX_TRACKER_ENABLED)
+            || !IgniteSystemProperties.getBoolean(IgniteSystemProperties.IGNITE_DISABLE_WAL_DURING_REBALANCING, false))
             return;
 
         Set<Integer> grpsToEnableWal = new HashSet<>();
@@ -473,7 +476,7 @@
     public void onGroupRebalanceFinished(int grpId, AffinityTopologyVersion topVer) {
         TemporaryDisabledWal session0 = tmpDisabledWal;
 
-        if (session0 == null || !session0.topVer.equals(topVer))
+        if (session0 == null || session0.topVer.compareTo(topVer) > 0)
             return;
 
         session0.remainingGrps.remove(grpId);
@@ -506,7 +509,7 @@
 
                         assert grp != null;
 
-                        grp.topology().ownMoving(session0.topVer);
+                        grp.topology().ownMoving(topVer);
                     }
 
                     cctx.exchange().refreshPartitions();
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/CacheDistributedGetFutureAdapter.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/CacheDistributedGetFutureAdapter.java
index b1a9be0..feea264 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/CacheDistributedGetFutureAdapter.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/CacheDistributedGetFutureAdapter.java
@@ -18,18 +18,40 @@
 package org.apache.ignite.internal.processors.cache.distributed.dht;
 
 import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
 import java.util.Map;
+import java.util.Set;
 import java.util.UUID;
 import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
+import java.util.concurrent.atomic.AtomicReference;
+import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.IgniteLogger;
+import org.apache.ignite.cluster.ClusterNode;
+import org.apache.ignite.internal.IgniteInternalFuture;
+import org.apache.ignite.internal.cluster.ClusterTopologyCheckedException;
 import org.apache.ignite.internal.cluster.ClusterTopologyServerNotFoundException;
 import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion;
 import org.apache.ignite.internal.processors.cache.GridCacheCompoundIdentityFuture;
 import org.apache.ignite.internal.processors.cache.GridCacheContext;
+import org.apache.ignite.internal.processors.cache.GridCacheEntryInfo;
 import org.apache.ignite.internal.processors.cache.GridCacheFuture;
 import org.apache.ignite.internal.processors.cache.IgniteCacheExpiryPolicy;
 import org.apache.ignite.internal.processors.cache.KeyCacheObject;
+import org.apache.ignite.internal.processors.cache.distributed.near.GridNearGetRequest;
+import org.apache.ignite.internal.processors.cache.distributed.near.GridNearGetResponse;
+import org.apache.ignite.internal.util.future.GridFutureAdapter;
+import org.apache.ignite.internal.util.tostring.GridToStringInclude;
+import org.apache.ignite.internal.util.typedef.C1;
+import org.apache.ignite.internal.util.typedef.CIX1;
 import org.apache.ignite.internal.util.typedef.F;
+import org.apache.ignite.internal.util.typedef.P1;
 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.IgniteInClosure;
 import org.apache.ignite.lang.IgniteUuid;
 import org.jetbrains.annotations.Nullable;
 
@@ -40,8 +62,14 @@
 /**
  *
  */
-public abstract class CacheDistributedGetFutureAdapter<K, V> extends GridCacheCompoundIdentityFuture<Map<K, V>>
-    implements GridCacheFuture<Map<K, V>>, CacheGetFuture {
+public abstract class CacheDistributedGetFutureAdapter<K, V>
+    extends GridCacheCompoundIdentityFuture<Map<K, V>> implements CacheGetFuture {
+    /** Logger reference. */
+    protected static final AtomicReference<IgniteLogger> logRef = new AtomicReference<>();
+
+    /** Logger. */
+    protected static IgniteLogger log;
+
     /** Default max remap count value. */
     public static final int DFLT_MAX_REMAP_CNT = 3;
 
@@ -100,6 +128,10 @@
     /** */
     protected final boolean recovery;
 
+    /** */
+    protected Map<AffinityTopologyVersion, Map<Integer, Set<ClusterNode>>> invalidNodes = Collections.emptyMap();
+
+
     /**
      * @param cctx Context.
      * @param keys Keys.
@@ -149,6 +181,29 @@
     }
 
     /**
+     * @param aclass Class.
+     */
+    protected void initLogger(Class<?> aclass){
+        if (log == null)
+            log = U.logger(cctx.kernalContext(), logRef, aclass);
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean trackable() {
+        return trackable;
+    }
+
+    /** {@inheritDoc} */
+    @Override public void markNotTrackable() {
+        // Should not flip trackable flag from true to false since get future can be remapped.
+    }
+
+    /** {@inheritDoc} */
+    @Override public IgniteUuid futureId() {
+        return futId;
+    }
+
+    /**
      * @param part Partition.
      * @return {@code True} if partition is in owned state.
      */
@@ -157,12 +212,384 @@
     }
 
     /**
+     * @param fut Future.
+     */
+    protected void registrateFutureInMvccManager(GridCacheFuture<?> fut) {
+        if (!trackable) {
+            trackable = true;
+
+            cctx.mvcc().addFuture(fut, futId);
+        }
+    }
+
+    /**
+     * @param node Cluster node.
+     * @param part Invalid partition.
+     * @param topVer Topology version.
+     */
+    protected synchronized void addNodeAsInvalid(ClusterNode node, int part, AffinityTopologyVersion topVer) {
+        if (invalidNodes == Collections.<AffinityTopologyVersion, Map<Integer, Set<ClusterNode>>>emptyMap()) {
+            invalidNodes = new HashMap<>();
+        }
+
+        Map<Integer, Set<ClusterNode>> invalidNodeMap = invalidNodes.get(topVer);
+
+        if (invalidNodeMap == null)
+            invalidNodes.put(topVer, invalidNodeMap = new HashMap<>());
+
+        Set<ClusterNode> invalidNodeSet = invalidNodeMap.get(part);
+
+        if (invalidNodeSet == null)
+            invalidNodeMap.put(part, invalidNodeSet = new HashSet<>());
+
+        invalidNodeSet.add(node);
+    }
+
+    /**
+     * @param part Partition.
+     * @param topVer Topology version.
+     * @return Set of invalid cluster nodes.
+     */
+    protected synchronized Set<ClusterNode> getInvalidNodes(int part, AffinityTopologyVersion topVer) {
+        Set<ClusterNode> invalidNodeSet = Collections.emptySet();
+
+        Map<Integer, Set<ClusterNode>> invalidNodesMap = invalidNodes.get(topVer);
+
+        if (invalidNodesMap != null) {
+            Set<ClusterNode> nodes = invalidNodesMap.get(part);
+
+            if (nodes != null)
+                invalidNodeSet = nodes;
+        }
+
+        return invalidNodeSet;
+    }
+
+    /**
+     *
+     * @param key Key.
+     * @param node Mapped node.
+     * @param missedNodesToKeysMapping Full node mapping.
+     */
+    protected boolean checkRetryPermits(
+        KeyCacheObject key,
+        ClusterNode node,
+        Map<ClusterNode, LinkedHashMap<KeyCacheObject, Boolean>> missedNodesToKeysMapping
+    ) {
+        LinkedHashMap<KeyCacheObject, Boolean> keys = missedNodesToKeysMapping.get(node);
+
+        if (keys != null && keys.containsKey(key)) {
+            if (REMAP_CNT_UPD.incrementAndGet(this) > MAX_REMAP_CNT) {
+                onDone(new ClusterTopologyCheckedException("Failed to remap key to a new node after " +
+                    MAX_REMAP_CNT + " attempts (key got remapped to the same node) [key=" + key + ", node=" +
+                    U.toShortString(node) + ", mappings=" + missedNodesToKeysMapping + ']'));
+
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean onNodeLeft(UUID nodeId) {
+        boolean found = false;
+
+        for (IgniteInternalFuture<Map<K, V>> fut : futures())
+            if (isMini(fut)) {
+                AbstractMiniFuture f = (AbstractMiniFuture)fut;
+
+                if (f.node().id().equals(nodeId)) {
+                    found = true;
+
+                    f.onNodeLeft(new ClusterTopologyCheckedException("Remote node left grid (will retry): " + nodeId));
+                }
+            }
+
+        return found;
+    }
+
+    /** {@inheritDoc} */
+    @Override public void onResult(UUID nodeId, GridNearGetResponse res) {
+        for (IgniteInternalFuture<Map<K, V>> fut : futures())
+            if (isMini(fut)) {
+                AbstractMiniFuture f = (AbstractMiniFuture)fut;
+
+                if (f.futureId().equals(res.miniId())) {
+                    assert f.node().id().equals(nodeId);
+
+                    f.onResult(res);
+                }
+            }
+    }
+
+    /**
      * @param part Partition.
      * @param topVer Topology version.
      * @return Exception.
      */
     protected final ClusterTopologyServerNotFoundException serverNotFoundError(int part, AffinityTopologyVersion topVer) {
         return new ClusterTopologyServerNotFoundException("Failed to map keys for cache " +
-            "(all partition nodes left the grid) [topVer=" + topVer + ", part" + part + ", cache=" + cctx.name() + ']');
+            "(all partition nodes left the grid) [topVer=" + topVer +
+            ", part" + part + ", cache=" + cctx.name() + ", localNodeId=" + cctx.localNodeId() + ']');
+    }
+
+    /**
+     * @param f Future.
+     * @return {@code True} if mini-future.
+     */
+    protected abstract boolean isMini(IgniteInternalFuture<?> f);
+
+    /**
+     * @param keys Collection of mapping keys.
+     * @param mapped Previous mapping.
+     * @param topVer Topology version.
+     */
+    protected abstract void map(
+        Collection<KeyCacheObject> keys,
+        Map<ClusterNode, LinkedHashMap<KeyCacheObject, Boolean>> mapped,
+        AffinityTopologyVersion topVer
+    );
+
+    /** {@inheritDoc} */
+    @Override public String toString() {
+        Collection<String> futuresStrings = F.viewReadOnly(futures(), new C1<IgniteInternalFuture<?>, String>() {
+            @SuppressWarnings("unchecked")
+            @Override public String apply(IgniteInternalFuture<?> f) {
+                if (isMini(f)) {
+                    AbstractMiniFuture mini = (AbstractMiniFuture)f;
+
+                    return "miniFuture([futId=" + mini.futureId() + ", node=" + mini.node().id() +
+                        ", loc=" + mini.node().isLocal() +
+                        ", done=" + f.isDone() + "])";
+                }
+                else
+                    return f.getClass().getSimpleName() + " [loc=true, done=" + f.isDone() + "]";
+            }
+        });
+
+        return S.toString(CacheDistributedGetFutureAdapter.class, this,
+            "innerFuts", futuresStrings,
+            "super", super.toString());
+    }
+
+    /**
+     * Mini-future for get operations. Mini-futures are only waiting on a single
+     * node as opposed to multiple nodes.
+     */
+    protected abstract class AbstractMiniFuture extends GridFutureAdapter<Map<K, V>> {
+        /** Mini-future id. */
+        private final IgniteUuid futId = IgniteUuid.randomUuid();
+
+        /** Mapped node. */
+        protected final ClusterNode node;
+
+        /** Mapped keys. */
+        @GridToStringInclude
+        protected final LinkedHashMap<KeyCacheObject, Boolean> keys;
+
+        /** Topology version on which this future was mapped. */
+        protected final AffinityTopologyVersion topVer;
+
+        /** Post processing closure. */
+        private final IgniteInClosure<Collection<GridCacheEntryInfo>> postProcessingClos;
+
+        /** {@code True} if remapped after node left. */
+        private boolean remapped;
+
+        /**
+         * @param node Node.
+         * @param keys Keys.
+         * @param topVer Topology version.
+         */
+        protected AbstractMiniFuture(
+            ClusterNode node,
+            LinkedHashMap<KeyCacheObject, Boolean> keys,
+            AffinityTopologyVersion topVer
+        ) {
+            this.node = node;
+            this.keys = keys;
+            this.topVer = topVer;
+            this.postProcessingClos = CU.createBackupPostProcessingClosure(
+                topVer, log, cctx, null, expiryPlc, readThrough, skipVals);
+        }
+
+        /**
+         * @return Future ID.
+         */
+        public IgniteUuid futureId() {
+            return futId;
+        }
+
+        /**
+         * @return Node ID.
+         */
+        public ClusterNode node() {
+            return node;
+        }
+
+        /**
+         * @return Keys.
+         */
+        public Collection<KeyCacheObject> keys() {
+            return keys.keySet();
+        }
+
+        /**
+         * Factory methond for generate request associated with this miniFuture.
+         *
+         * @param rootFutId Root future id.
+         * @return Near get request.
+         */
+        public GridNearGetRequest createGetRequest(IgniteUuid rootFutId) {
+            return createGetRequest0(rootFutId, futureId());
+        }
+
+        /**
+         * @param rootFutId Root future id.
+         * @param futId Mini future id.
+         * @return Near get request.
+         */
+        protected abstract GridNearGetRequest createGetRequest0(IgniteUuid rootFutId, IgniteUuid futId);
+
+        /**
+         * @param entries Collection of entries.
+         * @return Map with key value results.
+         */
+        protected abstract Map<K, V> createResultMap(Collection<GridCacheEntryInfo> entries);
+
+        /**
+         * @param e Error.
+         */
+        public void onResult(Throwable e) {
+            if (log.isDebugEnabled())
+                log.debug("Failed to get future result [fut=" + this + ", err=" + e + ']');
+
+            // Fail.
+            onDone(e);
+        }
+
+        /**
+         * @param e Failure exception.
+         */
+       public synchronized void onNodeLeft(ClusterTopologyCheckedException e) {
+            if (remapped)
+                return;
+
+            remapped = true;
+
+            if (log.isDebugEnabled())
+                log.debug("Remote node left grid while sending or waiting for reply (will retry): " + this);
+
+            // Try getting from existing nodes.
+            if (!canRemap) {
+                map(keys.keySet(), F.t(node, keys), topVer);
+
+                onDone(Collections.<K, V>emptyMap());
+            }
+            else {
+                long maxTopVer = Math.max(topVer.topologyVersion() + 1, cctx.discovery().topologyVersion());
+
+                AffinityTopologyVersion awaitTopVer = new AffinityTopologyVersion(maxTopVer);
+
+                cctx.shared().exchange()
+                    .affinityReadyFuture(awaitTopVer)
+                    .listen((f) -> {
+                            try {
+                                // Remap.
+                                map(keys.keySet(), F.t(node, keys), f.get());
+
+                                onDone(Collections.<K, V>emptyMap());
+                            }
+                            catch (IgniteCheckedException ex) {
+                                CacheDistributedGetFutureAdapter.this.onDone(ex);
+                            }
+                        }
+                    );
+            }
+        }
+
+        /**
+         * @param res Result callback.
+         */
+        public void onResult(GridNearGetResponse res) {
+            // If error happened on remote node, fail the whole future.
+            if (res.error() != null) {
+                onDone(res.error());
+
+                return;
+            }
+
+            Collection<Integer> invalidParts = res.invalidPartitions();
+
+            // Remap invalid partitions.
+            if (!F.isEmpty(invalidParts)) {
+                AffinityTopologyVersion rmtTopVer = res.topologyVersion();
+
+                for (Integer part : invalidParts)
+                    addNodeAsInvalid(node, part, topVer);
+
+                if (log.isDebugEnabled())
+                    log.debug("Remapping mini get future [invalidParts=" + invalidParts + ", fut=" + this + ']');
+
+                if (!canRemap) {
+                    map(F.view(keys.keySet(), new P1<KeyCacheObject>() {
+                        @Override public boolean apply(KeyCacheObject key) {
+                            return invalidParts.contains(cctx.affinity().partition(key));
+                        }
+                    }), F.t(node, keys), topVer);
+
+                    postProcessResult(res);
+
+                    onDone(createResultMap(res.entries()));
+
+                    return;
+                }
+
+                // Remap after remote version will be finished localy.
+                cctx.shared().exchange().affinityReadyFuture(rmtTopVer)
+                    .listen(new CIX1<IgniteInternalFuture<AffinityTopologyVersion>>() {
+                        @Override public void applyx(
+                            IgniteInternalFuture<AffinityTopologyVersion> fut
+                        ) throws IgniteCheckedException {
+                            AffinityTopologyVersion topVer = fut.get();
+
+                            // This will append new futures to compound list.
+                            map(F.view(keys.keySet(), new P1<KeyCacheObject>() {
+                                @Override public boolean apply(KeyCacheObject key) {
+                                    return invalidParts.contains(cctx.affinity().partition(key));
+                                }
+                            }), F.t(node, keys), topVer);
+
+                            postProcessResult(res);
+
+                            onDone(createResultMap(res.entries()));
+                        }
+                    });
+            }
+            else {
+                try {
+                    postProcessResult(res);
+
+                    onDone(createResultMap(res.entries()));
+                }
+                catch (Exception e) {
+                    onDone(e);
+                }
+            }
+        }
+
+        /**
+         * @param res Response.
+         */
+        protected void postProcessResult(final GridNearGetResponse res) {
+            if (postProcessingClos != null)
+                postProcessingClos.apply(res.entries());
+        }
+
+        /** {@inheritDoc} */
+        @Override public String toString() {
+            return S.toString(AbstractMiniFuture.class, this);
+        }
     }
 }
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtCacheAdapter.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtCacheAdapter.java
index 17bf4ca..611c87c 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtCacheAdapter.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtCacheAdapter.java
@@ -969,12 +969,14 @@
                                 res0 = info.value();
                         }
 
-                        res = new GridNearSingleGetResponse(ctx.cacheId(),
+                        res = new GridNearSingleGetResponse(
+                            ctx.cacheId(),
                             req.futureId(),
                             null,
                             res0,
                             false,
-                            req.addDeploymentInfo());
+                            req.addDeploymentInfo()
+                        );
 
                         if (info != null && req.skipValues())
                             res.setContainsValue();
@@ -982,15 +984,14 @@
                     else {
                         AffinityTopologyVersion topVer = ctx.shared().exchange().lastTopologyFuture().initialVersion();
 
-                        assert topVer.compareTo(req.topologyVersion()) > 0 : "Wrong ready topology version for " +
-                            "invalid partitions response [topVer=" + topVer + ", req=" + req + ']';
-
-                        res = new GridNearSingleGetResponse(ctx.cacheId(),
+                        res = new GridNearSingleGetResponse(
+                            ctx.cacheId(),
                             req.futureId(),
                             topVer,
                             null,
                             true,
-                            req.addDeploymentInfo());
+                            req.addDeploymentInfo()
+                        );
                     }
                 }
                 catch (NodeStoppingException ignored) {
@@ -1075,8 +1076,11 @@
                     res.error(e);
                 }
 
-                if (!F.isEmpty(fut.invalidPartitions()))
-                    res.invalidPartitions(fut.invalidPartitions(), ctx.shared().exchange().lastTopologyFuture().initialVersion());
+                if (!F.isEmpty(fut.invalidPartitions())){
+                    AffinityTopologyVersion topVer = ctx.shared().exchange().lastTopologyFuture().initialVersion();
+
+                    res.invalidPartitions(fut.invalidPartitions(), topVer);
+                }
 
                 try {
                     ctx.io().send(nodeId, res, ctx.ioPolicy());
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 e0fe8be..8588084 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
@@ -213,7 +213,7 @@
      *
      */
     private void map() {
-        // TODO get rid of force keys request https://issues.apache.org/jira/browse/IGNITE-10251
+        // TODO Get rid of force keys request https://issues.apache.org/jira/browse/IGNITE-10251.
         if (cctx.group().preloader().needForceKeys()) {
             GridDhtFuture<Object> fut = cctx.group().preloader().request(
                 cctx,
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTransactionalCacheAdapter.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTransactionalCacheAdapter.java
index 4693232..dcd7be5 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTransactionalCacheAdapter.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTransactionalCacheAdapter.java
@@ -1122,7 +1122,8 @@
                             null,
                             req.subjectId(),
                             req.taskNameHash(),
-                            req.txLabel());
+                            req.txLabel(),
+                            null);
 
                         if (req.syncCommit())
                             tx.syncMode(FULL_SYNC);
@@ -2158,6 +2159,7 @@
                     null,
                     txSubjectId,
                     txTaskNameHash,
+                    null,
                     null);
 
                 // if (req.syncCommit())
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxLocal.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxLocal.java
index 6bad093..53c49428 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxLocal.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxLocal.java
@@ -36,6 +36,7 @@
 import org.apache.ignite.internal.processors.cache.KeyCacheObject;
 import org.apache.ignite.internal.processors.cache.distributed.GridCacheMappedVersion;
 import org.apache.ignite.internal.processors.cache.distributed.near.GridNearTxFinishResponse;
+import org.apache.ignite.internal.processors.cache.distributed.near.GridNearTxLocal;
 import org.apache.ignite.internal.processors.cache.distributed.near.GridNearTxPrepareRequest;
 import org.apache.ignite.internal.processors.cache.distributed.near.GridNearTxPrepareResponse;
 import org.apache.ignite.internal.processors.cache.transactions.IgniteInternalTx;
@@ -122,6 +123,7 @@
      * @param txSize Expected transaction size.
      * @param txNodes Transaction nodes mapping.
      * @param lb Transaction label.
+     * @param parentTx Transaction from which this transaction was copied by(if it was).
      */
     public GridDhtTxLocal(
         GridCacheSharedContext cctx,
@@ -146,7 +148,8 @@
         Map<UUID, Collection<UUID>> txNodes,
         UUID subjId,
         int taskNameHash,
-        @Nullable String lb
+        @Nullable String lb,
+        GridNearTxLocal parentTx
     ) {
         super(
             cctx,
@@ -180,6 +183,8 @@
 
         threadId = nearThreadId;
 
+        setParentTx(parentTx);
+
         assert !F.eq(xidVer, nearXidVer);
 
         initResult();
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxPrepareFuture.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxPrepareFuture.java
index cc07d77..58edc9d 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxPrepareFuture.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxPrepareFuture.java
@@ -97,12 +97,14 @@
 import org.jetbrains.annotations.Nullable;
 
 import static org.apache.ignite.events.EventType.EVT_CACHE_REBALANCE_OBJECT_LOADED;
+import static org.apache.ignite.internal.IgniteNodeAttributes.ATTR_VALIDATE_CACHE_REQUESTS;
 import static org.apache.ignite.internal.processors.cache.GridCacheOperation.CREATE;
 import static org.apache.ignite.internal.processors.cache.GridCacheOperation.DELETE;
 import static org.apache.ignite.internal.processors.cache.GridCacheOperation.NOOP;
 import static org.apache.ignite.internal.processors.cache.GridCacheOperation.READ;
 import static org.apache.ignite.internal.processors.cache.GridCacheOperation.TRANSFORM;
 import static org.apache.ignite.internal.processors.cache.GridCacheOperation.UPDATE;
+import static org.apache.ignite.internal.util.lang.GridFunc.isEmpty;
 import static org.apache.ignite.transactions.TransactionState.PREPARED;
 
 /**
@@ -1001,7 +1003,7 @@
      * @return {@code True} if {@code done} flag was changed as a result of this call.
      */
     private boolean onComplete(@Nullable GridNearTxPrepareResponse res) {
-        if ((last || tx.isSystemInvalidate()) && !(tx.near() && tx.local()))
+        if (!tx.onePhaseCommit() && ((last || tx.isSystemInvalidate()) && !(tx.near() && tx.local())))
             tx.state(PREPARED);
 
         if (super.onDone(res, res == null ? err : null)) {
@@ -1045,6 +1047,24 @@
 
         this.req = req;
 
+        ClusterNode node = cctx.discovery().node(tx.topologyVersion(), tx.nearNodeId());
+
+        boolean validateCache = needCacheValidation(node);
+
+        if (validateCache) {
+            GridDhtTopologyFuture topFut = cctx.exchange().lastFinishedFuture();
+
+            if (topFut != null && !isEmpty(req.writes())) {
+                // All caches either read only or not. So validation of one cache context is enough.
+                GridCacheContext ctx = F.first(req.writes()).context();
+
+                Throwable err = topFut.validateCache(ctx, req.recovery(), isEmpty(req.writes()), null, null);
+
+                if (err != null)
+                    onDone(null, new IgniteCheckedException(err));
+            }
+        }
+
         boolean ser = tx.serializable() && tx.optimistic();
 
         if (!F.isEmpty(req.writes()) || (ser && !F.isEmpty(req.reads()))) {
@@ -1077,6 +1097,22 @@
     }
 
     /**
+     * Returns {@code true} if cache validation needed.
+     *
+     * @param node Originating node.
+     * @return {@code True} if cache should be validated, {@code false} - otherwise.
+     */
+    private boolean needCacheValidation(ClusterNode node) {
+        if (node == null) {
+            // The originating (aka near) node has left the topology
+            // and therefore the cache validation doesn't make sense.
+            return false;
+        }
+
+        return Boolean.TRUE.equals(node.attribute(ATTR_VALIDATE_CACHE_REQUESTS));
+    }
+
+    /**
      * Checks if this transaction needs previous value for the given tx entry. Will use passed in map to store
      * required key or will create new map if passed in map is {@code null}.
      *
@@ -1275,8 +1311,14 @@
             if (isDone())
                 return;
 
-            if (last)
+            if (last) {
+                recheckOnePhaseCommit();
+
+                if (tx.onePhaseCommit())
+                    tx.chainState(PREPARED);
+
                 sendPrepareRequests();
+            }
         }
         finally {
             markInitialized();
@@ -1284,9 +1326,9 @@
     }
 
     /**
-     *
+     * Checking that one phase commit for transaction still actual.
      */
-    private void sendPrepareRequests() {
+    private void recheckOnePhaseCommit() {
         if (tx.onePhaseCommit() && !tx.nearMap().isEmpty()) {
             for (GridDistributedTxMapping nearMapping : tx.nearMap().values()) {
                 if (!tx.dhtMap().containsKey(nearMapping.primary().id())) {
@@ -1296,7 +1338,12 @@
                 }
             }
         }
+    }
 
+    /**
+     *
+     */
+    private void sendPrepareRequests() {
         assert !tx.txState().mvccEnabled() || !tx.onePhaseCommit() || tx.mvccSnapshot() != null;
 
         int miniId = 0;
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridPartitionedGetFuture.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridPartitionedGetFuture.java
index 2fcd677..0629754 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridPartitionedGetFuture.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridPartitionedGetFuture.java
@@ -23,10 +23,9 @@
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.UUID;
-import java.util.concurrent.atomic.AtomicReference;
 import org.apache.ignite.IgniteCheckedException;
-import org.apache.ignite.IgniteLogger;
 import org.apache.ignite.cluster.ClusterNode;
 import org.apache.ignite.internal.IgniteInternalFuture;
 import org.apache.ignite.internal.cluster.ClusterTopologyCheckedException;
@@ -43,7 +42,6 @@
 import org.apache.ignite.internal.processors.cache.KeyCacheObject;
 import org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridDhtInvalidPartitionException;
 import org.apache.ignite.internal.processors.cache.distributed.near.GridNearGetRequest;
-import org.apache.ignite.internal.processors.cache.distributed.near.GridNearGetResponse;
 import org.apache.ignite.internal.processors.cache.mvcc.MvccQueryTracker;
 import org.apache.ignite.internal.processors.cache.mvcc.MvccQueryTrackerImpl;
 import org.apache.ignite.internal.processors.cache.mvcc.MvccSnapshot;
@@ -52,17 +50,10 @@
 import org.apache.ignite.internal.processors.cache.version.GridCacheVersion;
 import org.apache.ignite.internal.util.GridLeanMap;
 import org.apache.ignite.internal.util.future.GridFinishedFuture;
-import org.apache.ignite.internal.util.future.GridFutureAdapter;
-import org.apache.ignite.internal.util.tostring.GridToStringInclude;
-import org.apache.ignite.internal.util.typedef.C1;
-import org.apache.ignite.internal.util.typedef.CI1;
-import org.apache.ignite.internal.util.typedef.CIX1;
 import org.apache.ignite.internal.util.typedef.F;
-import org.apache.ignite.internal.util.typedef.P1;
 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.IgniteInClosure;
 import org.apache.ignite.lang.IgniteUuid;
 import org.jetbrains.annotations.Nullable;
 
@@ -71,17 +62,9 @@
  */
 public class GridPartitionedGetFuture<K, V> extends CacheDistributedGetFutureAdapter<K, V>
     implements MvccSnapshotResponseListener {
-    /** */
-    private static final long serialVersionUID = 0L;
-
-    /** Logger reference. */
-    private static final AtomicReference<IgniteLogger> logRef = new AtomicReference<>();
-
-    /** Logger. */
-    private static IgniteLogger log;
 
     /** Transaction label. */
-    private String txLbl;
+    protected final String txLbl;
 
     /** */
     protected final MvccSnapshot mvccSnapshot;
@@ -122,7 +105,8 @@
         @Nullable String txLbl,
         @Nullable MvccSnapshot mvccSnapshot
     ) {
-        super(cctx,
+        super(
+            cctx,
             keys,
             readThrough,
             forcePrimary,
@@ -133,15 +117,16 @@
             skipVals,
             needVer,
             keepCacheObjects,
-            recovery);
+            recovery
+        );
+
         assert mvccSnapshot == null || cctx.mvccEnabled();
 
         this.mvccSnapshot = mvccSnapshot;
 
         this.txLbl = txLbl;
 
-        if (log == null)
-            log = U.logger(cctx.kernalContext(), logRef, GridPartitionedGetFuture.class);
+        initLogger(GridPartitionedGetFuture.class);
     }
 
     /**
@@ -169,14 +154,15 @@
     public void init(AffinityTopologyVersion topVer) {
         AffinityTopologyVersion lockedTopVer = cctx.shared().lockedTopologyVersion(null);
 
+        // Can not remap if we in transaction and locked on some topology.
         if (lockedTopVer != null) {
             topVer = lockedTopVer;
 
             canRemap = false;
         }
-        else {
-            topVer = topVer.topologyVersion() > 0 ? topVer :
-                canRemap ? cctx.affinity().affinityTopologyVersion() : cctx.shared().exchange().readyAffinityVersion();
+        else{
+            // Use affinity topology version if constructor version is not specify.
+            topVer = topVer.topologyVersion() > 0 ? topVer : cctx.affinity().affinityTopologyVersion();
         }
 
         if (!cctx.mvccEnabled() || mvccSnapshot != null)
@@ -184,14 +170,22 @@
         else {
             mvccTracker = new MvccQueryTrackerImpl(cctx, canRemap);
 
-            trackable = true;
-
-            cctx.mvcc().addFuture(this, futId);
+            registrateFutureInMvccManager(this);
 
             mvccTracker.requestSnapshot(topVer, this);
         }
     }
 
+    /**
+     * @param topVer Topology version.
+     */
+    private void initialMap(AffinityTopologyVersion topVer) {
+        map(keys, Collections.emptyMap(), topVer);
+
+        markInitialized();
+    }
+
+    /** {@inheritDoc} */
     @Override public void onResponse(MvccSnapshot res) {
         AffinityTopologyVersion topVer = mvccTracker.topologyVersion();
 
@@ -200,76 +194,19 @@
         initialMap(topVer);
     }
 
+    /** {@inheritDoc} */
     @Override public void onError(IgniteCheckedException e) {
         onDone(e);
     }
 
-    /**
-     * @param topVer Topology version.
-     */
-    private void initialMap(AffinityTopologyVersion topVer) {
-        map(keys, Collections.<ClusterNode, LinkedHashMap<KeyCacheObject, Boolean>>emptyMap(), topVer);
-
-        markInitialized();
-    }
-
-    /** {@inheritDoc} */
-    @Override public boolean trackable() {
-        return trackable;
-    }
-
-    /** {@inheritDoc} */
-    @Override public void markNotTrackable() {
-        // Should not flip trackable flag from true to false since get future can be remapped.
-    }
-
-    /** {@inheritDoc} */
-    @Override public IgniteUuid futureId() {
-        return futId;
-    }
-
-    /** {@inheritDoc} */
-    @Override public boolean onNodeLeft(UUID nodeId) {
-        boolean found = false;
-
-        for (IgniteInternalFuture<Map<K, V>> fut : futures())
-            if (isMini(fut)) {
-                MiniFuture f = (MiniFuture)fut;
-
-                if (f.node().id().equals(nodeId)) {
-                    found = true;
-
-                    f.onNodeLeft(new ClusterTopologyCheckedException("Remote node left grid (will retry): " + nodeId));
-                }
-            }
-
-        return found;
-    }
-
-    /**
-     * @param nodeId Sender.
-     * @param res Result.
-     */
-    @Override public void onResult(UUID nodeId, GridNearGetResponse res) {
-        for (IgniteInternalFuture<Map<K, V>> fut : futures()) {
-            if (isMini(fut)) {
-                MiniFuture f = (MiniFuture)fut;
-
-                if (f.futureId().equals(res.miniId())) {
-                    assert f.node().id().equals(nodeId);
-
-                    f.onResult(res);
-                }
-            }
-        }
-    }
-
     /** {@inheritDoc} */
     @Override public boolean onDone(Map<K, V> res, Throwable err) {
         if (super.onDone(res, err)) {
             if (trackable)
                 cctx.mvcc().removeFuture(futId);
 
+            MvccQueryTracker mvccTracker = this.mvccTracker;
+
             if (mvccTracker != null)
                 mvccTracker.onDone();
 
@@ -281,11 +218,8 @@
         return false;
     }
 
-    /**
-     * @param f Future.
-     * @return {@code True} if mini-future.
-     */
-    private boolean isMini(IgniteInternalFuture<?> f) {
+    /** {@inheritDoc} */
+    @Override protected boolean isMini(IgniteInternalFuture<?> f) {
         return f.getClass().equals(MiniFuture.class);
     }
 
@@ -294,68 +228,60 @@
      * @param mapped Mappings to check for duplicates.
      * @param topVer Topology version on which keys should be mapped.
      */
-    private void map(
+    @Override protected void map(
         Collection<KeyCacheObject> keys,
         Map<ClusterNode, LinkedHashMap<KeyCacheObject, Boolean>> mapped,
-        final AffinityTopologyVersion topVer
+        AffinityTopologyVersion topVer
     ) {
         Collection<ClusterNode> cacheNodes = CU.affinityNodes(cctx, topVer);
 
-        if (cacheNodes.isEmpty()) {
-            onDone(new ClusterTopologyServerNotFoundException("Failed to map keys for cache " +
-                "(all partition nodes left the grid) [topVer=" + topVer + ", cache=" + cctx.name() + ']'));
+        validate(cacheNodes, topVer);
 
-            return;
-        }
-
-        GridDhtTopologyFuture topFut = cctx.shared().exchange().lastFinishedFuture();
-
-        Throwable err = topFut != null ? topFut.validateCache(cctx, recovery, true, null, keys) : null;
-
-        if (err != null) {
-            onDone(err);
-
-            return;
-        }
-
-        Map<ClusterNode, LinkedHashMap<KeyCacheObject, Boolean>> mappings = U.newHashMap(cacheNodes.size());
-
-        final int keysSize = keys.size();
-
-        Map<K, V> locVals = U.newHashMap(keysSize);
-
-        boolean hasRmtNodes = false;
-
-        // Assign keys to primary nodes.
-        for (KeyCacheObject key : keys)
-            hasRmtNodes |= map(key, mappings, locVals, topVer, mapped);
-
+        // Future can be already done with some exception.
         if (isDone())
             return;
 
+        Map<ClusterNode, LinkedHashMap<KeyCacheObject, Boolean>> mappings = U.newHashMap(cacheNodes.size());
+
+        int keysSize = keys.size();
+
+        // Map for local (key,value) pairs.
+        Map<K, V> locVals = U.newHashMap(keysSize);
+
+        // True if we have remote nodes after key mapping complete.
+        boolean hasRmtNodes = false;
+
+        // Assign keys to nodes.
+        for (KeyCacheObject key : keys)
+            hasRmtNodes |= map(key, topVer, mappings, mapped, locVals);
+
+        // Future can be alredy done with some exception.
+        if (isDone())
+            return;
+
+        // Add local read (key,value) in result.
         if (!locVals.isEmpty())
             add(new GridFinishedFuture<>(locVals));
 
-        if (hasRmtNodes) {
-            if (!trackable) {
-                trackable = true;
+        // If we have remote nodes in mapping we should registrate future in mvcc manager.
+        if (hasRmtNodes)
+            registrateFutureInMvccManager(this);
 
-                cctx.mvcc().addFuture(this, futId);
-            }
-        }
-
-        // Create mini futures.
+        // Create mini futures after mapping to remote nodes.
         for (Map.Entry<ClusterNode, LinkedHashMap<KeyCacheObject, Boolean>> entry : mappings.entrySet()) {
-            final ClusterNode n = entry.getKey();
+            // Node for request.
+            ClusterNode n = entry.getKey();
 
-            final LinkedHashMap<KeyCacheObject, Boolean> mappedKeys = entry.getValue();
+            // Keys for request.
+            LinkedHashMap<KeyCacheObject, Boolean> mappedKeys = entry.getValue();
 
             assert !mappedKeys.isEmpty();
 
             // If this is the primary or backup node for the keys.
             if (n.isLocal()) {
-                final GridDhtFuture<Collection<GridCacheEntryInfo>> fut =
-                    cache().getDhtAsync(n.id(),
+                GridDhtFuture<Collection<GridCacheEntryInfo>> fut = cache()
+                    .getDhtAsync(
+                        n.id(),
                         -1,
                         mappedKeys,
                         false,
@@ -367,68 +293,50 @@
                         skipVals,
                         recovery,
                         txLbl,
-                        mvccSnapshot());
+                        mvccSnapshot()
+                    );
 
-                final Collection<Integer> invalidParts = fut.invalidPartitions();
+                Collection<Integer> invalidParts = fut.invalidPartitions();
 
                 if (!F.isEmpty(invalidParts)) {
                     Collection<KeyCacheObject> remapKeys = new ArrayList<>(keysSize);
 
                     for (KeyCacheObject key : keys) {
-                        if (key != null && invalidParts.contains(cctx.affinity().partition(key)))
+                        int part = cctx.affinity().partition(key);
+
+                        if (key != null && invalidParts.contains(part)) {
+                            addNodeAsInvalid(n, part, topVer);
+
                             remapKeys.add(key);
+                        }
                     }
 
                     AffinityTopologyVersion updTopVer = cctx.shared().exchange().readyAffinityVersion();
 
-                    assert updTopVer.compareTo(topVer) > 0 : "Got invalid partitions for local node but topology version did " +
-                        "not change [topVer=" + topVer + ", updTopVer=" + updTopVer +
-                        ", invalidParts=" + invalidParts + ']';
-
                     // Remap recursively.
                     map(remapKeys, mappings, updTopVer);
                 }
 
                 // Add new future.
-                add(fut.chain(new C1<IgniteInternalFuture<Collection<GridCacheEntryInfo>>, Map<K, V>>() {
-                    @Override public Map<K, V> apply(IgniteInternalFuture<Collection<GridCacheEntryInfo>> fut) {
-                        try {
-                            return createResultMap(fut.get());
-                        }
-                        catch (Exception e) {
-                            U.error(log, "Failed to get values from dht cache [fut=" + fut + "]", e);
+                add(fut.chain(f -> {
+                    try {
+                        return createResultMap(f.get());
+                    }
+                    catch (Exception e) {
+                        U.error(log, "Failed to get values from dht cache [fut=" + fut + "]", e);
 
-                            onDone(e);
+                        onDone(e);
 
-                            return Collections.emptyMap();
-                        }
+                        return Collections.emptyMap();
                     }
                 }));
             }
             else {
-                MiniFuture fut = new MiniFuture(n, mappedKeys, topVer,
-                    CU.createBackupPostProcessingClosure(topVer, log, cctx, null, expiryPlc, readThrough, skipVals));
+                MiniFuture miniFut = new MiniFuture(n, mappedKeys, topVer);
 
-                GridCacheMessage req = new GridNearGetRequest(
-                    cctx.cacheId(),
-                    futId,
-                    fut.futureId(),
-                    null,
-                    mappedKeys,
-                    readThrough,
-                    topVer,
-                    subjId,
-                    taskName == null ? 0 : taskName.hashCode(),
-                    expiryPlc != null ? expiryPlc.forCreate() : -1L,
-                    expiryPlc != null ? expiryPlc.forAccess() : -1L,
-                    false,
-                    skipVals,
-                    cctx.deploymentEnabled(),
-                    recovery,
-                    txLbl,
-                    mvccSnapshot());
+                GridCacheMessage req = miniFut.createGetRequest(futId);
 
-                add(fut); // Append new future.
+                add(miniFut); // Append new future.
 
                 try {
                     cctx.io().send(n, req, cctx.ioPolicy());
@@ -436,83 +344,118 @@
                 catch (IgniteCheckedException e) {
                     // Fail the whole thing.
                     if (e instanceof ClusterTopologyCheckedException)
-                        fut.onNodeLeft((ClusterTopologyCheckedException)e);
+                        miniFut.onNodeLeft((ClusterTopologyCheckedException)e);
                     else
-                        fut.onResult(e);
+                        miniFut.onResult(e);
                 }
             }
         }
     }
 
     /**
-     * @param mappings Mappings.
+     * @param nodesToKeysMapping Mappings.
      * @param key Key to map.
      * @param locVals Local values.
      * @param topVer Topology version.
-     * @param mapped Previously mapped.
+     * @param missedNodesToKeysMapping Previously mapped.
      * @return {@code True} if has remote nodes.
      */
     private boolean map(
         KeyCacheObject key,
-        Map<ClusterNode, LinkedHashMap<KeyCacheObject, Boolean>> mappings,
-        Map<K, V> locVals,
         AffinityTopologyVersion topVer,
-        Map<ClusterNode, LinkedHashMap<KeyCacheObject, Boolean>> mapped
+        Map<ClusterNode, LinkedHashMap<KeyCacheObject, Boolean>> nodesToKeysMapping,
+        Map<ClusterNode, LinkedHashMap<KeyCacheObject, Boolean>> missedNodesToKeysMapping,
+        Map<K, V> locVals
     ) {
         int part = cctx.affinity().partition(key);
 
         List<ClusterNode> affNodes = cctx.affinity().nodesByPartition(part, topVer);
 
+        // Failed if none affinity node found.
         if (affNodes.isEmpty()) {
             onDone(serverNotFoundError(part, topVer));
 
             return false;
         }
 
-        // Local get cannot be used with MVCC as local node can contain some visible version which is not latest.
-        boolean fastLocGet = !cctx.mvccEnabled() && (!forcePrimary || affNodes.get(0).isLocal()) &&
-            cctx.reserveForFastLocalGet(part, topVer);
+        // Try to read key localy if we can.
+        if (tryLocalGet(key, part, topVer, affNodes, locVals))
+            return false;
 
-        if (fastLocGet) {
-            try {
-                if (localGet(topVer, key, part, locVals))
-                    return false;
-            }
-            finally {
-                cctx.releaseForFastLocalGet(part, topVer);
-            }
-        }
+        Set<ClusterNode> invalidNodeSet = getInvalidNodes(part, topVer);
 
-        ClusterNode node = cctx.selectAffinityNodeBalanced(affNodes, part, canRemap);
+        // Get remote node for request for this key.
+        ClusterNode node = cctx.selectAffinityNodeBalanced(affNodes, invalidNodeSet, part, canRemap);
 
+        // Failed if none remote node found.
         if (node == null) {
             onDone(serverNotFoundError(part, topVer));
 
             return false;
         }
 
+        // The node still can be local, see details implementation of #tryLocalGet().
         boolean remote = !node.isLocal();
 
-        LinkedHashMap<KeyCacheObject, Boolean> keys = mapped.get(node);
+        // Check retry counter, bound for avoid inifinit remap.
+        if (!checkRetryPermits(key, node, missedNodesToKeysMapping))
+            return false;
 
-        if (keys != null && keys.containsKey(key)) {
-            if (REMAP_CNT_UPD.incrementAndGet(this) > MAX_REMAP_CNT) {
-                onDone(new ClusterTopologyCheckedException("Failed to remap key to a new node after " +
-                    MAX_REMAP_CNT + " attempts (key got remapped to the same node) [key=" + key + ", node=" +
-                    U.toShortString(node) + ", mappings=" + mapped + ']'));
+        addNodeMapping(key, node, nodesToKeysMapping);
 
-                return false;
-            }
-        }
+        return remote;
+    }
 
+    /**
+     *
+     * @param key Key.
+     * @param node Mapped node.
+     * @param mappings Full node mapping.
+     */
+    private void addNodeMapping(
+        KeyCacheObject key,
+        ClusterNode node,
+        Map<ClusterNode, LinkedHashMap<KeyCacheObject, Boolean>> mappings
+    ) {
         LinkedHashMap<KeyCacheObject, Boolean> old = mappings.get(node);
 
         if (old == null)
             mappings.put(node, old = new LinkedHashMap<>(3, 1f));
 
         old.put(key, false);
+    }
 
-        return remote;
+    /**
+     *
+     * @param key Key.
+     * @param part Partition.
+     * @param topVer Topology version.
+     * @param affNodes Affynity nodes.
+     * @param locVals Map for local (key,value) pairs.
+     */
+    private boolean tryLocalGet(
+        KeyCacheObject key,
+        int part,
+        AffinityTopologyVersion topVer,
+        List<ClusterNode> affNodes,
+        Map<K, V> locVals
+    ) {
+        // Local get cannot be used with MVCC as local node can contain some visible version which is not latest.
+        boolean fastLocGet = !cctx.mvccEnabled() &&
+            (!forcePrimary || affNodes.get(0).isLocal()) &&
+            cctx.reserveForFastLocalGet(part, topVer);
+
+        if (fastLocGet) {
+            try {
+                if (localGet(topVer, key, part, locVals))
+                    return true;
+            }
+            finally {
+                cctx.releaseForFastLocalGet(part, topVer);
+            }
+        }
+
+        return false;
     }
 
     /**
@@ -662,6 +605,27 @@
     }
 
     /**
+     *
+     * @param cacheNodes Cache affynity nodes.
+     * @param topVer Topology version.
+     */
+    private void validate(Collection<ClusterNode> cacheNodes, AffinityTopologyVersion topVer) {
+        if (cacheNodes.isEmpty()) {
+            onDone(new ClusterTopologyServerNotFoundException("Failed to map keys for cache " +
+                "(all partition nodes left the grid) [topVer=" + topVer + ", cache=" + cctx.name() + ']'));
+
+            return;
+        }
+
+        GridDhtTopologyFuture topFut = cctx.shared().exchange().lastFinishedFuture();
+
+        Throwable err = topFut != null ? topFut.validateCache(cctx, recovery, true, null, keys) : null;
+
+        if (err != null)
+            onDone(err);
+    }
+
+    /**
      * @return Near cache.
      */
     private GridDhtCacheAdapter<K, V> cache() {
@@ -701,21 +665,7 @@
 
     /** {@inheritDoc} */
     @Override public String toString() {
-        Collection<String> futs = F.viewReadOnly(futures(), new C1<IgniteInternalFuture<?>, String>() {
-            @SuppressWarnings("unchecked")
-            @Override public String apply(IgniteInternalFuture<?> f) {
-                if (isMini(f)) {
-                    return "[node=" + ((MiniFuture)f).node().id() +
-                        ", loc=" + ((MiniFuture)f).node().isLocal() +
-                        ", done=" + f.isDone() + "]";
-                }
-                else
-                    return "[loc=true, done=" + f.isDone() + "]";
-            }
-        });
-
         return S.toString(GridPartitionedGetFuture.class, this,
-            "innerFuts", futs,
             "super", super.toString());
     }
 
@@ -723,197 +673,46 @@
      * Mini-future for get operations. Mini-futures are only waiting on a single
      * node as opposed to multiple nodes.
      */
-    private class MiniFuture extends GridFutureAdapter<Map<K, V>> {
-        /** */
-        private final IgniteUuid futId = IgniteUuid.randomUuid();
-
-        /** Node ID. */
-        private final ClusterNode node;
-
-        /** Keys. */
-        @GridToStringInclude
-        private final LinkedHashMap<KeyCacheObject, Boolean> keys;
-
-        /** Topology version on which this future was mapped. */
-        private final AffinityTopologyVersion topVer;
-
-        /** Post processing closure. */
-        private final IgniteInClosure<Collection<GridCacheEntryInfo>> postProcessingClos;
-
-        /** {@code True} if remapped after node left. */
-        private boolean remapped;
-
+    private class MiniFuture extends AbstractMiniFuture {
         /**
          * @param node Node.
          * @param keys Keys.
          * @param topVer Topology version.
-         * @param postProcessingClos Post processing closure.
          */
-        MiniFuture(ClusterNode node, LinkedHashMap<KeyCacheObject, Boolean> keys, AffinityTopologyVersion topVer,
-            @Nullable IgniteInClosure<Collection<GridCacheEntryInfo>> postProcessingClos) {
-            this.node = node;
-            this.keys = keys;
-            this.topVer = topVer;
-            this.postProcessingClos = postProcessingClos;
+        public MiniFuture(
+            ClusterNode node,
+            LinkedHashMap<KeyCacheObject, Boolean> keys,
+            AffinityTopologyVersion topVer
+        ) {
+            super(node, keys, topVer);
         }
 
-        /**
-         * @return Future ID.
-         */
-        IgniteUuid futureId() {
-            return futId;
+        /** {@inheritDoc} */
+        @Override protected GridNearGetRequest createGetRequest0(IgniteUuid rootFutId, IgniteUuid futId) {
+            return new GridNearGetRequest(
+                cctx.cacheId(),
+                rootFutId,
+                futId,
+                null,
+                keys,
+                readThrough,
+                topVer,
+                subjId,
+                taskName == null ? 0 : taskName.hashCode(),
+                expiryPlc != null ? expiryPlc.forCreate() : -1L,
+                expiryPlc != null ? expiryPlc.forAccess() : -1L,
+                false,
+                skipVals,
+                cctx.deploymentEnabled(),
+                recovery,
+                txLbl,
+                mvccSnapshot()
+            );
         }
 
-        /**
-         * @return Node ID.
-         */
-        public ClusterNode node() {
-            return node;
-        }
-
-        /**
-         * @return Keys.
-         */
-        public Collection<KeyCacheObject> keys() {
-            return keys.keySet();
-        }
-
-        /**
-         * @param e Error.
-         */
-        void onResult(Throwable e) {
-            if (log.isDebugEnabled())
-                log.debug("Failed to get future result [fut=" + this + ", err=" + e + ']');
-
-            // Fail.
-            onDone(e);
-        }
-
-        /**
-         * @param e Failure exception.
-         */
-        synchronized void onNodeLeft(ClusterTopologyCheckedException e) {
-            if (remapped)
-                return;
-
-            remapped = true;
-
-            if (log.isDebugEnabled())
-                log.debug("Remote node left grid while sending or waiting for reply (will retry): " + this);
-
-            // Try getting from existing nodes.
-            if (!canRemap) {
-                map(keys.keySet(), F.t(node, keys), topVer);
-
-                onDone(Collections.<K, V>emptyMap());
-            }
-            else {
-                AffinityTopologyVersion updTopVer =
-                    new AffinityTopologyVersion(Math.max(topVer.topologyVersion() + 1, cctx.discovery().topologyVersion()));
-
-                cctx.shared().exchange().affinityReadyFuture(updTopVer).listen(
-                    new CI1<IgniteInternalFuture<AffinityTopologyVersion>>() {
-                        @Override public void apply(IgniteInternalFuture<AffinityTopologyVersion> fut) {
-                            try {
-                                // Remap.
-                                map(keys.keySet(), F.t(node, keys), fut.get());
-
-                                onDone(Collections.<K, V>emptyMap());
-                            }
-                            catch (IgniteCheckedException e) {
-                                GridPartitionedGetFuture.this.onDone(e);
-                            }
-                        }
-                    }
-                );
-            }
-        }
-
-        /**
-         * @param res Result callback.
-         */
-        void onResult(final GridNearGetResponse res) {
-            final Collection<Integer> invalidParts = res.invalidPartitions();
-
-            // If error happened on remote node, fail the whole future.
-            if (res.error() != null) {
-                onDone(res.error());
-
-                return;
-            }
-
-            // Remap invalid partitions.
-            if (!F.isEmpty(invalidParts)) {
-                AffinityTopologyVersion rmtTopVer = res.topologyVersion();
-
-                assert !rmtTopVer.equals(AffinityTopologyVersion.ZERO);
-
-                if (rmtTopVer.compareTo(topVer) <= 0) {
-                    // Fail the whole get future.
-                    onDone(new IgniteCheckedException("Failed to process invalid partitions response (remote node reported " +
-                        "invalid partitions but remote topology version does not differ from local) " +
-                        "[topVer=" + topVer + ", rmtTopVer=" + rmtTopVer + ", invalidParts=" + invalidParts +
-                        ", nodeId=" + node.id() + ']'));
-
-                    return;
-                }
-
-                if (log.isDebugEnabled())
-                    log.debug("Remapping mini get future [invalidParts=" + invalidParts + ", fut=" + this + ']');
-
-                if (!canRemap) {
-                    map(F.view(keys.keySet(), new P1<KeyCacheObject>() {
-                        @Override public boolean apply(KeyCacheObject key) {
-                            return invalidParts.contains(cctx.affinity().partition(key));
-                        }
-                    }), F.t(node, keys), topVer);
-
-                    postProcessResult(res);
-
-                    onDone(createResultMap(res.entries()));
-
-                    return;
-                }
-
-                // Need to wait for next topology version to remap.
-                IgniteInternalFuture<AffinityTopologyVersion> topFut = cctx.shared().exchange().affinityReadyFuture(rmtTopVer);
-
-                topFut.listen(new CIX1<IgniteInternalFuture<AffinityTopologyVersion>>() {
-                    @Override public void applyx(
-                        IgniteInternalFuture<AffinityTopologyVersion> fut) throws IgniteCheckedException {
-                        AffinityTopologyVersion topVer = fut.get();
-
-                        // This will append new futures to compound list.
-                        map(F.view(keys.keySet(), new P1<KeyCacheObject>() {
-                            @Override public boolean apply(KeyCacheObject key) {
-                                return invalidParts.contains(cctx.affinity().partition(key));
-                            }
-                        }), F.t(node, keys), topVer);
-
-                        postProcessResult(res);
-
-                        onDone(createResultMap(res.entries()));
-                    }
-                });
-            }
-            else {
-                try {
-                    postProcessResult(res);
-
-                    onDone(createResultMap(res.entries()));
-                }
-                catch (Exception e) {
-                    onDone(e);
-                }
-            }
-        }
-
-        /**
-         * @param res Response.
-         */
-        private void postProcessResult(final GridNearGetResponse res) {
-            if (postProcessingClos != null)
-                postProcessingClos.apply(res.entries());
+        /** {@inheritDoc} */
+        @Override protected Map<K, V> createResultMap(Collection<GridCacheEntryInfo> entries) {
+            return GridPartitionedGetFuture.this.createResultMap(entries);
         }
 
         /** {@inheritDoc} */
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 4d0e129..0d69485 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
@@ -18,8 +18,12 @@
 package org.apache.ignite.internal.processors.cache.distributed.dht;
 
 import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 import java.util.UUID;
+import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
 import java.util.concurrent.atomic.AtomicReference;
 import org.apache.ignite.IgniteCheckedException;
 import org.apache.ignite.IgniteLogger;
@@ -51,8 +55,6 @@
 import org.apache.ignite.internal.processors.cache.persistence.CacheDataRow;
 import org.apache.ignite.internal.processors.cache.version.GridCacheVersion;
 import org.apache.ignite.internal.util.tostring.GridToStringInclude;
-import org.apache.ignite.internal.util.typedef.CI1;
-import org.apache.ignite.internal.util.typedef.CIX1;
 import org.apache.ignite.internal.util.typedef.F;
 import org.apache.ignite.internal.util.typedef.internal.CU;
 import org.apache.ignite.internal.util.typedef.internal.S;
@@ -61,13 +63,25 @@
 import org.apache.ignite.plugin.extensions.communication.Message;
 import org.jetbrains.annotations.Nullable;
 
+import static org.apache.ignite.IgniteSystemProperties.IGNITE_NEAR_GET_MAX_REMAPS;
+import static org.apache.ignite.IgniteSystemProperties.getInteger;
 import static org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridDhtPartitionState.OWNING;
 
 /**
  *
  */
-public class GridPartitionedSingleGetFuture extends GridCacheFutureAdapter<Object> implements GridCacheFuture<Object>,
-    CacheGetFuture, IgniteDiagnosticAware {
+public class GridPartitionedSingleGetFuture extends GridCacheFutureAdapter<Object>
+    implements CacheGetFuture, IgniteDiagnosticAware {
+    /** Default max remap count value. */
+    public static final int DFLT_MAX_REMAP_CNT = 3;
+
+    /** Maximum number of attempts to remap key to the same primary node. */
+    protected static final int MAX_REMAP_CNT = getInteger(IGNITE_NEAR_GET_MAX_REMAPS, DFLT_MAX_REMAP_CNT);
+
+    /** Remap count updater. */
+    protected static final AtomicIntegerFieldUpdater<GridPartitionedSingleGetFuture> REMAP_CNT_UPD =
+        AtomicIntegerFieldUpdater.newUpdater(GridPartitionedSingleGetFuture.class, "remapCnt");
+
     /** Logger reference. */
     private static final AtomicReference<IgniteLogger> logRef = new AtomicReference<>();
 
@@ -133,7 +147,13 @@
     private volatile BackupPostProcessingClosure postProcessingClos;
 
     /** Transaction label. */
-    private String txLbl;
+    private final String txLbl;
+
+    /** Invalid mappened nodes. */
+    private Set<ClusterNode> invalidNodes = Collections.emptySet();
+
+    /** Remap count. */
+    protected volatile int remapCnt;
 
     /**
      * @param cctx Context.
@@ -204,30 +224,30 @@
     }
 
     /**
-     *
+     * Initialize future.
      */
     public void init() {
-        AffinityTopologyVersion topVer = this.topVer.topologyVersion() > 0 ? this.topVer :
-            canRemap ? cctx.affinity().affinityTopologyVersion() : cctx.shared().exchange().readyAffinityVersion();
+        AffinityTopologyVersion mappingtopVermappingtopVer;
 
-        GridDhtTopologyFuture topFut = cctx.shared().exchange().lastFinishedFuture();
-
-        Throwable err = topFut != null ? topFut.validateCache(cctx, recovery, true, key, null) : null;
-
-        if (err != null) {
-            onDone(err);
-
-            return;
+        if (topVer.topologyVersion() > 0)
+            mappingtopVermappingtopVer = topVer;
+        else {
+            mappingtopVermappingtopVer = canRemap ?
+                cctx.affinity().affinityTopologyVersion() :
+                cctx.shared().exchange().readyAffinityVersion();
         }
 
-        map(topVer);
+        map(mappingtopVermappingtopVer);
     }
 
     /**
      * @param topVer Topology version.
      */
     @SuppressWarnings("unchecked")
-    private void map(final AffinityTopologyVersion topVer) {
+    private void map(AffinityTopologyVersion topVer) {
+        if (!validate(topVer))
+            return;
+
         ClusterNode node = mapKeyToNode(topVer);
 
         if (node == null) {
@@ -239,46 +259,46 @@
         if (isDone())
             return;
 
+        // Read value if node is localNode.
         if (node.isLocal()) {
-            final GridDhtFuture<GridCacheEntryInfo> fut = cctx.dht().getDhtSingleAsync(node.id(),
-                -1,
-                key,
-                false,
-                readThrough,
-                topVer,
-                subjId,
-                taskName == null ? 0 : taskName.hashCode(),
-                expiryPlc,
-                skipVals,
-                recovery,
-                txLbl,
-                mvccSnapshot);
+            GridDhtFuture<GridCacheEntryInfo> fut = cctx.dht()
+                .getDhtSingleAsync(
+                    node.id(),
+                    -1,
+                    key,
+                    false,
+                    readThrough,
+                    topVer,
+                    subjId,
+                    taskName == null ? 0 : taskName.hashCode(),
+                    expiryPlc,
+                    skipVals,
+                    recovery,
+                    txLbl,
+                    mvccSnapshot
+                );
 
-            final Collection<Integer> invalidParts = fut.invalidPartitions();
+            Collection<Integer> invalidParts = fut.invalidPartitions();
 
             if (!F.isEmpty(invalidParts)) {
-                AffinityTopologyVersion updTopVer = cctx.shared().exchange().readyAffinityVersion();
+                addNodeAsInvalid(node);
 
-                assert updTopVer.compareTo(topVer) > 0 : "Got invalid partitions for local node but topology " +
-                    "version did not change [topVer=" + topVer + ", updTopVer=" + updTopVer +
-                    ", invalidParts=" + invalidParts + ']';
+                AffinityTopologyVersion updTopVer = cctx.shared().exchange().readyAffinityVersion();
 
                 // Remap recursively.
                 map(updTopVer);
             }
             else {
-                fut.listen(new CI1<IgniteInternalFuture<GridCacheEntryInfo>>() {
-                    @Override public void apply(IgniteInternalFuture<GridCacheEntryInfo> fut) {
-                        try {
-                            GridCacheEntryInfo info = fut.get();
+                fut.listen(f -> {
+                    try {
+                        GridCacheEntryInfo info = f.get();
 
-                            setResult(info);
-                        }
-                        catch (Exception e) {
-                            U.error(log, "Failed to get values from dht cache [fut=" + fut + "]", e);
+                        setResult(info);
+                    }
+                    catch (Exception e) {
+                        U.error(log, "Failed to get values from dht cache [fut=" + fut + "]", e);
 
-                            onDone(e);
-                        }
+                        onDone(e);
                     }
                 });
             }
@@ -291,15 +311,11 @@
                 this.node = node;
             }
 
-            if (!trackable) {
-                trackable = true;
-
-                cctx.mvcc().addFuture(this, futId);
-            }
+            registrateFutureInMvccManager(this);
 
             boolean needVer = this.needVer;
 
-            final BackupPostProcessingClosure postClos = CU.createBackupPostProcessingClosure(topVer, log,
+            BackupPostProcessingClosure postClos = CU.createBackupPostProcessingClosure(topVer, log,
                 cctx, key, expiryPlc, readThrough, skipVals);
 
             if (postClos != null) {
@@ -309,7 +325,8 @@
                 postProcessingClos = postClos;
             }
 
-            GridCacheMessage req = new GridNearSingleGetRequest(cctx.cacheId(),
+            GridCacheMessage req = new GridNearSingleGetRequest(
+                cctx.cacheId(),
                 futId.localId(),
                 key,
                 readThrough,
@@ -324,7 +341,8 @@
                 cctx.deploymentEnabled(),
                 recovery,
                 txLbl,
-                mvccSnapshot);
+                mvccSnapshot
+            );
 
             try {
                 cctx.io().send(node, req, cctx.ioPolicy());
@@ -347,28 +365,20 @@
 
         List<ClusterNode> affNodes = cctx.affinity().nodesByPartition(part, topVer);
 
+        // Failed if none affinity node found by assigment.
         if (affNodes.isEmpty()) {
             onDone(serverNotFoundError(part, topVer));
 
             return null;
         }
 
-        // Local get cannot be used with MVCC as local node can contain some visible version which is not latest.
-        boolean fastLocGet = !cctx.mvccEnabled() && (!forcePrimary || affNodes.get(0).isLocal()) &&
-            cctx.reserveForFastLocalGet(part, topVer);
+        // Try to read key localy if we can.
+        if (tryLocalGet(key, part, topVer, affNodes))
+            return null;
 
-        if (fastLocGet) {
-            try {
-                if (localGet(topVer, part))
-                    return null;
-            }
-            finally {
-                cctx.releaseForFastLocalGet(part, topVer);
-            }
-        }
+        ClusterNode affNode = cctx.selectAffinityNodeBalanced(affNodes, getInvalidNodes(), part, canRemap);
 
-        ClusterNode affNode = cctx.selectAffinityNodeBalanced(affNodes, part, canRemap);
-
+        // Failed if none balanced node found.
         if (affNode == null) {
             onDone(serverNotFoundError(part, topVer));
 
@@ -379,11 +389,42 @@
     }
 
     /**
+     *
+     * @param key Key.
+     * @param part Partition.
+     * @param topVer Topology version.
+     * @param affNodes Affynity nodes.
+     */
+    private boolean tryLocalGet(
+        KeyCacheObject key,
+        int part,
+        AffinityTopologyVersion topVer,
+        List<ClusterNode> affNodes
+    ) {
+        // Local get cannot be used with MVCC as local node can contain some visible version which is not latest.
+        boolean fastLocGet = !cctx.mvccEnabled() &&
+            (!forcePrimary || affNodes.get(0).isLocal()) &&
+            cctx.reserveForFastLocalGet(part, topVer);
+
+        if (fastLocGet) {
+            try {
+                if (localGet(topVer, key, part))
+                    return true;
+            }
+            finally {
+                cctx.releaseForFastLocalGet(part, topVer);
+            }
+        }
+
+        return false;
+    }
+
+    /**
      * @param topVer Topology version.
      * @param part Partition.
      * @return {@code True} if future completed.
      */
-    private boolean localGet(AffinityTopologyVersion topVer, int part) {
+    private boolean localGet(AffinityTopologyVersion topVer, KeyCacheObject key, int part) {
         assert cctx.affinityNode() : this;
 
         GridDhtCacheAdapter colocated = cctx.dht();
@@ -522,12 +563,28 @@
     }
 
     /**
+     * @param fut Future.
+     */
+    private void registrateFutureInMvccManager(GridCacheFuture<?> fut) {
+        if (!trackable) {
+            trackable = true;
+
+            cctx.mvcc().addFuture(fut, futId);
+        }
+    }
+
+    /**
      * @param nodeId Node ID.
      * @param res Result.
      */
     public void onResult(UUID nodeId, GridNearSingleGetResponse res) {
-        if (!processResponse(nodeId) ||
-            !checkError(res.error(), res.invalidPartitions(), res.topologyVersion(), nodeId))
+        // Brake here if response from unexpected node.
+        if (!processResponse(nodeId))
+            return;
+
+        // Brake here if exception was throws on remote node or
+        // parition on remote node is invalid.
+        if (!checkError(nodeId, res.invalidPartitions(), res.topologyVersion(), res.error()))
             return;
 
         Message res0 = res.result();
@@ -562,13 +619,15 @@
         }
     }
 
-    /**
-     * @param nodeId Node ID.
-     * @param res Result.
-     */
+    /** {@inheritDoc} */
     @Override public void onResult(UUID nodeId, GridNearGetResponse res) {
-        if (!processResponse(nodeId) ||
-            !checkError(res.error(), !F.isEmpty(res.invalidPartitions()), res.topologyVersion(), nodeId))
+        // Brake here if response from unexpected node.
+        if (!processResponse(nodeId))
+            return;
+
+        // Brake here if exception was throws on remote node or
+        // parition on remote node is invalid.
+        if (!checkError(nodeId, !F.isEmpty(res.invalidPartitions()), res.topologyVersion(), res.error()))
             return;
 
         Collection<GridCacheEntryInfo> infos = res.entries();
@@ -601,10 +660,12 @@
      * @param nodeId Node ID.
      * @return {@code True} if should process received response.
      */
-    private boolean checkError(@Nullable IgniteCheckedException err,
+    private boolean checkError(
+        UUID nodeId,
         boolean invalidParts,
         AffinityTopologyVersion rmtTopVer,
-        UUID nodeId) {
+        @Nullable IgniteCheckedException err
+    ) {
         if (err != null) {
             onDone(err);
 
@@ -612,34 +673,10 @@
         }
 
         if (invalidParts) {
-            assert !rmtTopVer.equals(AffinityTopologyVersion.ZERO);
-
-            if (rmtTopVer.compareTo(topVer) <= 0) {
-                // Fail the whole get future.
-                onDone(new IgniteCheckedException("Failed to process invalid partitions response (remote node reported " +
-                    "invalid partitions but remote topology version does not differ from local) " +
-                    "[topVer=" + topVer + ", rmtTopVer=" + rmtTopVer + ", part=" + cctx.affinity().partition(key) +
-                    ", nodeId=" + nodeId + ']'));
-
-                return false;
-            }
+            addNodeAsInvalid(cctx.node(nodeId));
 
             if (canRemap) {
-                IgniteInternalFuture<AffinityTopologyVersion> topFut = cctx.shared().exchange().affinityReadyFuture(rmtTopVer);
-
-                topFut.listen(new CIX1<IgniteInternalFuture<AffinityTopologyVersion>>() {
-                    @Override public void applyx(IgniteInternalFuture<AffinityTopologyVersion> fut) {
-                        try {
-                            AffinityTopologyVersion topVer = fut.get();
-
-                            remap(topVer);
-                        }
-                        catch (IgniteCheckedException e) {
-                            onDone(e);
-                        }
-                    }
-                });
-
+                awaitVersionAndRemap(rmtTopVer);
             }
             else
                 map(topVer);
@@ -728,6 +765,43 @@
     }
 
     /**
+     * @param node Invalid node.
+     */
+    private synchronized void addNodeAsInvalid(ClusterNode node) {
+        if (invalidNodes == Collections.<ClusterNode>emptySet())
+            invalidNodes = new HashSet<>();
+
+        invalidNodes.add(node);
+    }
+
+    /**
+     * @return Set of invalid cluster nodes.
+     */
+    protected synchronized Set<ClusterNode> getInvalidNodes() {
+        return invalidNodes;
+    }
+
+    /**
+     * @param topVer Topology version.
+     */
+    private boolean checkRetryPermits(AffinityTopologyVersion topVer) {
+        if (topVer.equals(this.topVer))
+            return true;
+
+        if (REMAP_CNT_UPD.incrementAndGet(this) > MAX_REMAP_CNT) {
+            ClusterNode node0 = node;
+
+            onDone(new ClusterTopologyCheckedException("Failed to remap key to a new node after " +
+                MAX_REMAP_CNT + " attempts (key got remapped to the same node) [key=" + key + ", node=" +
+                (node0 != null ? U.toShortString(node0) : node0) + ", invalidNodes=" + invalidNodes + ']'));
+
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
      * @param part Partition.
      * @param topVer Topology version.
      * @return Exception.
@@ -737,6 +811,27 @@
             "(all partition nodes left the grid) [topVer=" + topVer + ", part=" + part + ", cache=" + cctx.name() + ']');
     }
 
+    /**
+     * @param topVer Topology version.
+     * @return True if validate success, False is not.
+     */
+    private boolean validate(AffinityTopologyVersion topVer) {
+        if (!checkRetryPermits(topVer))
+            return false;
+
+        GridDhtTopologyFuture lastFut = cctx.shared().exchange().lastFinishedFuture();
+
+        Throwable error = lastFut.validateCache(cctx, recovery, true, key, null);
+
+        if (error != null) {
+            onDone(error);
+
+            return false;
+        }
+        else
+            return true;
+    }
+
     /** {@inheritDoc} */
     @Override public IgniteUuid futureId() {
         return futId;
@@ -748,20 +843,9 @@
             return false;
 
         if (canRemap) {
-            AffinityTopologyVersion updTopVer = new AffinityTopologyVersion(
-                Math.max(topVer.topologyVersion() + 1, cctx.discovery().topologyVersion()));
+            long maxTopVer = Math.max(topVer.topologyVersion() + 1, cctx.discovery().topologyVersion());
 
-            cctx.shared().exchange().affinityReadyFuture(updTopVer).listen(
-                new CI1<IgniteInternalFuture<AffinityTopologyVersion>>() {
-                    @Override public void apply(IgniteInternalFuture<AffinityTopologyVersion> fut) {
-                        try {
-                            remap(fut.get());
-                        }
-                        catch (IgniteCheckedException e) {
-                            onDone(e);
-                        }
-                    }
-                });
+            awaitVersionAndRemap(new AffinityTopologyVersion(maxTopVer));
         }
         else
             remap(topVer);
@@ -772,15 +856,30 @@
     /**
      * @param topVer Topology version.
      */
+    private void awaitVersionAndRemap(AffinityTopologyVersion topVer){
+        IgniteInternalFuture<AffinityTopologyVersion> awaitTopologyVersionFuture =
+            cctx.shared().exchange().affinityReadyFuture(topVer);
+
+        awaitTopologyVersionFuture.listen(f -> {
+            try {
+                remap(f.get());
+            }
+            catch (IgniteCheckedException e) {
+                onDone(e);
+            }
+        });
+    }
+
+    /**
+     * @param topVer Topology version.
+     */
     private void remap(final AffinityTopologyVersion topVer) {
         cctx.closures().runLocalSafe(new Runnable() {
             @Override public void run() {
-                GridDhtTopologyFuture lastFut = cctx.shared().exchange().lastFinishedFuture();
-
-                Throwable error = lastFut.validateCache(cctx, recovery, true, key, null);
-
-                if (error != null)
-                    onDone(error);
+                // If topology changed reset collection of invalid nodes.
+                synchronized (this) {
+                    invalidNodes = Collections.emptySet();
+                }
 
                 map(topVer);
             }
@@ -834,6 +933,6 @@
 
     /** {@inheritDoc} */
     @Override public String toString() {
-        return S.toString(GridPartitionedSingleGetFuture.class, this);
+        return S.toString(GridPartitionedSingleGetFuture.class, this, "super", super.toString());
     }
 }
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridDhtAtomicCache.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridDhtAtomicCache.java
index 74be8e1..6118fbb 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridDhtAtomicCache.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridDhtAtomicCache.java
@@ -42,7 +42,6 @@
 import org.apache.ignite.internal.UnregisteredClassException;
 import org.apache.ignite.internal.cluster.ClusterTopologyCheckedException;
 import org.apache.ignite.internal.mem.IgniteOutOfMemoryException;
-import org.apache.ignite.internal.processors.cache.persistence.StorageException;
 import org.apache.ignite.internal.processors.affinity.AffinityAssignment;
 import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion;
 import org.apache.ignite.internal.processors.cache.CacheEntryPredicate;
@@ -69,12 +68,13 @@
 import org.apache.ignite.internal.processors.cache.distributed.dht.GridDhtCacheAdapter;
 import org.apache.ignite.internal.processors.cache.distributed.dht.GridDhtCacheEntry;
 import org.apache.ignite.internal.processors.cache.distributed.dht.GridDhtFuture;
-import org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridDhtInvalidPartitionException;
-import org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridDhtPartitionTopology;
+import org.apache.ignite.internal.processors.cache.distributed.dht.GridDhtTopologyFuture;
 import org.apache.ignite.internal.processors.cache.distributed.dht.GridPartitionedGetFuture;
 import org.apache.ignite.internal.processors.cache.distributed.dht.GridPartitionedSingleGetFuture;
 import org.apache.ignite.internal.processors.cache.distributed.dht.preloader.GridDhtForceKeysRequest;
 import org.apache.ignite.internal.processors.cache.distributed.dht.preloader.GridDhtForceKeysResponse;
+import org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridDhtInvalidPartitionException;
+import org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridDhtPartitionTopology;
 import org.apache.ignite.internal.processors.cache.distributed.near.GridNearAtomicCache;
 import org.apache.ignite.internal.processors.cache.distributed.near.GridNearCacheAdapter;
 import org.apache.ignite.internal.processors.cache.distributed.near.GridNearGetRequest;
@@ -84,6 +84,7 @@
 import org.apache.ignite.internal.processors.cache.dr.GridCacheDrExpirationInfo;
 import org.apache.ignite.internal.processors.cache.dr.GridCacheDrInfo;
 import org.apache.ignite.internal.processors.cache.persistence.CacheDataRow;
+import org.apache.ignite.internal.processors.cache.persistence.StorageException;
 import org.apache.ignite.internal.processors.cache.transactions.IgniteTxLocalEx;
 import org.apache.ignite.internal.processors.cache.version.GridCacheVersion;
 import org.apache.ignite.internal.processors.cache.version.GridCacheVersionConflictContext;
@@ -120,6 +121,7 @@
 import static org.apache.ignite.IgniteSystemProperties.IGNITE_ATOMIC_DEFERRED_ACK_TIMEOUT;
 import static org.apache.ignite.cache.CacheWriteSynchronizationMode.FULL_ASYNC;
 import static org.apache.ignite.cache.CacheWriteSynchronizationMode.PRIMARY_SYNC;
+import static org.apache.ignite.internal.IgniteNodeAttributes.ATTR_VALIDATE_CACHE_REQUESTS;
 import static org.apache.ignite.internal.processors.cache.GridCacheOperation.DELETE;
 import static org.apache.ignite.internal.processors.cache.GridCacheOperation.TRANSFORM;
 import static org.apache.ignite.internal.processors.cache.GridCacheOperation.UPDATE;
@@ -1773,11 +1775,31 @@
                             if (!req.topologyLocked()) {
                                 // Can not wait for topology future since it will break
                                 // GridNearAtomicCheckUpdateRequest processing.
-                                remap = !top.topologyVersionFuture().exchangeDone() ||
+                                remap = !top.topologyVersionFuture().isDone() ||
                                     needRemap(req.topologyVersion(), top.readyTopologyVersion(), req.keys());
                             }
 
                             if (!remap) {
+                                boolean validateCache = needCacheValidation(node);
+
+                                if (validateCache) {
+                                    GridDhtTopologyFuture topFut = top.topologyVersionFuture();
+
+                                    assert topFut.isDone() : topFut;
+
+                                    Throwable err = topFut.validateCache(ctx, req.recovery(), false, null, null);
+
+                                    if (err != null) {
+                                        IgniteCheckedException e = new IgniteCheckedException(err);
+
+                                        res.error(e);
+
+                                        completionCb.apply(req, res);
+
+                                        return;
+                                    }
+                                }
+
                                 update(node, locked, req, res, updDhtRes);
 
                                 dhtFut = updDhtRes.dhtFuture();
@@ -3636,6 +3658,17 @@
         }
     }
 
+    /**
+     * Returns {@code true} if cache validation needed.
+     *
+     * @return {@code True} if cache should be validated, {@code false} - otherwise.
+     */
+    private boolean needCacheValidation(ClusterNode node) {
+        assert node != null: "The near node must not be null. This is guaranteed by processNearAtomicUpdateRequest()";
+
+        return Boolean.TRUE.equals(node.attribute(ATTR_VALIDATE_CACHE_REQUESTS));
+    }
+
     /** {@inheritDoc} */
     @Override public String toString() {
         return S.toString(GridDhtAtomicCache.class, this, super.toString());
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridNearAtomicAbstractUpdateRequest.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridNearAtomicAbstractUpdateRequest.java
index 64fe1ee..f0d89bf 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridNearAtomicAbstractUpdateRequest.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridNearAtomicAbstractUpdateRequest.java
@@ -396,14 +396,14 @@
     }
 
     /**
-     * @return Keep binary flag.
+     * @return Recovery flag.
      */
     public final boolean recovery() {
         return isFlag(RECOVERY_FLAG_MASK);
     }
 
     /**
-     * @param val Keep binary flag.
+     * @param val Recovery flag.
      */
     public void recovery(boolean val) {
         setFlag(val, RECOVERY_FLAG_MASK);
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 a75fae7..ddbb3b1 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
@@ -906,6 +906,9 @@
             try {
                 GridCacheContext cctx = grp.sharedGroup() ? ctx.cacheContext(entry.cacheId()) : grp.singleCacheContext();
 
+                if (cctx == null)
+                    return true;
+
                 if (cctx.isNear())
                     cctx = cctx.dhtCache().context();
 
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionSupplyMessage.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionSupplyMessage.java
index 3034fb9..7e281e5 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionSupplyMessage.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionSupplyMessage.java
@@ -249,6 +249,9 @@
 
         CacheGroupContext grp = ctx.cache().cacheGroup(grpId);
 
+        if (grp == null)
+            return;
+
         for (CacheEntryInfoCollection col : infos().values()) {
             List<GridCacheEntryInfo> entries = col.infos();
 
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 7e31b90..e429bf2 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
@@ -2101,7 +2101,8 @@
                     grp.topology().onExchangeDone(this, grp.affinity().readyAffinity(res), false);
             }
 
-            cctx.walState().changeLocalStatesOnExchangeDone(res);
+            if (changedAffinity())
+                cctx.walState().changeLocalStatesOnExchangeDone(res, changedBaseline());
         }
 
         final Throwable err0 = err;
@@ -3544,10 +3545,8 @@
      * failed to send update counter deltas to backup.
      */
     private void finalizePartitionCounters() {
-        int parallelismLvl = cctx.kernalContext().config().getSystemThreadPoolSize();
-
         // Reserve at least 2 threads for system operations.
-        parallelismLvl = Math.max(1, parallelismLvl - 2);
+        int parallelismLvl = U.availableThreadCount(cctx.kernalContext(), GridIoPolicy.SYSTEM_POOL, 2);
 
         long time = System.currentTimeMillis();
 
@@ -3976,10 +3975,8 @@
 
         long time = System.currentTimeMillis();
 
-        int parallelismLvl = cctx.kernalContext().config().getSystemThreadPoolSize();
-
         // Reserve at least 2 threads for system operations.
-        parallelismLvl = Math.max(1, parallelismLvl - 2);
+        int parallelismLvl = U.availableThreadCount(cctx.kernalContext(), GridIoPolicy.SYSTEM_POOL, 2);
 
         try {
             doInParallel(
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionsFullMessage.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionsFullMessage.java
index fbaa241..a2cecb8 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionsFullMessage.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionsFullMessage.java
@@ -31,6 +31,7 @@
 import org.apache.ignite.cluster.ClusterNode;
 import org.apache.ignite.internal.GridDirectMap;
 import org.apache.ignite.internal.GridDirectTransient;
+import org.apache.ignite.internal.managers.communication.GridIoPolicy;
 import org.apache.ignite.internal.managers.discovery.GridDiscoveryManager;
 import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion;
 import org.apache.ignite.internal.processors.cache.GridCacheSharedContext;
@@ -415,7 +416,7 @@
 
         if (marshal) {
             // Reserve at least 2 threads for system operations.
-            int parallelismLvl = Math.max(1, ctx.kernalContext().config().getSystemThreadPoolSize() - 2);
+            int parallelismLvl = U.availableThreadCount(ctx.kernalContext(), GridIoPolicy.SYSTEM_POOL, 2);
 
             Collection<Object> objectsToMarshall = new ArrayList<>();
 
@@ -509,7 +510,7 @@
         Collection<byte[]> objectsToUnmarshall = new ArrayList<>();
 
         // Reserve at least 2 threads for system operations.
-        int parallelismLvl = Math.max(1, ctx.kernalContext().config().getSystemThreadPoolSize() - 2);
+        int parallelismLvl = U.availableThreadCount(ctx.kernalContext(), GridIoPolicy.SYSTEM_POOL, 2);
 
         if (partsBytes != null && parts == null)
             objectsToUnmarshall.add(partsBytes);
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 eed0816..e92a240 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
@@ -20,14 +20,16 @@
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
+import java.util.Queue;
 import java.util.UUID;
+import java.util.concurrent.ConcurrentLinkedQueue;
 import java.util.concurrent.locks.ReadWriteLock;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
-import java.util.stream.Collectors;
 import org.apache.ignite.IgniteCheckedException;
 import org.apache.ignite.cluster.ClusterNode;
 import org.apache.ignite.internal.IgniteInternalFuture;
 import org.apache.ignite.internal.NodeStoppingException;
+import org.apache.ignite.internal.managers.communication.GridIoPolicy;
 import org.apache.ignite.internal.processors.affinity.AffinityAssignment;
 import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion;
 import org.apache.ignite.internal.processors.cache.CacheGroupContext;
@@ -43,7 +45,9 @@
 import org.apache.ignite.internal.util.future.GridFinishedFuture;
 import org.apache.ignite.internal.util.future.GridFutureAdapter;
 import org.apache.ignite.internal.util.lang.GridPlainRunnable;
+import org.apache.ignite.internal.util.lang.GridTuple3;
 import org.apache.ignite.internal.util.typedef.CI1;
+import org.apache.ignite.internal.util.typedef.F;
 import org.apache.ignite.lang.IgnitePredicate;
 import org.jetbrains.annotations.Nullable;
 
@@ -81,6 +85,12 @@
     private final ReadWriteLock demandLock = new ReentrantReadWriteLock();
 
     /** */
+    private boolean paused;
+
+    /** */
+    private Queue<GridTuple3<Integer, UUID, GridDhtPartitionSupplyMessage>> pausedDemanderQueue = new ConcurrentLinkedQueue<>();
+
+    /** */
     private boolean stopped;
 
     /**
@@ -186,38 +196,10 @@
         if (rebFut.isDone() && !rebFut.result())
             return true; // Required, previous rebalance cancelled.
 
-        final AffinityTopologyVersion exchTopVer = exchFut.context().events().topologyVersion();
+        AffinityTopologyVersion lastAffChangeTopVer =
+            ctx.exchange().lastAffinityChangedTopologyVersion(exchFut.topologyVersion());
 
-        Collection<UUID> aliveNodes = ctx.discovery().aliveServerNodes().stream()
-            .map(ClusterNode::id)
-            .collect(Collectors.toList());
-
-        return assignmentsChanged(rebTopVer, exchTopVer) ||
-            !aliveNodes.containsAll(demander.remainingNodes()); // Some of nodes left before rabalance compelete.
-    }
-
-    /**
-     * @param oldTopVer Previous topology version.
-     * @param newTopVer New topology version to check result.
-     * @return {@code True} if affinity assignments changed between two versions for local node.
-     */
-    private boolean assignmentsChanged(AffinityTopologyVersion oldTopVer, AffinityTopologyVersion newTopVer) {
-        final AffinityAssignment aff = grp.affinity().readyAffinity(newTopVer);
-
-        // We should get affinity assignments based on previous rebalance to calculate difference.
-        // Whole history size described by IGNITE_AFFINITY_HISTORY_SIZE constant.
-        final AffinityAssignment prevAff = grp.affinity().cachedVersions().contains(oldTopVer) ?
-            grp.affinity().cachedAffinity(oldTopVer) : null;
-
-        if (prevAff == null)
-            return false;
-
-        boolean assignsChanged = false;
-
-        for (int p = 0; !assignsChanged && p < grp.affinity().partitions(); p++)
-            assignsChanged |= aff.get(p).contains(ctx.localNode()) != prevAff.get(p).contains(ctx.localNode());
-
-        return assignsChanged;
+        return lastAffChangeTopVer.compareTo(rebTopVer) > 0;
     }
 
     /** {@inheritDoc} */
@@ -386,7 +368,10 @@
             demandLock.readLock().lock();
 
             try {
-                demander.handleSupplyMessage(idx, id, s);
+                if (paused)
+                    pausedDemanderQueue.add(F.t(idx, id, s));
+                else
+                    demander.handleSupplyMessage(idx, id, s);
             }
             finally {
                 demandLock.readLock().unlock();
@@ -591,6 +576,41 @@
     }
 
     /** {@inheritDoc} */
+    @Override public void pause() {
+        demandLock.writeLock().lock();
+
+        try {
+            paused = true;
+        }
+        finally {
+           demandLock.writeLock().unlock();
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override public void resume() {
+        demandLock.writeLock().lock();
+
+        try {
+            final List<GridTuple3<Integer, UUID, GridDhtPartitionSupplyMessage>> msgToProc =
+                    new ArrayList<>(pausedDemanderQueue);
+
+            pausedDemanderQueue.clear();
+
+            final GridDhtPreloader preloader = this;
+
+            ctx.kernalContext().closure().runLocalSafe(() -> msgToProc.forEach(
+                    m -> preloader.handleSupplyMessage(m.get1(), m.get2(), m.get3())
+            ), GridIoPolicy.SYSTEM_POOL);
+
+            paused = false;
+        }
+        finally {
+            demandLock.writeLock().unlock();
+        }
+    }
+
+    /** {@inheritDoc} */
     @Override public void dumpDebugInfo() {
         // No-op
     }
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/topology/GridClientPartitionTopology.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/topology/GridClientPartitionTopology.java
index 02faa51..710dc42 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/topology/GridClientPartitionTopology.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/topology/GridClientPartitionTopology.java
@@ -1173,7 +1173,7 @@
     }
 
     /** {@inheritDoc} */
-    @Override public void ownMoving(AffinityTopologyVersion topVer) {
+    @Override public void ownMoving(AffinityTopologyVersion rebFinishedTopVer) {
         // No-op
     }
 
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/topology/GridDhtPartitionTopology.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/topology/GridDhtPartitionTopology.java
index 81eab84..4b1e5a6 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/topology/GridDhtPartitionTopology.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/topology/GridDhtPartitionTopology.java
@@ -373,9 +373,9 @@
     /**
      * Owns all moving partitions for the given topology version.
      *
-     * @param topVer Topology version.
+     * @param rebFinishedTopVer Topology version when rebalancing finished.
      */
-    public void ownMoving(AffinityTopologyVersion topVer);
+    public void ownMoving(AffinityTopologyVersion rebFinishedTopVer);
 
     /**
      * @param part Evicted partition.
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/topology/GridDhtPartitionTopologyImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/topology/GridDhtPartitionTopologyImpl.java
index cc8a198..e55ab2b 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/topology/GridDhtPartitionTopologyImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/topology/GridDhtPartitionTopologyImpl.java
@@ -2583,19 +2583,26 @@
     }
 
     /** {@inheritDoc} */
-    @Override public void ownMoving(AffinityTopologyVersion topVer) {
+    @Override public void ownMoving(AffinityTopologyVersion rebFinishedTopVer) {
         lock.writeLock().lock();
 
+        AffinityTopologyVersion lastAffChangeVer = ctx.exchange().lastAffinityChangedTopologyVersion(lastTopChangeVer);
+
+        if (lastAffChangeVer.compareTo(rebFinishedTopVer) > 0)
+            log.info("Affinity topology changed, no MOVING partitions will be owned " +
+                "[rebFinishedTopVer=" + rebFinishedTopVer +
+                ", lastAffChangeVer=" + lastAffChangeVer + "]");
+
         try {
             for (GridDhtLocalPartition locPart : grp.topology().currentLocalPartitions()) {
                 if (locPart.state() == MOVING) {
                     boolean reserved = locPart.reserve();
 
                     try {
-                        if (reserved && locPart.state() == MOVING && lastTopChangeVer.equals(topVer))
-                            grp.topology().own(locPart);
-                        else // topology changed, rebalancing must be restarted
-                            return;
+                        if (reserved && locPart.state() == MOVING &&
+                            lastAffChangeVer.compareTo(rebFinishedTopVer) <= 0 &&
+                            rebFinishedTopVer.compareTo(lastTopChangeVer) <= 0)
+                                grp.topology().own(locPart);
                     }
                     finally {
                         if (reserved)
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearGetFuture.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearGetFuture.java
index 54c3cae..09445f7 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearGetFuture.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearGetFuture.java
@@ -23,10 +23,9 @@
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.UUID;
-import java.util.concurrent.atomic.AtomicReference;
 import org.apache.ignite.IgniteCheckedException;
-import org.apache.ignite.IgniteLogger;
 import org.apache.ignite.cluster.ClusterNode;
 import org.apache.ignite.internal.IgniteInternalFuture;
 import org.apache.ignite.internal.cluster.ClusterTopologyCheckedException;
@@ -38,8 +37,6 @@
 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.GridCacheMessage;
-import org.apache.ignite.internal.processors.cache.GridCacheUtils.BackupPostProcessingClosure;
 import org.apache.ignite.internal.processors.cache.IgniteCacheExpiryPolicy;
 import org.apache.ignite.internal.processors.cache.KeyCacheObject;
 import org.apache.ignite.internal.processors.cache.distributed.dht.CacheDistributedGetFutureAdapter;
@@ -50,12 +47,7 @@
 import org.apache.ignite.internal.processors.cache.version.GridCacheVersion;
 import org.apache.ignite.internal.util.GridLeanMap;
 import org.apache.ignite.internal.util.future.GridFinishedFuture;
-import org.apache.ignite.internal.util.future.GridFutureAdapter;
-import org.apache.ignite.internal.util.tostring.GridToStringInclude;
-import org.apache.ignite.internal.util.typedef.C1;
-import org.apache.ignite.internal.util.typedef.CIX1;
 import org.apache.ignite.internal.util.typedef.F;
-import org.apache.ignite.internal.util.typedef.P1;
 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;
@@ -66,17 +58,8 @@
  *
  */
 public final class GridNearGetFuture<K, V> extends CacheDistributedGetFutureAdapter<K, V> {
-    /** */
-    private static final long serialVersionUID = 0L;
-
-    /** Logger reference. */
-    private static final AtomicReference<IgniteLogger> logRef = new AtomicReference<>();
-
-    /** Logger. */
-    private static IgniteLogger log;
-
     /** Transaction. */
-    private IgniteTxLocalEx tx;
+    private final IgniteTxLocalEx tx;
 
     /** */
     private GridCacheVersion ver;
@@ -111,7 +94,8 @@
         boolean keepCacheObjects,
         boolean recovery
     ) {
-        super(cctx,
+        super(
+            cctx,
             keys,
             readThrough,
             forcePrimary,
@@ -122,18 +106,16 @@
             skipVals,
             needVer,
             keepCacheObjects,
-            recovery);
+            recovery
+        );
 
         assert !F.isEmpty(keys);
 
         this.tx = tx;
 
-        futId = IgniteUuid.randomUuid();
-
         ver = tx == null ? cctx.versions().next() : tx.xidVersion();
 
-        if (log == null)
-            log = U.logger(cctx.kernalContext(), logRef, GridNearGetFuture.class);
+        initLogger(GridNearGetFuture.class);
     }
 
     /**
@@ -147,74 +129,22 @@
         if (lockedTopVer != null) {
             canRemap = false;
 
-            map(keys, Collections.<ClusterNode, LinkedHashMap<KeyCacheObject, Boolean>>emptyMap(), lockedTopVer);
+            map(keys, Collections.emptyMap(), lockedTopVer);
         }
         else {
             AffinityTopologyVersion mapTopVer = topVer;
 
             if (mapTopVer == null) {
-                mapTopVer = tx == null ?
-                    (canRemap ? cctx.affinity().affinityTopologyVersion() : cctx.shared().exchange().readyAffinityVersion()) :
-                    tx.topologyVersion();
+                mapTopVer = tx == null ? cctx.affinity().affinityTopologyVersion() : tx.topologyVersion();
             }
 
-            map(keys, Collections.<ClusterNode, LinkedHashMap<KeyCacheObject, Boolean>>emptyMap(), mapTopVer);
+            map(keys, Collections.emptyMap(), mapTopVer);
         }
 
         markInitialized();
     }
 
     /** {@inheritDoc} */
-    @Override public boolean trackable() {
-        return trackable;
-    }
-
-    /** {@inheritDoc} */
-    @Override public void markNotTrackable() {
-        // Should not flip trackable flag from true to false since get future can be remapped.
-    }
-
-    /** {@inheritDoc} */
-    @Override public IgniteUuid futureId() {
-        return futId;
-    }
-
-    /** {@inheritDoc} */
-    @Override public boolean onNodeLeft(UUID nodeId) {
-        boolean found = false;
-
-        for (IgniteInternalFuture<Map<K, V>> fut : futures())
-            if (isMini(fut)) {
-                MiniFuture f = (MiniFuture)fut;
-
-                if (f.node().id().equals(nodeId)) {
-                    found = true;
-
-                    f.onNodeLeft();
-                }
-            }
-
-        return found;
-    }
-
-    /**
-     * @param nodeId Sender.
-     * @param res Result.
-     */
-    @Override public void onResult(UUID nodeId, GridNearGetResponse res) {
-        for (IgniteInternalFuture<Map<K, V>> fut : futures())
-            if (isMini(fut)) {
-                MiniFuture f = (MiniFuture)fut;
-
-                if (f.futureId().equals(res.miniId())) {
-                    assert f.node().id().equals(nodeId);
-
-                    f.onResult(res);
-                }
-            }
-    }
-
-    /** {@inheritDoc} */
     @Override public boolean onDone(Map<K, V> res, Throwable err) {
         if (super.onDone(res, err)) {
             // Don't forget to clean up.
@@ -229,11 +159,8 @@
         return false;
     }
 
-    /**
-     * @param f Future.
-     * @return {@code True} if mini-future.
-     */
-    private boolean isMini(IgniteInternalFuture<?> f) {
+    /** {@inheritDoc} */
+    @Override protected boolean isMini(IgniteInternalFuture<?> f) {
         return f.getClass().equals(MiniFuture.class);
     }
 
@@ -242,10 +169,10 @@
      * @param mapped Mappings to check for duplicates.
      * @param topVer Topology version to map on.
      */
-    private void map(
+    @Override protected void map(
         Collection<KeyCacheObject> keys,
         Map<ClusterNode, LinkedHashMap<KeyCacheObject, Boolean>> mapped,
-        final AffinityTopologyVersion topVer
+        AffinityTopologyVersion topVer
     ) {
         Collection<ClusterNode> affNodes = CU.affinityNodes(cctx, topVer);
 
@@ -268,7 +195,7 @@
             try {
                 // Assign keys to primary nodes.
                 for (KeyCacheObject key : keys)
-                    savedEntries = map(key, mappings, topVer, mapped, savedEntries);
+                    savedEntries = map(key, topVer, mappings, mapped, savedEntries);
 
                 success = true;
             }
@@ -292,23 +219,24 @@
         if (isDone())
             return;
 
-        final Map<KeyCacheObject, GridNearCacheEntry> saved = savedEntries != null ? savedEntries :
-            Collections.<KeyCacheObject, GridNearCacheEntry>emptyMap();
+        Map<KeyCacheObject, GridNearCacheEntry> saved =
+            savedEntries != null ? savedEntries : Collections.emptyMap();
 
-        final int keysSize = keys.size();
+        int keysSize = keys.size();
 
         // Create mini futures.
         for (Map.Entry<ClusterNode, LinkedHashMap<KeyCacheObject, Boolean>> entry : mappings.entrySet()) {
-            final ClusterNode n = entry.getKey();
+            ClusterNode n = entry.getKey();
 
-            final LinkedHashMap<KeyCacheObject, Boolean> mappedKeys = entry.getValue();
+            LinkedHashMap<KeyCacheObject, Boolean> mappedKeys = entry.getValue();
 
             assert !mappedKeys.isEmpty();
 
             // If this is the primary or backup node for the keys.
             if (n.isLocal()) {
-                final GridDhtFuture<Collection<GridCacheEntryInfo>> fut =
-                    dht().getDhtAsync(n.id(),
+                GridDhtFuture<Collection<GridCacheEntryInfo>> fut = dht()
+                    .getDhtAsync(
+                        n.id(),
                         -1,
                         mappedKeys,
                         false,
@@ -320,74 +248,52 @@
                         skipVals,
                         recovery,
                         null,
-                        null); // TODO IGNITE-7371
+                        null
+                    ); // TODO IGNITE-7371
 
-                final Collection<Integer> invalidParts = fut.invalidPartitions();
+                Collection<Integer> invalidParts = fut.invalidPartitions();
 
                 if (!F.isEmpty(invalidParts)) {
                     Collection<KeyCacheObject> remapKeys = new ArrayList<>(keysSize);
 
                     for (KeyCacheObject key : keys) {
-                        if (key != null && invalidParts.contains(cctx.affinity().partition(key)))
+                        int part = cctx.affinity().partition(key);
+
+                        if (key != null && invalidParts.contains(part)) {
+                            addNodeAsInvalid(n, part, topVer);
+
                             remapKeys.add(key);
+                        }
                     }
 
                     AffinityTopologyVersion updTopVer = cctx.shared().exchange().readyAffinityVersion();
 
-                    assert updTopVer.compareTo(topVer) > 0 : "Got invalid partitions for local node but topology version did " +
-                        "not change [topVer=" + topVer + ", updTopVer=" + updTopVer +
-                        ", invalidParts=" + invalidParts + ']';
-
                     // Remap recursively.
                     map(remapKeys, mappings, updTopVer);
                 }
 
                 // Add new future.
-                add(fut.chain(new C1<IgniteInternalFuture<Collection<GridCacheEntryInfo>>, Map<K, V>>() {
-                    @Override public Map<K, V> apply(IgniteInternalFuture<Collection<GridCacheEntryInfo>> fut) {
-                        try {
-                            return loadEntries(n.id(), mappedKeys.keySet(), fut.get(), saved, topVer);
-                        }
-                        catch (Exception e) {
-                            U.error(log, "Failed to get values from dht cache [fut=" + fut + "]", e);
+                add(fut.chain(f -> {
+                    try {
+                        return loadEntries(n.id(), mappedKeys.keySet(), f.get(), saved, topVer);
+                    }
+                    catch (Exception e) {
+                        U.error(log, "Failed to get values from dht cache [fut=" + fut + "]", e);
 
-                            onDone(e);
+                        onDone(e);
 
-                            return Collections.emptyMap();
-                        }
+                        return Collections.emptyMap();
                     }
                 }));
             }
             else {
-                if (!trackable) {
-                    trackable = true;
+                registrateFutureInMvccManager(this);
 
-                    cctx.mvcc().addFuture(this, futId);
-                }
+                MiniFuture miniFuture = new MiniFuture(n, mappedKeys, saved, topVer);
 
-                MiniFuture fut = new MiniFuture(n, mappedKeys, saved, topVer,
-                    CU.createBackupPostProcessingClosure(topVer, log, cctx, null, expiryPlc, readThrough, skipVals));
+                GridNearGetRequest req = miniFuture.createGetRequest(futId);
 
-                GridCacheMessage req = new GridNearGetRequest(
-                    cctx.cacheId(),
-                    futId,
-                    fut.futureId(),
-                    ver,
-                    mappedKeys,
-                    readThrough,
-                    topVer,
-                    subjId,
-                    taskName == null ? 0 : taskName.hashCode(),
-                    expiryPlc != null ? expiryPlc.forCreate() : -1L,
-                    expiryPlc != null ? expiryPlc.forAccess() : -1L,
-                    true,
-                    skipVals,
-                    cctx.deploymentEnabled(),
-                    recovery,
-                    null,
-                    null); // TODO IGNITE-7371
-
-                add(fut); // Append new future.
+                add(miniFuture); // Append new future.
 
                 try {
                     cctx.io().send(n, req, cctx.ioPolicy());
@@ -395,16 +301,14 @@
                 catch (IgniteCheckedException e) {
                     // Fail the whole thing.
                     if (e instanceof ClusterTopologyCheckedException)
-                        fut.onNodeLeft();
+                        miniFuture.onNodeLeft((ClusterTopologyCheckedException)e);
                     else
-                        fut.onResult(e);
+                        miniFuture.onResult(e);
                 }
             }
         }
     }
 
-
-
     /**
      * @param mappings Mappings.
      * @param key Key to map.
@@ -415,8 +319,8 @@
      */
     private Map<KeyCacheObject, GridNearCacheEntry> map(
         KeyCacheObject key,
-        Map<ClusterNode, LinkedHashMap<KeyCacheObject, Boolean>> mappings,
         AffinityTopologyVersion topVer,
+        Map<ClusterNode, LinkedHashMap<KeyCacheObject, Boolean>> mappings,
         Map<ClusterNode, LinkedHashMap<KeyCacheObject, Boolean>> mapped,
         Map<KeyCacheObject, GridNearCacheEntry> saved
     ) {
@@ -494,7 +398,9 @@
                         }
                     }
 
-                    ClusterNode affNode = cctx.selectAffinityNodeBalanced(affNodes, part, canRemap);
+                    Set<ClusterNode> invalidNodesSet = getInvalidNodes(part, topVer);
+
+                    ClusterNode affNode = cctx.selectAffinityNodeBalanced(affNodes, invalidNodesSet, part, canRemap);
 
                     if (affNode == null) {
                         onDone(serverNotFoundError(part, topVer));
@@ -505,17 +411,8 @@
                     if (cctx.statisticsEnabled() && !skipVals && !affNode.isLocal() && !isNear)
                         cache().metrics0().onRead(false);
 
-                    LinkedHashMap<KeyCacheObject, Boolean> keys = mapped.get(affNode);
-
-                    if (keys != null && keys.containsKey(key)) {
-                        if (REMAP_CNT_UPD.incrementAndGet(this) > MAX_REMAP_CNT) {
-                            onDone(new ClusterTopologyCheckedException("Failed to remap key to a new node after " +
-                                MAX_REMAP_CNT + " attempts (key got remapped to the same node) " +
-                                "[key=" + key + ", node=" + U.toShortString(affNode) + ", mappings=" + mapped + ']'));
-
-                            return saved;
-                        }
-                    }
+                    if (!checkRetryPermits(key,affNode,mapped))
+                        return saved;
 
                     if (!affNodes.contains(cctx.localNode())) {
                         GridNearCacheEntry nearEntry = entry != null ? entry : near.entryExx(key, topVer);
@@ -572,10 +469,12 @@
      * @param nearRead {@code True} if already tried to read from near cache.
      * @return {@code True} if there is no need to further search value.
      */
-    private boolean localDhtGet(KeyCacheObject key,
+    private boolean localDhtGet(
+        KeyCacheObject key,
         int part,
         AffinityTopologyVersion topVer,
-        boolean nearRead) {
+        boolean nearRead
+    ) {
         GridDhtCacheAdapter<K, V> dht = cache().dht();
 
         assert dht.context().affinityNode() : this;
@@ -795,9 +694,11 @@
      * @param saved Saved entries.
      * @param topVer Topology version.
      */
-    private void releaseEvictions(Collection<KeyCacheObject> keys,
+    private void releaseEvictions(
+        Collection<KeyCacheObject> keys,
         Map<KeyCacheObject, GridNearCacheEntry> saved,
-        AffinityTopologyVersion topVer) {
+        AffinityTopologyVersion topVer
+    ) {
         for (KeyCacheObject key : keys) {
             GridNearCacheEntry entry = saved.get(key);
 
@@ -812,101 +713,59 @@
 
     /** {@inheritDoc} */
     @Override public String toString() {
-        Collection<String> futs = F.viewReadOnly(futures(), new C1<IgniteInternalFuture<?>, String>() {
-            @SuppressWarnings("unchecked")
-            @Override public String apply(IgniteInternalFuture<?> f) {
-                if (isMini(f)) {
-                    return "[node=" + ((MiniFuture)f).node().id() +
-                        ", loc=" + ((MiniFuture)f).node().isLocal() +
-                        ", done=" + f.isDone() + "]";
-                }
-                else
-                    return "[loc=true, done=" + f.isDone() + "]";
-            }
-        });
-
         return S.toString(GridNearGetFuture.class, this,
-            "innerFuts", futs,
             "super", super.toString());
     }
 
     /**
-     * Mini-future for get operations. Mini-futures are only waiting on a single
-     * node as opposed to multiple nodes.
+     * Mini-future for get operations. Mini-futures are only waiting on a single node as opposed to multiple nodes.
      */
-    private class MiniFuture extends GridFutureAdapter<Map<K, V>> {
-        /** */
-        private final IgniteUuid futId = IgniteUuid.randomUuid();
-
-        /** Node ID. */
-        private ClusterNode node;
-
-        /** Keys. */
-        @GridToStringInclude
-        private LinkedHashMap<KeyCacheObject, Boolean> keys;
-
+    private class MiniFuture extends AbstractMiniFuture {
         /** Saved entry versions. */
-        private Map<KeyCacheObject, GridNearCacheEntry> savedEntries;
-
-        /** Topology version on which this future was mapped. */
-        private AffinityTopologyVersion topVer;
-
-        /** Post processing closure. */
-        private final BackupPostProcessingClosure postProcessingClos;
-
-        /** {@code True} if remapped after node left. */
-        private boolean remapped;
+        private final Map<KeyCacheObject, GridNearCacheEntry> savedEntries;
 
         /**
          * @param node Node.
          * @param keys Keys.
          * @param savedEntries Saved entries.
          * @param topVer Topology version.
-         * @param postProcessingClos Post processing closure.
          */
         MiniFuture(
             ClusterNode node,
             LinkedHashMap<KeyCacheObject, Boolean> keys,
             Map<KeyCacheObject, GridNearCacheEntry> savedEntries,
-            AffinityTopologyVersion topVer,
-            BackupPostProcessingClosure postProcessingClos) {
-            this.node = node;
-            this.keys = keys;
+            AffinityTopologyVersion topVer
+        ) {
+            super(node, keys, topVer);
             this.savedEntries = savedEntries;
-            this.topVer = topVer;
-            this.postProcessingClos = postProcessingClos;
         }
 
-        /**
-         * @return Future ID.
-         */
-        IgniteUuid futureId() {
-            return futId;
+        /** {@inheritDoc} */
+        @Override protected GridNearGetRequest createGetRequest0(IgniteUuid rootFutId, IgniteUuid futId) {
+            return new GridNearGetRequest(
+                cctx.cacheId(),
+                rootFutId,
+                futId,
+                ver,
+                keys,
+                readThrough,
+                topVer,
+                subjId,
+                taskName == null ? 0 : taskName.hashCode(),
+                expiryPlc != null ? expiryPlc.forCreate() : -1L,
+                expiryPlc != null ? expiryPlc.forAccess() : -1L,
+                true,
+                skipVals,
+                cctx.deploymentEnabled(),
+                recovery,
+                null,
+                null
+            ); // TODO IGNITE-7371
         }
 
-        /**
-         * @return Node ID.
-         */
-        public ClusterNode node() {
-            return node;
-        }
-
-        /**
-         * @return Keys.
-         */
-        public Collection<KeyCacheObject> keys() {
-            return keys.keySet();
-        }
-
-        /**
-         * @param e Error.
-         */
-        void onResult(Throwable e) {
-            if (log.isDebugEnabled())
-                log.debug("Failed to get future result [fut=" + this + ", err=" + e + ']');
-
-            // Fail.
-            onDone(e);
+        /** {@inheritDoc} */
+        @Override protected Map<K, V> createResultMap(Collection<GridCacheEntryInfo> entries) {
+            return loadEntries(node.id(), keys.keySet(), entries, savedEntries, topVer);
         }
 
         /** {@inheritDoc} */
@@ -920,136 +779,6 @@
                 return false;
         }
 
-        /**
-         */
-        synchronized void onNodeLeft() {
-            if (remapped)
-                return;
-
-            remapped = true;
-
-            if (log.isDebugEnabled())
-                log.debug("Remote node left grid while sending or waiting for reply (will retry): " + this);
-
-            // Try getting value from alive nodes.
-            if (!canRemap) {
-                // Remap
-                map(keys.keySet(), F.t(node, keys), topVer);
-
-                onDone(Collections.<K, V>emptyMap());
-            }
-            else {
-                AffinityTopologyVersion updTopVer =
-                    new AffinityTopologyVersion(Math.max(topVer.topologyVersion() + 1, cctx.discovery().topologyVersion()));
-
-                cctx.shared().exchange().affinityReadyFuture(updTopVer).listen(f -> {
-                    try {
-                        // Remap.
-                        map(keys.keySet(), F.t(node, keys), f.get());
-
-                        onDone(Collections.<K, V>emptyMap());
-
-                    }
-                    catch (IgniteCheckedException e) {
-                        GridNearGetFuture.this.onDone(e);
-                    }
-                });
-            }
-        }
-
-        /**
-         * @param res Result callback.
-         */
-        void onResult(final GridNearGetResponse res) {
-            final Collection<Integer> invalidParts = res.invalidPartitions();
-
-            // If error happened on remote node, fail the whole future.
-            if (res.error() != null) {
-                onDone(res.error());
-
-                return;
-            }
-
-            // Remap invalid partitions.
-            if (!F.isEmpty(invalidParts)) {
-                AffinityTopologyVersion rmtTopVer = res.topologyVersion();
-
-                assert rmtTopVer.topologyVersion() != 0;
-
-                if (rmtTopVer.compareTo(topVer) <= 0) {
-                    // Fail the whole get future.
-                    onDone(new IgniteCheckedException("Failed to process invalid partitions response (remote node reported " +
-                        "invalid partitions but remote topology version does not differ from local) " +
-                        "[topVer=" + topVer + ", rmtTopVer=" + rmtTopVer + ", invalidParts=" + invalidParts +
-                        ", nodeId=" + node.id() + ']'));
-
-                    return;
-                }
-
-                if (log.isDebugEnabled())
-                    log.debug("Remapping mini get future [invalidParts=" + invalidParts + ", fut=" + this + ']');
-
-                if (!canRemap) {
-                    map(F.view(keys.keySet(), new P1<KeyCacheObject>() {
-                        @Override public boolean apply(KeyCacheObject key) {
-                            return invalidParts.contains(cctx.affinity().partition(key));
-                        }
-                    }), F.t(node, keys), topVer);
-
-                    postProcessResultAndDone(res);
-
-                    return;
-                }
-
-                // Need to wait for next topology version to remap.
-                IgniteInternalFuture<AffinityTopologyVersion> topFut =  cctx.shared().exchange().affinityReadyFuture(rmtTopVer);
-
-                topFut.listen(new CIX1<IgniteInternalFuture<AffinityTopologyVersion>>() {
-                    @Override public void applyx(
-                        IgniteInternalFuture<AffinityTopologyVersion> fut) throws IgniteCheckedException {
-                        AffinityTopologyVersion readyTopVer = fut.get();
-
-                        // This will append new futures to compound list.
-                        map(F.view(keys.keySet(), new P1<KeyCacheObject>() {
-                            @Override public boolean apply(KeyCacheObject key) {
-                                return invalidParts.contains(cctx.affinity().partition(key));
-                            }
-                        }), F.t(node, keys), readyTopVer);
-
-                        postProcessResultAndDone(res);
-                    }
-                });
-            }
-            else
-                postProcessResultAndDone(res);
-
-        }
-
-        /**
-         * Post processes result and done future.
-         *
-         * @param res Response.
-         */
-        private void postProcessResultAndDone(final GridNearGetResponse res){
-            try {
-                postProcessResult(res);
-
-                // It is critical to call onDone after adding futures to compound list.
-                onDone(loadEntries(node.id(), keys.keySet(), res.entries(), savedEntries, topVer));
-            }
-            catch (Exception ex) {
-                onDone(ex);
-            }
-        }
-
-        /**
-         * @param res Response.
-         */
-        private void postProcessResult(final GridNearGetResponse res) {
-            if (postProcessingClos != null)
-                postProcessingClos.apply(res.entries());
-        }
-
         /** {@inheritDoc} */
         @Override public String toString() {
             return S.toString(MiniFuture.class, this);
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearOptimisticSerializableTxPrepareFuture.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearOptimisticSerializableTxPrepareFuture.java
index ef88a6b..46bab86 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearOptimisticSerializableTxPrepareFuture.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearOptimisticSerializableTxPrepareFuture.java
@@ -269,7 +269,8 @@
     private boolean onComplete() {
         Throwable err0 = err;
 
-        if (err0 == null || tx.needCheckBackup())
+        if ((!tx.onePhaseCommit() || tx.mappings().get(cctx.localNodeId()) == null) &&
+            (err0 == null || tx.needCheckBackup()))
             tx.state(PREPARED);
 
         if (super.onDone(tx, err0)) {
@@ -350,9 +351,13 @@
                 hasNearCache = true;
         }
 
-        for (IgniteTxEntry read : reads)
+        for (IgniteTxEntry read : reads) {
             map(read, topVer, mappings, txMapping, remap, topLocked);
 
+            if (read.context().isNear())
+                hasNearCache = true;
+        }
+
         if (keyLockFut != null)
             keyLockFut.onAllKeysAdded();
 
@@ -553,7 +558,8 @@
             tx.taskNameHash(),
             m.clientFirst(),
             txNodes.size() == 1,
-            tx.activeCachesDeploymentEnabled());
+            tx.activeCachesDeploymentEnabled(),
+            tx.txState().recovery());
 
         for (IgniteTxEntry txEntry : writes) {
             if (txEntry.op() == TRANSFORM)
@@ -574,7 +580,7 @@
         final MiniFuture fut,
         final boolean nearEntries) {
         IgniteInternalFuture<GridNearTxPrepareResponse> prepFut = nearEntries ?
-            cctx.tm().txHandler().prepareNearTxLocal(req) :
+            cctx.tm().txHandler().prepareNearTxLocal(tx, req) :
             cctx.tm().txHandler().prepareColocatedTx(tx, req);
 
         prepFut.listen(new CI1<IgniteInternalFuture<GridNearTxPrepareResponse>>() {
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearOptimisticTxPrepareFuture.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearOptimisticTxPrepareFuture.java
index d47420f..140f593 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearOptimisticTxPrepareFuture.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearOptimisticTxPrepareFuture.java
@@ -297,7 +297,8 @@
     private boolean onComplete() {
         Throwable err0 = err;
 
-        if (err0 == null || tx.needCheckBackup())
+        if ((!tx.onePhaseCommit() || tx.mappings().get(cctx.localNodeId()) == null) &&
+                (err0 == null || tx.needCheckBackup()))
             tx.state(PREPARED);
 
         if (super.onDone(tx, err0)) {
@@ -537,7 +538,8 @@
                     tx.taskNameHash(),
                     m.clientFirst(),
                     true,
-                    tx.activeCachesDeploymentEnabled());
+                    tx.activeCachesDeploymentEnabled(),
+                    tx.txState().recovery());
 
                 for (IgniteTxEntry txEntry : m.entries()) {
                     if (txEntry.op() == TRANSFORM)
@@ -566,7 +568,7 @@
                     assert !(m.hasColocatedCacheEntries() && m.hasNearCacheEntries()) : m;
 
                     IgniteInternalFuture<GridNearTxPrepareResponse> prepFut =
-                        m.hasNearCacheEntries() ? cctx.tm().txHandler().prepareNearTxLocal(req)
+                        m.hasNearCacheEntries() ? cctx.tm().txHandler().prepareNearTxLocal(tx, req)
                         : cctx.tm().txHandler().prepareColocatedTx(tx, req);
 
                     prepFut.listen(new CI1<IgniteInternalFuture<GridNearTxPrepareResponse>>() {
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearPessimisticTxPrepareFuture.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearPessimisticTxPrepareFuture.java
index 5b6d440..d2e1586 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearPessimisticTxPrepareFuture.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearPessimisticTxPrepareFuture.java
@@ -223,7 +223,8 @@
             tx.taskNameHash(),
             false,
             true,
-            tx.activeCachesDeploymentEnabled());
+            tx.activeCachesDeploymentEnabled(),
+            tx.txState().recovery());
 
         req.queryUpdate(m.queryUpdate());
 
@@ -253,7 +254,7 @@
         add((IgniteInternalFuture)fut);
 
         IgniteInternalFuture<GridNearTxPrepareResponse> prepFut = nearEntries ?
-            cctx.tm().txHandler().prepareNearTxLocal(req) :
+            cctx.tm().txHandler().prepareNearTxLocal(tx, req) :
             cctx.tm().txHandler().prepareColocatedTx(tx, req);
 
         prepFut.listen(new CI1<IgniteInternalFuture<GridNearTxPrepareResponse>>() {
@@ -437,7 +438,8 @@
 
         err = this.err;
 
-        if (err == null || tx.needCheckBackup())
+        if ((!tx.onePhaseCommit() || tx.mappings().get(cctx.localNodeId()) == null) &&
+            (err == null || tx.needCheckBackup()))
             tx.state(PREPARED);
 
         if (super.onDone(tx, err)) {
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearTxLocal.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearTxLocal.java
index 9f1f86d..ef74de4 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearTxLocal.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearTxLocal.java
@@ -3917,16 +3917,23 @@
                 fut.listen(new IgniteInClosure<IgniteInternalFuture<IgniteInternalTx>>() {
                     @Override public void apply(IgniteInternalFuture<IgniteInternalTx> fut0) {
                         if (FINISH_FUT_UPD.compareAndSet(tx, fut, rollbackFut)) {
-                            if (tx.state() == COMMITTED) {
-                                if (log.isDebugEnabled())
-                                    log.debug("Failed to rollback, transaction is already committed: " + tx);
+                            switch (tx.state()) {
+                                case COMMITTED:
+                                    if (log.isDebugEnabled())
+                                        log.debug("Failed to rollback, transaction is already committed: " + tx);
 
-                                rollbackFut.forceFinish();
+                                    // Fall-through.
 
-                                assert rollbackFut.isDone() : rollbackFut;
+                                case ROLLED_BACK:
+                                    rollbackFut.forceFinish();
+
+                                    assert rollbackFut.isDone() : rollbackFut;
+
+                                    break;
+
+                                default: // First finish attempt was unsuccessful. Try again.
+                                    rollbackFut.finish(false, clearThreadMap, onTimeout);
                             }
-                            else // First finish attempt was unsuccessful. Try again.
-                                rollbackFut.finish(false, clearThreadMap, onTimeout);
                         }
                         else {
                             finishFut.listen(new IgniteInClosure<IgniteInternalFuture<IgniteInternalTx>>() {
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearTxPrepareRequest.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearTxPrepareRequest.java
index 87546aa..941c7b3 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearTxPrepareRequest.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearTxPrepareRequest.java
@@ -59,6 +59,9 @@
     /** */
     private static final int ALLOW_WAIT_TOP_FUT_FLAG_MASK = 0x10;
 
+    /** Recovery value flag. */
+    private static final int RECOVERY_FLAG_MASK = 0x40;
+
     /** Future ID. */
     private IgniteUuid futId;
 
@@ -127,7 +130,8 @@
         int taskNameHash,
         boolean firstClientReq,
         boolean allowWaitTopFut,
-        boolean addDepInfo
+        boolean addDepInfo,
+        boolean recovery
     ) {
         super(tx,
             timeout,
@@ -154,6 +158,7 @@
         setFlag(explicitLock, EXPLICIT_LOCK_FLAG_MASK);
         setFlag(firstClientReq, FIRST_CLIENT_REQ_FLAG_MASK);
         setFlag(allowWaitTopFut, ALLOW_WAIT_TOP_FUT_FLAG_MASK);
+        setFlag(recovery, RECOVERY_FLAG_MASK);
     }
 
     /**
@@ -165,6 +170,20 @@
     }
 
     /**
+     * @return Recovery flag.
+     */
+    public final boolean recovery() {
+        return isFlag(RECOVERY_FLAG_MASK);
+    }
+
+    /**
+     * @param val Recovery flag.
+     */
+    public void recovery(boolean val) {
+        setFlag(val, RECOVERY_FLAG_MASK);
+    }
+
+    /**
      * @return {@code True} if first optimistic tx prepare request sent from client node.
      */
     public final boolean firstClientRequest() {
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 3ea8f4c..7f386d8 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
@@ -80,6 +80,7 @@
 import org.apache.ignite.internal.processors.cache.mvcc.txlog.TxState;
 import org.apache.ignite.internal.processors.cache.persistence.CacheDataRow;
 import org.apache.ignite.internal.processors.cache.persistence.DatabaseLifecycleListener;
+import org.apache.ignite.internal.processors.cache.persistence.GridCacheDatabaseSharedManager;
 import org.apache.ignite.internal.processors.cache.persistence.IgniteCacheDatabaseSharedManager;
 import org.apache.ignite.internal.processors.cache.transactions.IgniteInternalTx;
 import org.apache.ignite.internal.processors.cache.tree.mvcc.data.MvccDataRow;
@@ -347,6 +348,11 @@
     /** {@inheritDoc} */
     @Override public void beforeBinaryMemoryRestore(IgniteCacheDatabaseSharedManager mgr) throws IgniteCheckedException {
         txLogPageStoreInit(mgr);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void afterBinaryMemoryRestore(IgniteCacheDatabaseSharedManager mgr,
+        GridCacheDatabaseSharedManager.RestoreBinaryState restoreState) throws IgniteCheckedException {
 
         boolean hasMvccCaches = ctx.cache().persistentCaches().stream()
             .anyMatch(c -> c.cacheConfiguration().getAtomicityMode() == TRANSACTIONAL_SNAPSHOT);
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/CheckpointFuture.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/CheckpointFuture.java
index 1c77013..76717381 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/CheckpointFuture.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/CheckpointFuture.java
@@ -31,5 +31,5 @@
     /**
      * @return Finish future.
      */
-    public GridFutureAdapter finishFuture();
+    public GridFutureAdapter<Object> finishFuture();
 }
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/DatabaseLifecycleListener.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/DatabaseLifecycleListener.java
index 6762109..34ad751 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/DatabaseLifecycleListener.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/DatabaseLifecycleListener.java
@@ -51,20 +51,24 @@
     /**
      * Callback executed when binary memory has fully restored and WAL logging is resumed.
      *
-     * @param binaryState Result of binary recovery.
+     *
+     * @param mgr
+     * @param restoreState Result of binary recovery.
      * @throws IgniteCheckedException If failed.
      */
-    public default void afterBinaryMemoryRestore(GridCacheDatabaseSharedManager.RestoreBinaryState binaryState)
-        throws IgniteCheckedException {}
+    public default void afterBinaryMemoryRestore(IgniteCacheDatabaseSharedManager mgr,
+        GridCacheDatabaseSharedManager.RestoreBinaryState restoreState) throws IgniteCheckedException {}
 
     /**
      * Callback executed when all logical updates were applied and page memory become to fully consistent state.
      *
-     * @param logicalState Result of logical recovery.
+     *
+     * @param mgr
+     * @param restoreState Result of logical recovery.
      * @throws IgniteCheckedException If failed.
      */
-    public default void afterLogicalUpdatesApplied(GridCacheDatabaseSharedManager.RestoreLogicalState logicalState)
-        throws IgniteCheckedException {}
+    public default void afterLogicalUpdatesApplied(IgniteCacheDatabaseSharedManager mgr,
+        GridCacheDatabaseSharedManager.RestoreLogicalState restoreState) throws IgniteCheckedException {}
 
     /**
      * Callback executed when all physical updates are applied and we are ready to write new physical records
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheDatabaseSharedManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheDatabaseSharedManager.java
index eb52ee6..95a99fb 100755
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheDatabaseSharedManager.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheDatabaseSharedManager.java
@@ -137,6 +137,7 @@
 import org.apache.ignite.internal.processors.cache.persistence.wal.FileWALPointer;
 import org.apache.ignite.internal.processors.cache.persistence.wal.crc.IgniteDataIntegrityViolationException;
 import org.apache.ignite.internal.processors.port.GridPortRecord;
+import org.apache.ignite.internal.processors.query.GridQueryProcessor;
 import org.apache.ignite.internal.util.GridMultiCollectionWrapper;
 import org.apache.ignite.internal.util.IgniteUtils;
 import org.apache.ignite.internal.util.future.CountDownFuture;
@@ -943,7 +944,7 @@
             cctx.wal().resumeLogging(restored);
 
             for (DatabaseLifecycleListener lsnr : getDatabaseListeners(cctx.kernalContext()))
-                lsnr.afterBinaryMemoryRestore(binaryState);
+                lsnr.afterBinaryMemoryRestore(this, binaryState);
 
             if (log.isInfoEnabled())
                 log.info("Binary recovery performed in " + (System.currentTimeMillis() - time) + " ms.");
@@ -1342,16 +1343,19 @@
 
     /** {@inheritDoc} */
     @Override public void rebuildIndexesIfNeeded(GridDhtPartitionsExchangeFuture fut) {
-        if (cctx.kernalContext().query().moduleEnabled()) {
+        GridQueryProcessor qryProc = cctx.kernalContext().query();
+
+        if (qryProc.moduleEnabled()) {
             for (final GridCacheContext cacheCtx : (Collection<GridCacheContext>)cctx.cacheContexts()) {
                 if (cacheCtx.startTopologyVersion().equals(fut.initialVersion())) {
                     final int cacheId = cacheCtx.cacheId();
                     final GridFutureAdapter<Void> usrFut = idxRebuildFuts.get(cacheId);
 
-                    if (!cctx.pageStore().hasIndexStore(cacheCtx.groupId()) && cacheCtx.affinityNode()
-                        && cacheCtx.group().persistenceEnabled()) {
-                        IgniteInternalFuture<?> rebuildFut = cctx.kernalContext().query()
-                            .rebuildIndexesFromHash(Collections.singleton(cacheCtx.cacheId()));
+                    IgniteInternalFuture<?> rebuildFut = qryProc.rebuildIndexesFromHash(cacheCtx);
+
+                    if (rebuildFut != null) {
+                        log().info("Started indexes rebuilding for cache [name=" + cacheCtx.name()
+                            + ", grpName=" + cacheCtx.group().name() + ']');
 
                         assert usrFut != null : "Missing user future for cache: " + cacheCtx.name();
 
@@ -2468,7 +2472,7 @@
                 ", time=" + (U.currentTimeMillis() - start) + " ms]");
 
         for (DatabaseLifecycleListener lsnr : getDatabaseListeners(cctx.kernalContext()))
-            lsnr.afterLogicalUpdatesApplied(restoreLogicalState);
+            lsnr.afterLogicalUpdatesApplied(this, restoreLogicalState);
 
         return restoreLogicalState;
     }
@@ -4277,7 +4281,7 @@
         }
 
         /** {@inheritDoc} */
-        @Override public GridFutureAdapter finishFuture() {
+        @Override public GridFutureAdapter<Object> finishFuture() {
             return cpFinishFut;
         }
     }
@@ -4709,7 +4713,9 @@
             cctx.pageStore().initializeForMetastorage();
         }
 
-        @Override public void afterBinaryMemoryRestore(RestoreBinaryState binaryState) throws IgniteCheckedException {
+        @Override public void afterBinaryMemoryRestore(
+            IgniteCacheDatabaseSharedManager mgr,
+            RestoreBinaryState restoreState) throws IgniteCheckedException {
             assert metaStorage == null;
 
             metaStorage = createMetastorage(false);
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 44ae6f1..e1bd8dd 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
@@ -142,6 +142,7 @@
             ctx.wal(),
             globalRemoveId(),
             grp.groupId(),
+            grp.sharedGroup(),
             PageIdAllocator.INDEX_PARTITION,
             PageIdAllocator.FLAG_IDX,
             reuseList,
@@ -835,19 +836,13 @@
     }
 
     /** {@inheritDoc} */
-    @Override public RootPage rootPageForIndex(int cacheId, String idxName) throws IgniteCheckedException {
-        if (grp.sharedGroup())
-            idxName = Integer.toString(cacheId) + "_" + idxName;
-
-        return indexStorage.getOrAllocateForTree(idxName);
+    @Override public RootPage rootPageForIndex(int cacheId, String idxName, int segment) throws IgniteCheckedException {
+        return indexStorage.allocateCacheIndex(cacheId, idxName, segment);
     }
 
     /** {@inheritDoc} */
-    @Override public void dropRootPageForIndex(int cacheId, String idxName) throws IgniteCheckedException {
-        if (grp.sharedGroup())
-            idxName = Integer.toString(cacheId) + "_" + idxName;
-
-        indexStorage.dropRootPage(idxName);
+    @Override public void dropRootPageForIndex(int cacheId, String idxName, int segment) throws IgniteCheckedException {
+        indexStorage.dropCacheIndex(cacheId, idxName, segment);
     }
 
     /** {@inheritDoc} */
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/IndexStorage.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/IndexStorage.java
index 5141b04..295ff00 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/IndexStorage.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/IndexStorage.java
@@ -24,6 +24,17 @@
  */
 public interface IndexStorage {
     /**
+     * Allocate page for cache index. Index name will be masked if needed.
+     *
+     * @param cacheId Cache ID.
+     * @param idxName Index name.
+     * @param segment Segment.
+     * @return Root page.
+     * @throws IgniteCheckedException If failed.
+     */
+    public RootPage allocateCacheIndex(Integer cacheId, String idxName, int segment) throws IgniteCheckedException;
+
+    /**
      * Get or allocate initial page for an index.
      *
      * @param idxName Index name.
@@ -31,7 +42,18 @@
      *      was newly allocated, and rootId that is counter which increments each time new page allocated.
      * @throws IgniteCheckedException If failed.
      */
-    public RootPage getOrAllocateForTree(String idxName) throws IgniteCheckedException;
+    public RootPage allocateIndex(String idxName) throws IgniteCheckedException;
+
+    /**
+     * Deallocate index page and remove from tree.
+     *
+     * @param cacheId Cache ID.
+     * @param idxName Index name.
+     * @param segment Segment.
+     * @return Root ID or -1 if no page was removed.
+     * @throws IgniteCheckedException  If failed.
+     */
+    public RootPage dropCacheIndex(Integer cacheId, String idxName, int segment) throws IgniteCheckedException;
 
     /**
      * Deallocate index page and remove from tree.
@@ -40,7 +62,7 @@
      * @return Root ID or -1 if no page was removed.
      * @throws IgniteCheckedException  If failed.
      */
-    public RootPage dropRootPage(String idxName) throws IgniteCheckedException;
+    public RootPage dropIndex(String idxName) throws IgniteCheckedException;
 
     /**
      * Destroy this meta store.
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/IndexStorageImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/IndexStorageImpl.java
index 6248765..b29553c 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/IndexStorageImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/IndexStorageImpl.java
@@ -61,6 +61,9 @@
     /** Cache group ID. */
     private final int grpId;
 
+    /** Whether group is shared. */
+    private final boolean grpShared;
+
     /** */
     private final int allocPartId;
 
@@ -76,6 +79,7 @@
         final IgniteWriteAheadLogManager wal,
         final AtomicLong globalRmvId,
         final int grpId,
+        boolean grpShared,
         final int allocPartId,
         final byte allocSpace,
         final ReuseList reuseList,
@@ -86,6 +90,7 @@
         try {
             this.pageMem = pageMem;
             this.grpId = grpId;
+            this.grpShared = grpShared;
             this.allocPartId = allocPartId;
             this.allocSpace = allocSpace;
             this.reuseList = reuseList;
@@ -99,7 +104,15 @@
     }
 
     /** {@inheritDoc} */
-    @Override public RootPage getOrAllocateForTree(final String idxName) throws IgniteCheckedException {
+    @Override public RootPage allocateCacheIndex(Integer cacheId, String idxName, int segment)
+        throws IgniteCheckedException {
+        String maskedIdxName = maskCacheIndexName(cacheId, idxName, segment);
+
+        return allocateIndex(maskedIdxName);
+    }
+
+    /** {@inheritDoc} */
+    @Override public RootPage allocateIndex(String idxName) throws IgniteCheckedException {
         final MetaTree tree = metaTree;
 
         synchronized (this) {
@@ -132,8 +145,15 @@
     }
 
     /** {@inheritDoc} */
-    @Override public RootPage dropRootPage(final String idxName)
+    @Override public RootPage dropCacheIndex(Integer cacheId, String idxName, int segment)
         throws IgniteCheckedException {
+        String maskedIdxName = maskCacheIndexName(cacheId, idxName, segment);
+
+        return dropIndex(maskedIdxName);
+    }
+
+    /** {@inheritDoc} */
+    @Override public RootPage dropIndex(final String idxName) throws IgniteCheckedException {
         byte[] idxNameBytes = idxName.getBytes(StandardCharsets.UTF_8);
 
         final IndexItem row = metaTree.remove(new IndexItem(idxNameBytes, 0));
@@ -152,6 +172,19 @@
     }
 
     /**
+     * Mask cache index name.
+     *
+     * @param idxName Index name.
+     * @return Masked name.
+     */
+    private String maskCacheIndexName(Integer cacheId, String idxName, int segment) {
+        if (grpShared)
+            idxName = Integer.toString(cacheId) + "_" + idxName;
+
+        return idxName + "%" + segment;
+    }
+
+    /**
      *
      */
     private static class MetaTree extends BPlusTree<IndexItem, IndexItem> {
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/migration/UpgradePendingTreeToPerPartitionTask.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/migration/UpgradePendingTreeToPerPartitionTask.java
index 6fa039d..1cba69a 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/migration/UpgradePendingTreeToPerPartitionTask.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/migration/UpgradePendingTreeToPerPartitionTask.java
@@ -131,14 +131,14 @@
             IndexStorage indexStorage = ((GridCacheOffheapManager)grp.offheap()).getIndexStorage();
 
             //TODO: IGNITE-5874: replace with some check-method to avoid unnecessary page allocation.
-            RootPage pendingRootPage = indexStorage.getOrAllocateForTree(PENDING_ENTRIES_TREE_NAME);
+            RootPage pendingRootPage = indexStorage.allocateIndex(PENDING_ENTRIES_TREE_NAME);
 
             if (pendingRootPage.isAllocated()) {
                 log.info("No pending tree found for cache group: [grpId=" + grp.groupId() +
                     ", grpName=" + grp.name() + ']');
 
                 // Nothing to do here as just allocated tree is obviously empty.
-                indexStorage.dropRootPage(PENDING_ENTRIES_TREE_NAME);
+                indexStorage.dropIndex(PENDING_ENTRIES_TREE_NAME);
 
                 return;
             }
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxAdapter.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxAdapter.java
index ec1b646..47a0276 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxAdapter.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxAdapter.java
@@ -17,6 +17,8 @@
 
 package org.apache.ignite.internal.processors.cache.transactions;
 
+import javax.cache.expiry.ExpiryPolicy;
+import javax.cache.processor.EntryProcessor;
 import java.io.Externalizable;
 import java.io.IOException;
 import java.io.ObjectInput;
@@ -37,8 +39,6 @@
 import java.util.concurrent.atomic.AtomicLong;
 import java.util.concurrent.atomic.AtomicReference;
 import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
-import javax.cache.expiry.ExpiryPolicy;
-import javax.cache.processor.EntryProcessor;
 import org.apache.ignite.IgniteCheckedException;
 import org.apache.ignite.IgniteException;
 import org.apache.ignite.IgniteLogger;
@@ -287,6 +287,9 @@
     @GridToStringExclude
     private volatile TxCounters txCounters;
 
+    /** Transaction from which this transaction was copied by(if it was). */
+    private GridNearTxLocal parentTx;
+
     /**
      * Empty constructor required for {@link Externalizable}.
      */
@@ -406,6 +409,13 @@
     }
 
     /**
+     * @param parentTx Transaction from which this transaction was copied by.
+     */
+    public void setParentTx(GridNearTxLocal parentTx) {
+        this.parentTx = parentTx;
+    }
+
+    /**
      * @return Mvcc info.
      */
     @Override @Nullable public MvccSnapshot mvccSnapshot() {
@@ -1044,6 +1054,19 @@
         return state(state, false);
     }
 
+    /**
+     * Changing state for this transaction as well as chained(parent) transactions.
+     *
+     * @param state Transaction state.
+     * @return {@code True} if transition was valid, {@code false} otherwise.
+     */
+    public boolean chainState(TransactionState state) {
+        if (parentTx != null)
+            parentTx.state(state);
+
+        return state(state);
+    }
+
     /** {@inheritDoc} */
     @Override public IgniteInternalFuture<IgniteInternalTx> finishFuture() {
         GridFutureAdapter<IgniteInternalTx> fut = finFut;
@@ -1162,11 +1185,11 @@
             }
 
             if (valid) {
-                this.state = state;
-
                 if (timedOut)
                     this.timedOut = true;
 
+                this.state = state;
+
                 if (log.isDebugEnabled())
                     log.debug("Changed transaction state [prev=" + prev + ", new=" + this.state + ", tx=" + this + ']');
 
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxHandler.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxHandler.java
index aefd54c..319073b 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxHandler.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxHandler.java
@@ -342,14 +342,17 @@
     }
 
     /**
+     * @param originTx Transaction for copy.
      * @param req Request.
      * @return Prepare future.
      */
-    public IgniteInternalFuture<GridNearTxPrepareResponse> prepareNearTxLocal(final GridNearTxPrepareRequest req) {
+    public IgniteInternalFuture<GridNearTxPrepareResponse>  prepareNearTxLocal(
+        final GridNearTxLocal originTx,
+        final GridNearTxPrepareRequest req) {
         // Make sure not to provide Near entries to DHT cache.
         req.cloneEntries();
 
-        return prepareNearTx(ctx.localNode(), req);
+        return prepareNearTx(originTx, ctx.localNode(), req);
     }
 
     /**
@@ -361,6 +364,20 @@
         final ClusterNode nearNode,
         final GridNearTxPrepareRequest req
     ) {
+        return prepareNearTx(null, nearNode, req);
+    }
+
+    /**
+     * @param originTx Transaction for copy.
+     * @param nearNode Node that initiated transaction.
+     * @param req Near prepare request.
+     * @return Prepare future or {@code null} if need retry operation.
+     */
+    @Nullable private IgniteInternalFuture<GridNearTxPrepareResponse> prepareNearTx(
+        final GridNearTxLocal originTx,
+        final ClusterNode nearNode,
+        final GridNearTxPrepareRequest req
+    ) {
         IgniteTxEntry firstEntry;
 
         try {
@@ -509,7 +526,8 @@
                     req.transactionNodes(),
                     req.subjectId(),
                     req.taskNameHash(),
-                    req.txLabel()
+                    req.txLabel(),
+                    originTx
                 );
 
                 tx = ctx.tm().onCreated(null, tx);
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 2b76772..808b7ca 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
@@ -303,6 +303,11 @@
     }
 
     /** {@inheritDoc} */
+    @Override public boolean recovery() {
+        return recovery;
+    }
+
+    /** {@inheritDoc} */
     @Override public String toString() {
         return S.toString(IgniteTxImplicitSingleStateImpl.class, this);
     }
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxLocalState.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxLocalState.java
index 01eb4f4..e007f90 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxLocalState.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxLocalState.java
@@ -57,4 +57,9 @@
      * @param partId Partition id.
      */
     public void touchPartition(int cacheId, int partId);
+
+    /**
+     * @return Recovery mode flag.
+     */
+    public boolean recovery();
 }
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxStateImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxStateImpl.java
index cd8c6e9..8a00244 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxStateImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxStateImpl.java
@@ -149,7 +149,7 @@
 
             assert ctx != null : cacheId;
 
-            Throwable err = topFut.validateCache(ctx, recovery != null && recovery, read, null, e.getValue());
+            Throwable err = topFut.validateCache(ctx, recovery(), read, null, e.getValue());
 
             if (err != null) {
                 if (invalidCaches != null)
@@ -181,6 +181,11 @@
     }
 
     /** {@inheritDoc} */
+    @Override public boolean recovery() {
+        return recovery != null && recovery;
+    }
+
+    /** {@inheritDoc} */
     @Override public CacheWriteSynchronizationMode syncMode(GridCacheSharedContext cctx) {
         CacheWriteSynchronizationMode syncMode = CacheWriteSynchronizationMode.FULL_ASYNC;
 
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/verify/VerifyBackupPartitionsTaskV2.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/verify/VerifyBackupPartitionsTaskV2.java
index e698e3a..14995cb 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/verify/VerifyBackupPartitionsTaskV2.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/verify/VerifyBackupPartitionsTaskV2.java
@@ -36,20 +36,26 @@
 import org.apache.ignite.IgniteException;
 import org.apache.ignite.IgniteInterruptedException;
 import org.apache.ignite.IgniteLogger;
+import org.apache.ignite.cache.CacheMode;
 import org.apache.ignite.cluster.ClusterNode;
 import org.apache.ignite.compute.ComputeJob;
 import org.apache.ignite.compute.ComputeJobAdapter;
 import org.apache.ignite.compute.ComputeJobResult;
 import org.apache.ignite.compute.ComputeTaskAdapter;
+import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.configuration.DataStorageConfiguration;
 import org.apache.ignite.internal.IgniteEx;
 import org.apache.ignite.internal.processors.cache.CacheGroupContext;
 import org.apache.ignite.internal.processors.cache.DynamicCacheDescriptor;
+import org.apache.ignite.internal.processors.cache.GridCacheUtils;
 import org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridDhtLocalPartition;
 import org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridDhtPartitionState;
 import org.apache.ignite.internal.processors.cache.persistence.CacheDataRow;
 import org.apache.ignite.internal.processors.task.GridInternal;
 import org.apache.ignite.internal.util.lang.GridIterator;
 import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.internal.visor.verify.CacheFilterEnum;
+import org.apache.ignite.internal.visor.verify.VisorIdleVerifyDumpTaskArg;
 import org.apache.ignite.internal.visor.verify.VisorIdleVerifyTaskArg;
 import org.apache.ignite.lang.IgniteProductVersion;
 import org.apache.ignite.resources.IgniteInstanceResource;
@@ -176,7 +182,7 @@
                 for (String cacheName : arg.getCaches()) {
                     DynamicCacheDescriptor desc = ignite.context().cache().cacheDescriptor(cacheName);
 
-                    if (desc == null) {
+                    if (desc == null || !isCacheMatchFilter(cacheName)) {
                         missingCaches.add(cacheName);
 
                         continue;
@@ -185,15 +191,13 @@
                     grpIds.add(desc.groupId());
                 }
 
-                if (!missingCaches.isEmpty()) {
-                    StringBuilder strBuilder = new StringBuilder("The following caches do not exist: ");
-
-                    for (String name : missingCaches)
-                        strBuilder.append(name).append(", ");
-
-                    strBuilder.delete(strBuilder.length() - 2, strBuilder.length());
-
-                    throw new IgniteException(strBuilder.toString());
+                handlingMissedCaches(missingCaches);
+            }
+            else if (onlySpecificCaches()) {
+                for (DynamicCacheDescriptor desc : ignite.context().cache().cacheDescriptors().values()) {
+                    if (desc.cacheConfiguration().getCacheMode() != CacheMode.LOCAL
+                        && isCacheMatchFilter(desc.cacheName()))
+                        grpIds.add(desc.groupId());
                 }
             }
             else {
@@ -260,6 +264,79 @@
         }
 
         /**
+         *  Checks and throw exception if caches was missed.
+         *
+         * @param missingCaches Missing caches.
+         */
+        private void handlingMissedCaches(Set<String> missingCaches) {
+            if (missingCaches.isEmpty())
+                return;
+
+            StringBuilder strBuilder = new StringBuilder("The following caches do not exist");
+
+            if (onlySpecificCaches()) {
+                VisorIdleVerifyDumpTaskArg vdta = (VisorIdleVerifyDumpTaskArg)arg;
+
+                strBuilder.append(" or do not match to the given filter [")
+                    .append(vdta.getCacheFilterEnum())
+                    .append("]: ");
+            }
+            else
+                strBuilder.append(": ");
+
+            for (String name : missingCaches)
+                strBuilder.append(name).append(", ");
+
+            strBuilder.delete(strBuilder.length() - 2, strBuilder.length());
+
+            throw new IgniteException(strBuilder.toString());
+        }
+
+        /**
+         * @return True if validates only specific caches, else false.
+         */
+        private boolean onlySpecificCaches() {
+            if (arg instanceof VisorIdleVerifyDumpTaskArg) {
+                VisorIdleVerifyDumpTaskArg vdta = (VisorIdleVerifyDumpTaskArg)arg;
+
+                return vdta.getCacheFilterEnum() != CacheFilterEnum.ALL;
+            }
+
+            return false;
+        }
+
+        /**
+         * @param cacheName Cache name.
+         */
+        private boolean isCacheMatchFilter(String cacheName) {
+            if (arg instanceof VisorIdleVerifyDumpTaskArg) {
+                DataStorageConfiguration dsc = ignite.context().config().getDataStorageConfiguration();
+                DynamicCacheDescriptor desc = ignite.context().cache().cacheDescriptor(cacheName);
+                CacheConfiguration cc = desc.cacheConfiguration();
+                VisorIdleVerifyDumpTaskArg vdta = (VisorIdleVerifyDumpTaskArg)arg;
+
+                switch (vdta.getCacheFilterEnum()) {
+                    case SYSTEM:
+                        return !desc.cacheType().userCache();
+
+                    case NOT_PERSISTENT:
+                        return desc.cacheType().userCache() && !GridCacheUtils.isPersistentCache(cc, dsc);
+
+                    case PERSISTENT:
+                        return desc.cacheType().userCache() && GridCacheUtils.isPersistentCache(cc, dsc);
+
+                    case ALL:
+                        break;
+
+                    default:
+                        assert false: "Illegal cache filter: " + vdta.getCacheFilterEnum();
+                }
+            }
+
+            return true;
+        }
+
+        /**
          * @param grpCtx Group context.
          * @param part Local partition.
          */
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cluster/GridClusterStateProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cluster/GridClusterStateProcessor.java
index 95ff770..9d2adae 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cluster/GridClusterStateProcessor.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cluster/GridClusterStateProcessor.java
@@ -414,7 +414,7 @@
         if (msg.requestId().equals(state.transitionRequestId())) {
             log.info("Received state change finish message: " + msg.clusterActive());
 
-            globalState = globalState.finish(msg.success());
+            globalState = state.finish(msg.success());
 
             afterStateChangeFinished(msg.id(), msg.success());
 
@@ -904,15 +904,19 @@
             forceChangeBaselineTopology,
             System.currentTimeMillis());
 
+        IgniteInternalFuture<?> resFut = wrapStateChangeFuture(startedFut, msg);
+
         try {
             if (log.isInfoEnabled())
                 U.log(log, "Sending " + prettyStr(activate) + " request with BaselineTopology " + blt);
 
             ctx.discovery().sendCustomEvent(msg);
 
-            if (ctx.isStopping())
-                startedFut.onDone(new IgniteCheckedException("Failed to execute " + prettyStr(activate) + " request, " +
-                    "node is stopping."));
+            if (ctx.isStopping()) {
+                String errMsg = "Failed to execute " + prettyStr(activate) + " request, node is stopping.";
+
+                startedFut.onDone(new IgniteCheckedException(errMsg));
+            }
         }
         catch (IgniteCheckedException e) {
             U.error(log, "Failed to send global state change request: " + activate, e);
@@ -920,7 +924,7 @@
             startedFut.onDone(e);
         }
 
-        return wrapStateChangeFuture(startedFut, msg);
+        return resFut;
     }
 
     /** {@inheritDoc} */
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 dab2516..2abafab 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
@@ -27,8 +27,10 @@
 import org.apache.ignite.cache.query.SqlFieldsQuery;
 import org.apache.ignite.cache.query.SqlQuery;
 import org.apache.ignite.internal.GridKernalContext;
+import org.apache.ignite.internal.IgniteInternalFuture;
 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;
@@ -197,20 +199,20 @@
      *
      * @param cacheName Cache name.
      * @param schemaName Schema name.
-     * @param cctx Cache context.
+     * @param cacheInfo Cache context info.
      * @throws IgniteCheckedException If failed.
      */
-    public void registerCache(String cacheName, String schemaName, GridCacheContext<?,?> cctx)
+    public void registerCache(String cacheName, String schemaName, GridCacheContextInfo<?, ?> cacheInfo)
         throws IgniteCheckedException;
 
     /**
      * Unregisters cache.
      *
-     * @param cctx Cache context.
+     * @param cacheInfo Cache context info.
      * @param rmvIdx If {@code true}, will remove index.
      * @throws IgniteCheckedException If failed to drop cache schema.
      */
-    public void unregisterCache(GridCacheContext cctx, boolean rmvIdx) throws IgniteCheckedException;
+    public void unregisterCache(GridCacheContextInfo cacheInfo, boolean rmvIdx) throws IgniteCheckedException;
 
     /**
      *
@@ -237,12 +239,14 @@
     /**
      * Registers type if it was not known before or updates it otherwise.
      *
-     * @param cctx Cache context.
+     * @param cacheInfo Cache context info.
      * @param desc Type descriptor.
+     * @param isSql {@code true} in case table has been created from SQL.
      * @throws IgniteCheckedException If failed.
      * @return {@code True} if type was registered, {@code false} if for some reason it was rejected.
      */
-    public boolean registerType(GridCacheContext cctx, GridQueryTypeDescriptor desc, boolean isSql) throws IgniteCheckedException;
+    public boolean registerType(GridCacheContextInfo cacheInfo, GridQueryTypeDescriptor desc,
+        boolean isSql) throws IgniteCheckedException;
 
     /**
      * Updates index. Note that key is unique for cache, so if cache contains multiple indexes
@@ -273,19 +277,12 @@
         throws IgniteCheckedException;
 
     /**
-     * Rebuilds all indexes of given type from hash index.
+     * Rebuild indexes for the given cache if necessary.
      *
-     * @param cacheName Cache name.
-     * @throws IgniteCheckedException If failed.
+     * @param cctx Cache context.
+     * @return Future completed when index rebuild finished.
      */
-    public void rebuildIndexesFromHash(String cacheName) throws IgniteCheckedException;
-
-    /**
-     * Marks all indexes of given type for rebuild from hash index, making them unusable until rebuild finishes.
-     *
-     * @param cacheName Cache name.
-     */
-    public void markForRebuildFromHash(String cacheName);
+    public IgniteInternalFuture<?> rebuildIndexesFromHash(GridCacheContext cctx);
 
     /**
      * Returns backup filter.
@@ -354,4 +351,22 @@
      * @return Row cache cleaner.
      */
     public GridQueryRowCacheCleaner rowCacheCleaner(int cacheGroupId);
+
+    /**
+     * Return context for registered cache info.
+     *
+     * @param cacheName Cache name.
+     * @return Cache context for registered cache or {@code null} in case the cache has not been registered.
+     */
+    @Nullable public GridCacheContextInfo registeredCacheInfo(String cacheName);
+
+    /**
+     * Initialize table's cache context created for not started cache.
+     *
+     * @param ctx Cache context.
+     * @throws IgniteCheckedException If failed.
+     *
+     * @return {@code true} If context has been initialized.
+     */
+    public boolean initCacheContext(GridCacheContext ctx) throws IgniteCheckedException;
 }
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 d3f2930..da5233a 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
@@ -63,8 +63,9 @@
 import org.apache.ignite.internal.processors.cache.CacheObject;
 import org.apache.ignite.internal.processors.cache.CacheObjectContext;
 import org.apache.ignite.internal.processors.cache.DynamicCacheDescriptor;
-import org.apache.ignite.internal.processors.cache.GridCacheAdapter;
 import org.apache.ignite.internal.processors.cache.GridCacheContext;
+import org.apache.ignite.internal.processors.cache.IgniteCacheOffheapManager;
+import org.apache.ignite.internal.processors.cache.GridCacheContextInfo;
 import org.apache.ignite.internal.processors.cache.KeyCacheObject;
 import org.apache.ignite.internal.processors.cache.QueryCursorImpl;
 import org.apache.ignite.internal.processors.cache.mvcc.MvccSnapshot;
@@ -93,7 +94,6 @@
 import org.apache.ignite.internal.processors.timeout.GridTimeoutProcessor;
 import org.apache.ignite.internal.util.GridBoundedConcurrentLinkedHashSet;
 import org.apache.ignite.internal.util.GridSpinBusyLock;
-import org.apache.ignite.internal.util.future.GridCompoundFuture;
 import org.apache.ignite.internal.util.future.GridFinishedFuture;
 import org.apache.ignite.internal.util.lang.GridCloseableIterator;
 import org.apache.ignite.internal.util.lang.GridClosureException;
@@ -106,8 +106,6 @@
 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;
-import org.apache.ignite.internal.util.worker.GridWorker;
-import org.apache.ignite.internal.util.worker.GridWorkerFuture;
 import org.apache.ignite.lang.IgniteBiTuple;
 import org.apache.ignite.lang.IgniteFuture;
 import org.apache.ignite.lang.IgniteInClosure;
@@ -673,23 +671,26 @@
     /**
      * Create type descriptors from schema and initialize indexing for given cache.<p>
      * Use with {@link #busyLock} where appropriate.
-     * @param cctx Cache context.
+     * @param cacheInfo Cache context info.
      * @param schema Initial schema.
      * @param isSql {@code true} in case create cache initialized from SQL.
      * @throws IgniteCheckedException If failed.
      */
-    public void onCacheStart0(GridCacheContext<?, ?> cctx, QuerySchema schema, boolean isSql)
+    public void onCacheStart0(GridCacheContextInfo<?, ?> cacheInfo, QuerySchema schema, boolean isSql)
         throws IgniteCheckedException {
 
-        cctx.shared().database().checkpointReadLock();
+        ctx.cache().context().database().checkpointReadLock();
 
         try {
+            if (cacheInfo.isClientCache() && cacheInfo.isCacheContextInited() && idx.initCacheContext(cacheInfo.gridCacheContext()))
+                return;
+
             synchronized (stateMux) {
-                boolean escape = cctx.config().isSqlEscapeAll();
+                boolean escape = cacheInfo.config().isSqlEscapeAll();
 
-                String cacheName = cctx.name();
+                String cacheName = cacheInfo.name();
 
-                String schemaName = QueryUtils.normalizeSchemaName(cacheName, cctx.config().getSqlSchema());
+                String schemaName = QueryUtils.normalizeSchemaName(cacheName, cacheInfo.config().getSqlSchema());
 
                 // Prepare candidates.
                 List<Class<?>> mustDeserializeClss = new ArrayList<>();
@@ -700,7 +701,7 @@
 
                 if (!F.isEmpty(qryEntities)) {
                     for (QueryEntity qryEntity : qryEntities) {
-                        QueryTypeCandidate cand = QueryUtils.typeForQueryEntity(cacheName, schemaName, cctx, qryEntity,
+                        QueryTypeCandidate cand = QueryUtils.typeForQueryEntity(cacheName, schemaName, cacheInfo, qryEntity,
                             mustDeserializeClss, escape);
 
                         cands.add(cand);
@@ -735,7 +736,7 @@
                 // Apply pending operation which could have been completed as no-op at this point.
                 // There could be only one in-flight operation for a cache.
                 for (SchemaOperation op : schemaOps.values()) {
-                    if (F.eq(op.proposeMessage().deploymentId(), cctx.dynamicDeploymentId())) {
+                    if (F.eq(op.proposeMessage().deploymentId(), cacheInfo.dynamicDeploymentId())) {
                         if (op.started()) {
                             SchemaOperationWorker worker = op.manager().worker();
 
@@ -799,7 +800,7 @@
                 }
 
                 // Ready to register at this point.
-                registerCache0(cacheName, schemaName, cctx, cands, isSql);
+                registerCache0(cacheName, schemaName, cacheInfo, cands, isSql);
 
                 // Warn about possible implicit deserialization.
                 if (!mustDeserializeClss.isEmpty()) {
@@ -813,7 +814,7 @@
             }
         }
         finally {
-            cctx.shared().database().checkpointReadUnlock();
+            ctx.cache().context().database().checkpointReadUnlock();
         }
     }
 
@@ -848,12 +849,13 @@
      * When called for the first time, we initialize topology thus understanding whether current node is coordinator
      * or not.
      *
-     * @param cctx Cache context.
+     * @param cacheInfo Cache context info.
      * @param schema Index states.
      * @param isSql {@code true} in case create cache initialized from SQL.
      * @throws IgniteCheckedException If failed.
      */
-    public void onCacheStart(GridCacheContext cctx, QuerySchema schema, boolean isSql) throws IgniteCheckedException {
+    public void onCacheStart(GridCacheContextInfo cacheInfo, QuerySchema schema,
+        boolean isSql) throws IgniteCheckedException {
         if (idx == null)
             return;
 
@@ -861,7 +863,7 @@
             return;
 
         try {
-            onCacheStart0(cctx, schema, isSql);
+            onCacheStart0(cacheInfo, schema, isSql);
         }
         finally {
             busyLock.leaveBusy();
@@ -869,10 +871,26 @@
     }
 
     /**
-     * @param cctx Cache context.
+     * Destroy H2 structures for not started caches.
+     *
+     * @param cacheName Cache name.
+     */
+    public void onCacheStop(String cacheName) {
+        if (idx == null)
+            return;
+
+        GridCacheContextInfo cacheInfo = idx.registeredCacheInfo(cacheName);
+
+        if (cacheInfo != null)
+            onCacheStop(cacheInfo, true);
+    }
+
+
+    /**
+     * @param cacheInfo Cache context info.
      * @param removeIdx If {@code true}, will remove index.
      */
-    public void onCacheStop(GridCacheContext cctx, boolean removeIdx) {
+    public void onCacheStop(GridCacheContextInfo cacheInfo, boolean removeIdx) {
         if (idx == null)
             return;
 
@@ -880,7 +898,7 @@
             return;
 
         try {
-            onCacheStop0(cctx, removeIdx);
+            onCacheStop0(cacheInfo, removeIdx);
         }
         finally {
             busyLock.leaveBusy();
@@ -1416,9 +1434,9 @@
 
         String cacheName = op.cacheName();
 
-        GridCacheAdapter cache = ctx.cache().internalCache(cacheName);
+        GridCacheContextInfo cacheInfo = idx.registeredCacheInfo(cacheName);
 
-        if (cache == null || !F.eq(depId, cache.context().dynamicDeploymentId()))
+        if (cacheInfo == null || !F.eq(depId, cacheInfo.dynamicDeploymentId()))
             throw new SchemaOperationException(SchemaOperationException.CODE_CACHE_NOT_FOUND, cacheName);
 
         try {
@@ -1427,11 +1445,18 @@
 
                 QueryIndexDescriptorImpl idxDesc = QueryUtils.createIndexDescriptor(type, op0.index());
 
-                GridCacheContext cctx = cache.context();
+                SchemaIndexCacheVisitor visitor;
 
-                SchemaIndexCacheFilter filter = new TableCacheFilter(cctx, op0.tableName());
+                if (cacheInfo.isCacheContextInited()) {
+                    GridCacheContext cctx = cacheInfo.gridCacheContext();
 
-                SchemaIndexCacheVisitor visitor = new SchemaIndexCacheVisitorImpl(cctx, filter, cancelTok, op0.parallel());
+                    SchemaIndexCacheFilter filter = new TableCacheFilter(cctx, op0.tableName());
+
+                    visitor = new SchemaIndexCacheVisitorImpl(cctx, filter, cancelTok, op0.parallel());
+                }
+                else
+                    //For not started caches we shouldn't add any data to index.
+                    visitor = clo -> {};
 
                 idx.dynamicIndexCreate(op0.schemaName(), op0.tableName(), idxDesc, op0.ifNotExists(), visitor);
             }
@@ -1582,7 +1607,7 @@
      *
      * @param cacheName Cache name.
      * @param schemaName Schema name.
-     * @param cctx Cache context.
+     * @param cacheInfo Cache context info.
      * @param cands Candidates.
      * @param isSql {@code true} in case create cache initialized from SQL.
      * @throws IgniteCheckedException If failed.
@@ -1590,13 +1615,13 @@
     private void registerCache0(
         String cacheName,
         String schemaName,
-        GridCacheContext<?, ?> cctx,
+        GridCacheContextInfo<?, ?> cacheInfo,
         Collection<QueryTypeCandidate> cands,
         boolean isSql
     ) throws IgniteCheckedException {
         synchronized (stateMux) {
             if (idx != null)
-                idx.registerCache(cacheName, schemaName, cctx);
+                idx.registerCache(cacheName, schemaName, cacheInfo);
 
             try {
                 for (QueryTypeCandidate cand : cands) {
@@ -1627,13 +1652,13 @@
                     }
 
                     if (idx != null)
-                        idx.registerType(cctx, desc, isSql);
+                        idx.registerType(cacheInfo, desc, isSql);
                 }
 
                 cacheNames.add(CU.mask(cacheName));
             }
             catch (IgniteCheckedException | RuntimeException e) {
-                onCacheStop0(cctx, true);
+                onCacheStop0(cacheInfo, true);
 
                 throw e;
             }
@@ -1644,14 +1669,14 @@
      * Unregister cache.<p>
      * Use with {@link #busyLock} where appropriate.
      *
-     * @param cctx Cache context.
+     * @param cacheInfo Cache context info.
      * @param destroy Destroy flag.
      */
-    public void onCacheStop0(GridCacheContext cctx, boolean destroy) {
+    public void onCacheStop0(GridCacheContextInfo cacheInfo, boolean destroy) {
         if (idx == null)
             return;
 
-        String cacheName = cctx.name();
+        String cacheName = cacheInfo.name();
 
         synchronized (stateMux) {
             // Clear types.
@@ -1687,7 +1712,7 @@
 
             // Notify indexing.
             try {
-                idx.unregisterCache(cctx, destroy);
+                idx.unregisterCache(cacheInfo, destroy);
             }
             catch (Exception e) {
                 U.error(log, "Failed to clear indexing on cache unregister (will ignore): " + cacheName, e);
@@ -1749,29 +1774,42 @@
     /**
      * Rebuilds indexes for provided caches from corresponding hash indexes.
      *
-     * @param cacheIds Cache IDs.
+     * @param cctx Cache context.
      * @return Future that will be completed when rebuilding is finished.
      */
-    public IgniteInternalFuture<?> rebuildIndexesFromHash(Set<Integer> cacheIds) {
-        if (!busyLock.enterBusy())
-            return new GridFinishedFuture<>(new NodeStoppingException("Failed to rebuild indexes from hash (grid is stopping)."));
+    public IgniteInternalFuture<?> rebuildIndexesFromHash(GridCacheContext cctx) {
+        // Indexing module is disabled, nothing to rebuild.
+        if (idx == null)
+            return null;
 
-        // Because of alt type ids, there can be few entries in 'types' for a single cache.
-        // In order to avoid processing a cache more than once, let's track processed names.
-        Set<String> processedCacheNames = new HashSet<>();
+        // No data on non-affinity nodes.
+        if (!cctx.affinityNode())
+            return null;
+
+        // No indexes to rebuild when there are no QueryEntities.
+        if (!cctx.isQueryEnabled())
+            return null;
+
+        // No need to rebuild if cache has no data.
+        boolean empty = true;
+
+        for (IgniteCacheOffheapManager.CacheDataStore store : cctx.offheap().cacheDataStores()) {
+            if (!store.isEmpty()) {
+                empty = false;
+
+                break;
+            }
+        }
+
+        if (empty)
+            return null;
+
+        if (!busyLock.enterBusy())
+            return new GridFinishedFuture<>(new NodeStoppingException("Failed to rebuild indexes from hash " +
+                "(grid is stopping)."));
 
         try {
-            GridCompoundFuture<Object, ?> fut = new GridCompoundFuture<Object, Object>();
-
-            for (Map.Entry<QueryTypeIdKey, QueryTypeDescriptorImpl> e : types.entrySet()) {
-                if (cacheIds.contains(CU.cacheId(e.getKey().cacheName())) &&
-                    processedCacheNames.add(e.getKey().cacheName()))
-                    fut.add(rebuildIndexesFromHash(e.getKey().cacheName(), e.getValue()));
-            }
-
-            fut.markInitialized();
-
-            return fut;
+            return idx.rebuildIndexesFromHash(cctx);
         }
         finally {
             busyLock.leaveBusy();
@@ -1780,51 +1818,6 @@
 
     /**
      * @param cacheName Cache name.
-     * @param desc Type descriptor.
-     * @return Future that will be completed when rebuilding of all indexes is finished.
-     */
-    private IgniteInternalFuture<Object> rebuildIndexesFromHash(@Nullable final String cacheName,
-        @Nullable final QueryTypeDescriptorImpl desc) {
-        if (idx == null)
-            return new GridFinishedFuture<>(new IgniteCheckedException("Indexing is disabled."));
-
-        if (desc == null)
-            return new GridFinishedFuture<>();
-
-        final GridWorkerFuture<Object> fut = new GridWorkerFuture<>();
-
-        idx.markForRebuildFromHash(cacheName);
-
-        GridWorker w = new GridWorker(ctx.igniteInstanceName(), "index-rebuild-worker", log) {
-            @Override protected void body() {
-                try {
-                    idx.rebuildIndexesFromHash(cacheName);
-
-                    fut.onDone();
-                }
-                catch (Exception e) {
-                    fut.onDone(e);
-                }
-                catch (Throwable e) {
-                    U.error(log, "Failed to rebuild indexes for type [cache=" + cacheName +
-                        ", name=" + desc.name() + ']', e);
-
-                    fut.onDone(e);
-
-                    throw e;
-                }
-            }
-        };
-
-        fut.setWorker(w);
-
-        ctx.getExecutorService().execute(w);
-
-        return fut;
-    }
-
-    /**
-     * @param cacheName Cache name.
      * @return Cache object context.
      */
     private CacheObjectContext cacheObjectContext(String cacheName) {
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/QueryUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/QueryUtils.java
index 6a2c22a..08d44bd 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/QueryUtils.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/QueryUtils.java
@@ -47,7 +47,7 @@
 import org.apache.ignite.internal.processors.cache.CacheDefaultBinaryAffinityKeyMapper;
 import org.apache.ignite.internal.processors.cache.CacheObjectContext;
 import org.apache.ignite.internal.processors.cache.DynamicCacheDescriptor;
-import org.apache.ignite.internal.processors.cache.GridCacheContext;
+import org.apache.ignite.internal.processors.cache.GridCacheContextInfo;
 import org.apache.ignite.internal.processors.cache.GridCacheDefaultAffinityKeyMapper;
 import org.apache.ignite.internal.processors.cache.binary.CacheObjectBinaryProcessorImpl;
 import org.apache.ignite.internal.processors.cache.query.IgniteQueryErrorCode;
@@ -397,17 +397,19 @@
      *
      * @param cacheName Cache name.
      * @param schemaName Schema name.
-     * @param cctx Cache context.
+     * @param cacheInfo Cache context info.
      * @param qryEntity Query entity.
      * @param mustDeserializeClss Classes which must be deserialized.
      * @param escape Escape flag.
      * @return Type candidate.
      * @throws IgniteCheckedException If failed.
      */
-    public static QueryTypeCandidate typeForQueryEntity(String cacheName, String schemaName, GridCacheContext cctx,
-        QueryEntity qryEntity, List<Class<?>> mustDeserializeClss, boolean escape) throws IgniteCheckedException {
-        GridKernalContext ctx = cctx.kernalContext();
-        CacheConfiguration<?,?> ccfg = cctx.config();
+    public static QueryTypeCandidate typeForQueryEntity(String cacheName, String schemaName,
+        GridCacheContextInfo cacheInfo,
+        QueryEntity qryEntity, List<Class<?>> mustDeserializeClss, boolean escape)
+        throws IgniteCheckedException {
+        GridKernalContext ctx = cacheInfo.context();
+        CacheConfiguration<?, ?> ccfg = cacheInfo.config();
 
         boolean binaryEnabled = ctx.cacheObjects().isBinaryEnabled(ccfg);
 
@@ -494,7 +496,7 @@
             // Need to setup affinity key for distributed joins.
             String keyType = qryEntity.getKeyType();
 
-            if (!cctx.customAffinityMapper() && keyType != null) {
+            if (!cacheInfo.customAffinityMapper() && keyType != null) {
                 if (coCtx != null) {
                     CacheDefaultBinaryAffinityKeyMapper mapper =
                         (CacheDefaultBinaryAffinityKeyMapper)coCtx.defaultAffMapper();
@@ -516,7 +518,7 @@
         else {
             processClassMeta(qryEntity, desc, coCtx);
 
-            AffinityKeyMapper keyMapper = cctx.config().getAffinityMapper();
+            AffinityKeyMapper keyMapper = cacheInfo.config().getAffinityMapper();
 
             if (keyMapper instanceof GridCacheDefaultAffinityKeyMapper) {
                 String affField =
@@ -619,14 +621,14 @@
 
     /**
      * Add validate property to QueryTypeDescriptor.
-     * 
+     *
      * @param ctx Kernel context.
      * @param qryEntity Query entity.
      * @param d Descriptor.
      * @param name Field name.
      * @throws IgniteCheckedException
      */
-    private static void addKeyValueValidationProperty(GridKernalContext ctx, QueryEntity qryEntity, QueryTypeDescriptorImpl d, 
+    private static void addKeyValueValidationProperty(GridKernalContext ctx, QueryEntity qryEntity, QueryTypeDescriptorImpl d,
         String name, boolean isKey) throws IgniteCheckedException {
 
         Map<String, Object> dfltVals = qryEntity.getDefaultFieldValues();
@@ -638,12 +640,12 @@
         Object dfltVal = dfltVals.get(name);
 
         QueryBinaryProperty prop = buildBinaryProperty(
-            ctx, 
+            ctx,
             name,
             U.classForName(typeName, Object.class, true),
-            d.aliases(), 
-            isKey, 
-            true, 
+            d.aliases(),
+            isKey,
+            true,
             dfltVal,
             precision == null ? -1 : precision.getOrDefault(name, -1),
             scale == null ? -1 : scale.getOrDefault(name, -1));
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/schema/SchemaIndexCacheVisitorImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/schema/SchemaIndexCacheVisitorImpl.java
index c037895..cb78ff6 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/schema/SchemaIndexCacheVisitorImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/schema/SchemaIndexCacheVisitorImpl.java
@@ -17,6 +17,7 @@
 
 package org.apache.ignite.internal.processors.query.schema;
 
+import java.util.List;
 import org.apache.ignite.IgniteCheckedException;
 import org.apache.ignite.internal.IgniteInterruptedCheckedException;
 import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion;
@@ -37,8 +38,6 @@
 import org.apache.ignite.internal.util.worker.GridWorker;
 import org.apache.ignite.thread.IgniteThread;
 
-import java.util.List;
-
 import static org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridDhtPartitionState.EVICTED;
 import static org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridDhtPartitionState.OWNING;
 import static org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridDhtPartitionState.RENTING;
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java
index 946378d..6da5c6e 100755
--- a/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java
@@ -55,6 +55,7 @@
 import org.apache.ignite.internal.compute.ComputeTaskTimeoutCheckedException;
 import org.apache.ignite.internal.events.DiscoveryCustomEvent;
 import org.apache.ignite.internal.managers.communication.GridIoManager;
+import org.apache.ignite.internal.managers.communication.GridIoPolicy;
 import org.apache.ignite.internal.managers.deployment.GridDeploymentInfo;
 import org.apache.ignite.internal.mxbean.IgniteStandardMXBean;
 import org.apache.ignite.internal.processors.cache.CacheClassLoaderMarker;
@@ -10604,6 +10605,71 @@
     }
 
     /**
+     * @param ctx Kernal context.
+     * @param plc IO Policy.
+     * @param reserved Thread to reserve.
+     * @return Number of available threads in executor service for {@code plc}. If {@code plc}
+     *         is invalid, return {@code 1}.
+     */
+    public static int availableThreadCount(GridKernalContext ctx, byte plc, int reserved) {
+        IgniteConfiguration cfg = ctx.config();
+
+        int parallelismLvl;
+
+        switch (plc) {
+            case GridIoPolicy.P2P_POOL:
+                parallelismLvl = cfg.getPeerClassLoadingThreadPoolSize();
+
+                break;
+
+            case GridIoPolicy.SYSTEM_POOL:
+                parallelismLvl = cfg.getSystemThreadPoolSize();
+
+                break;
+
+            case GridIoPolicy.PUBLIC_POOL:
+                parallelismLvl = cfg.getPublicThreadPoolSize();
+
+                break;
+
+            case GridIoPolicy.MANAGEMENT_POOL:
+                parallelismLvl = cfg.getManagementThreadPoolSize();
+
+                break;
+
+            case GridIoPolicy.UTILITY_CACHE_POOL:
+                parallelismLvl = cfg.getUtilityCacheThreadPoolSize();
+
+                break;
+
+            case GridIoPolicy.IGFS_POOL:
+                parallelismLvl = cfg.getIgfsThreadPoolSize();
+
+                break;
+
+            case GridIoPolicy.SERVICE_POOL:
+                parallelismLvl = cfg.getServiceThreadPoolSize();
+
+                break;
+
+            case GridIoPolicy.DATA_STREAMER_POOL:
+                parallelismLvl = cfg.getDataStreamerThreadPoolSize();
+
+                break;
+
+            case GridIoPolicy.QUERY_POOL:
+                parallelismLvl = cfg.getQueryThreadPoolSize();
+
+                break;
+
+            default:
+                parallelismLvl = -1;
+        }
+
+        return Math.max(1, parallelismLvl - reserved);
+    }
+
+    /**
      * Execute operation on data in parallel.
      *
      * @param executorSvc Service for parallel execution.
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/visor/node/VisorCacheRebalanceCollectorJobResult.java b/modules/core/src/main/java/org/apache/ignite/internal/visor/node/VisorCacheRebalanceCollectorJobResult.java
new file mode 100644
index 0000000..5bd818d
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/visor/node/VisorCacheRebalanceCollectorJobResult.java
@@ -0,0 +1,91 @@
+/*
+ * 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.node;
+
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import org.apache.ignite.internal.dto.IgniteDataTransferObject;
+import org.apache.ignite.internal.util.typedef.internal.S;
+import org.apache.ignite.internal.util.typedef.internal.U;
+
+/**
+ * Result object for cache rebalance job.
+ */
+public class VisorCacheRebalanceCollectorJobResult extends IgniteDataTransferObject {
+    /** */
+    private static final long serialVersionUID = 0L;
+
+    /** Rebalance percent. */
+    private double rebalance;
+
+    /** Node baseline state. */
+    private VisorNodeBaselineStatus baseline;
+
+    /**
+     * Default constructor.
+     */
+    public VisorCacheRebalanceCollectorJobResult() {
+        // No-op.
+    }
+
+    /**
+     * @return Rebalance progress.
+     */
+    public double getRebalance() {
+        return rebalance;
+    }
+
+    /**
+     * @param rebalance Rebalance progress.
+     */
+    public void setRebalance(double rebalance) {
+        this.rebalance = rebalance;
+    }
+
+    /**
+     * @return Node baseline status.
+     */
+    public VisorNodeBaselineStatus getBaseline() {
+        return baseline;
+    }
+
+    /**
+     * @param baseline Node baseline status.
+     */
+    public void setBaseline(VisorNodeBaselineStatus baseline) {
+        this.baseline = baseline;
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void writeExternalData(ObjectOutput out) throws IOException {
+        out.writeDouble(rebalance);
+        U.writeEnum(out, baseline);
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void readExternalData(byte protoVer, ObjectInput in) throws IOException, ClassNotFoundException {
+        rebalance = in.readDouble();
+        baseline = VisorNodeBaselineStatus.fromOrdinal(in.readByte());
+    }
+
+    /** {@inheritDoc} */
+    @Override public String toString() {
+        return S.toString(VisorCacheRebalanceCollectorJobResult.class, this);
+    }
+}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/visor/node/VisorCacheRebalanceCollectorTask.java b/modules/core/src/main/java/org/apache/ignite/internal/visor/node/VisorCacheRebalanceCollectorTask.java
new file mode 100644
index 0000000..eda9f94
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/visor/node/VisorCacheRebalanceCollectorTask.java
@@ -0,0 +1,194 @@
+/*
+ * 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.node;
+
+import java.util.Collection;
+import java.util.List;
+import org.apache.ignite.cache.CacheMetrics;
+import org.apache.ignite.cluster.BaselineNode;
+import org.apache.ignite.compute.ComputeJobResult;
+import org.apache.ignite.internal.cluster.IgniteClusterEx;
+import org.apache.ignite.internal.processors.cache.CacheGroupContext;
+import org.apache.ignite.internal.processors.cache.GridCacheAdapter;
+import org.apache.ignite.internal.processors.cache.GridCacheProcessor;
+import org.apache.ignite.internal.processors.cache.GridCacheUtils;
+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.VisorJob;
+import org.apache.ignite.internal.visor.VisorMultiNodeTask;
+import org.jetbrains.annotations.Nullable;
+
+import static org.apache.ignite.internal.visor.node.VisorNodeBaselineStatus.BASELINE_NOT_AVAILABLE;
+import static org.apache.ignite.internal.visor.node.VisorNodeBaselineStatus.NODE_IN_BASELINE;
+import static org.apache.ignite.internal.visor.node.VisorNodeBaselineStatus.NODE_NOT_IN_BASELINE;
+import static org.apache.ignite.internal.visor.util.VisorTaskUtils.MINIMAL_REBALANCE;
+import static org.apache.ignite.internal.visor.util.VisorTaskUtils.NOTHING_TO_REBALANCE;
+import static org.apache.ignite.internal.visor.util.VisorTaskUtils.REBALANCE_COMPLETE;
+import static org.apache.ignite.internal.visor.util.VisorTaskUtils.REBALANCE_NOT_AVAILABLE;
+import static org.apache.ignite.internal.visor.util.VisorTaskUtils.isProxyCache;
+import static org.apache.ignite.internal.visor.util.VisorTaskUtils.isRestartingCache;
+import static org.apache.ignite.internal.visor.util.VisorTaskUtils.log;
+
+/**
+ * Collects topology rebalance metrics.
+ */
+@GridInternal
+public class VisorCacheRebalanceCollectorTask extends VisorMultiNodeTask<VisorCacheRebalanceCollectorTaskArg,
+    VisorCacheRebalanceCollectorTaskResult, VisorCacheRebalanceCollectorJobResult> {
+    /** */
+    private static final long serialVersionUID = 0L;
+
+    /** {@inheritDoc} */
+    @Override protected VisorCacheRebalanceCollectorJob job(VisorCacheRebalanceCollectorTaskArg arg) {
+        return new VisorCacheRebalanceCollectorJob(arg, debug);
+    }
+
+    /** {@inheritDoc} */
+    @Nullable @Override protected VisorCacheRebalanceCollectorTaskResult reduce0(List<ComputeJobResult> results) {
+        return reduce(new VisorCacheRebalanceCollectorTaskResult(), results);
+    }
+
+    /**
+     * @param taskRes Task result.
+     * @param results Results.
+     * @return Topology rebalance metrics collector task result.
+     */
+    protected VisorCacheRebalanceCollectorTaskResult reduce(
+        VisorCacheRebalanceCollectorTaskResult taskRes,
+        List<ComputeJobResult> results
+    ) {
+        for (ComputeJobResult res : results) {
+            VisorCacheRebalanceCollectorJobResult jobRes = res.getData();
+
+            if (jobRes != null) {
+                if (res.getException() == null)
+                    taskRes.getRebalance().put(res.getNode().id(), jobRes.getRebalance());
+
+                taskRes.getBaseline().put(res.getNode().id(), jobRes.getBaseline());
+            }
+        }
+
+        return taskRes;
+    }
+
+    /**
+     * Job that collects rebalance metrics.
+     */
+    private static class VisorCacheRebalanceCollectorJob extends VisorJob<VisorCacheRebalanceCollectorTaskArg, VisorCacheRebalanceCollectorJobResult> {
+        /** */
+        private static final long serialVersionUID = 0L;
+
+        /**
+         * Create job with given argument.
+         *
+         * @param arg Job argument.
+         * @param debug Debug flag.
+         */
+        private VisorCacheRebalanceCollectorJob(VisorCacheRebalanceCollectorTaskArg arg, boolean debug) {
+            super(arg, debug);
+        }
+
+        /** {@inheritDoc} */
+        @Override protected VisorCacheRebalanceCollectorJobResult run(VisorCacheRebalanceCollectorTaskArg arg) {
+            VisorCacheRebalanceCollectorJobResult res = new VisorCacheRebalanceCollectorJobResult();
+
+            long start0 = U.currentTimeMillis();
+
+            try {
+                int partitions = 0;
+                double total = 0;
+                double ready = 0;
+
+                GridCacheProcessor cacheProc = ignite.context().cache();
+
+                boolean rebalanceInProgress = false;
+
+                for (CacheGroupContext grp: cacheProc.cacheGroups()) {
+                    String cacheName = grp.config().getName();
+
+                    if (isProxyCache(ignite, cacheName) || isRestartingCache(ignite, cacheName))
+                        continue;
+
+                    try {
+                        GridCacheAdapter ca = cacheProc.internalCache(cacheName);
+
+                        if (ca == null || !ca.context().started())
+                            continue;
+
+                        CacheMetrics cm = ca.localMetrics();
+
+                        partitions += cm.getTotalPartitionsCount();
+
+                        long keysTotal = cm.getEstimatedRebalancingKeys();
+                        long keysReady = cm.getRebalancedKeys();
+
+                        if (keysReady >= keysTotal)
+                            keysReady = Math.max(keysTotal - 1, 0);
+
+                        total += keysTotal;
+                        ready += keysReady;
+
+                        if (cm.getRebalancingPartitionsCount() > 0)
+                            rebalanceInProgress = true;
+                    }
+                    catch(IllegalStateException | IllegalArgumentException e) {
+                        if (debug && ignite.log() != null)
+                            ignite.log().error("Ignored cache group: " + grp.cacheOrGroupName(), e);
+                    }
+                }
+
+                if (partitions == 0)
+                    res.setRebalance(NOTHING_TO_REBALANCE);
+                else if (total == 0 && rebalanceInProgress)
+                    res.setRebalance(MINIMAL_REBALANCE);
+                else
+                    res.setRebalance(total > 0 ? Math.max(ready / total, MINIMAL_REBALANCE) : REBALANCE_COMPLETE);
+            }
+            catch (Exception e) {
+                res.setRebalance(REBALANCE_NOT_AVAILABLE);
+
+                ignite.log().error("Failed to collect rebalance metrics", e);
+            }
+
+            if (GridCacheUtils.isPersistenceEnabled(ignite.configuration())) {
+                IgniteClusterEx cluster = ignite.cluster();
+
+                Object consistentId = ignite.localNode().consistentId();
+
+                Collection<? extends BaselineNode> baseline = cluster.currentBaselineTopology();
+
+                boolean inBaseline = baseline.stream().anyMatch(n -> consistentId.equals(n.consistentId()));
+
+                res.setBaseline(inBaseline ? NODE_IN_BASELINE : NODE_NOT_IN_BASELINE);
+            }
+            else
+                res.setBaseline(BASELINE_NOT_AVAILABLE);
+
+            if (debug)
+                log(ignite.log(), "Collected rebalance metrics", getClass(), start0);
+
+            return res;
+        }
+
+        /** {@inheritDoc} */
+        @Override public String toString() {
+            return S.toString(VisorCacheRebalanceCollectorJob.class, this);
+        }
+    }
+}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/visor/node/VisorCacheRebalanceCollectorTaskArg.java b/modules/core/src/main/java/org/apache/ignite/internal/visor/node/VisorCacheRebalanceCollectorTaskArg.java
new file mode 100644
index 0000000..d97fd50
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/visor/node/VisorCacheRebalanceCollectorTaskArg.java
@@ -0,0 +1,54 @@
+/*
+ * 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.node;
+
+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;
+
+/**
+ * Argument for {@link VisorCacheRebalanceCollectorTask} task.
+ */
+public class VisorCacheRebalanceCollectorTaskArg extends VisorDataTransferObject {
+    /** */
+    private static final long serialVersionUID = 0L;
+
+    /**
+     * Default constructor.
+     */
+    public VisorCacheRebalanceCollectorTaskArg() {
+        // No-op.
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void writeExternalData(ObjectOutput out) throws IOException {
+        // No-op.
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void readExternalData(byte protoVer, ObjectInput in) throws IOException, ClassNotFoundException {
+        // No-op.
+    }
+
+    /** {@inheritDoc} */
+    @Override public String toString() {
+        return S.toString(VisorCacheRebalanceCollectorTaskArg.class, this);
+    }
+}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/visor/node/VisorCacheRebalanceCollectorTaskResult.java b/modules/core/src/main/java/org/apache/ignite/internal/visor/node/VisorCacheRebalanceCollectorTaskResult.java
new file mode 100644
index 0000000..1305cd2
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/visor/node/VisorCacheRebalanceCollectorTaskResult.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.visor.node;
+
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+import org.apache.ignite.internal.dto.IgniteDataTransferObject;
+import org.apache.ignite.internal.util.typedef.internal.S;
+import org.apache.ignite.internal.util.typedef.internal.U;
+
+/**
+ * Result object for {@link VisorCacheRebalanceCollectorTask} task.
+ */
+public class VisorCacheRebalanceCollectorTaskResult extends IgniteDataTransferObject {
+    /** */
+    private static final long serialVersionUID = 0L;
+
+    /** Rebalance state on nodes. */
+    private Map<UUID, Double> rebalance = new HashMap<>();
+
+    /** Nodes baseline status. */
+    private Map<UUID, VisorNodeBaselineStatus> baseline = new HashMap<>();
+
+    /**
+     * Default constructor.
+     */
+    public VisorCacheRebalanceCollectorTaskResult() {
+        // No-op.
+    }
+
+    /**
+     * @return Rebalance on nodes.
+     */
+    public Map<UUID, Double> getRebalance() {
+        return rebalance;
+    }
+
+    /**
+     * @return Baseline.
+     */
+    public Map<UUID, VisorNodeBaselineStatus> getBaseline() {
+        return baseline;
+    }
+
+    /**
+     * Add specified results.
+     *
+     * @param res Results to add.
+     */
+    public void add(VisorCacheRebalanceCollectorTaskResult res) {
+        assert res != null;
+
+        rebalance.putAll(res.getRebalance());
+        baseline.putAll(res.getBaseline());
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void writeExternalData(ObjectOutput out) throws IOException {
+        U.writeMap(out, rebalance);
+        U.writeMap(out, baseline);
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void readExternalData(byte protoVer, ObjectInput in) throws IOException, ClassNotFoundException {
+        rebalance = U.readMap(in);
+        baseline = U.readMap(in);
+    }
+
+    /** {@inheritDoc} */
+    @Override public String toString() {
+        return S.toString(VisorCacheRebalanceCollectorTaskResult.class, this);
+    }
+}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/visor/node/VisorNodeBaselineStatus.java b/modules/core/src/main/java/org/apache/ignite/internal/visor/node/VisorNodeBaselineStatus.java
new file mode 100644
index 0000000..ea90be3
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/visor/node/VisorNodeBaselineStatus.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.internal.visor.node;
+
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * Node baseline status.
+ */
+public enum VisorNodeBaselineStatus {
+    /** */
+    NODE_IN_BASELINE,
+    /** */
+    NODE_NOT_IN_BASELINE,
+    /** */
+    BASELINE_NOT_AVAILABLE;
+
+    /** Enumerated values. */
+    private static final VisorNodeBaselineStatus[] VALS = values();
+
+    /**
+     * 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 VisorNodeBaselineStatus fromOrdinal(int ord) {
+        return ord >= 0 && ord < VALS.length ? VALS[ord] : null;
+    }
+}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/visor/node/VisorNodeDataCollectorJob.java b/modules/core/src/main/java/org/apache/ignite/internal/visor/node/VisorNodeDataCollectorJob.java
index 9025ed0..9a7d2b1 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/visor/node/VisorNodeDataCollectorJob.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/visor/node/VisorNodeDataCollectorJob.java
@@ -28,8 +28,9 @@
 import org.apache.ignite.cluster.ClusterNode;
 import org.apache.ignite.configuration.FileSystemConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
-import org.apache.ignite.internal.managers.discovery.GridDiscoveryManager;
+import org.apache.ignite.internal.processors.cache.CacheGroupContext;
 import org.apache.ignite.internal.processors.cache.GridCacheAdapter;
+import org.apache.ignite.internal.processors.cache.GridCacheContext;
 import org.apache.ignite.internal.processors.cache.GridCachePartitionExchangeManager;
 import org.apache.ignite.internal.processors.cache.GridCacheProcessor;
 import org.apache.ignite.internal.processors.igfs.IgfsProcessorAdapter;
@@ -50,9 +51,15 @@
 import static org.apache.ignite.internal.processors.cache.GridCacheUtils.isSystemCache;
 import static org.apache.ignite.internal.visor.compute.VisorComputeMonitoringHolder.COMPUTE_MONITORING_HOLDER_KEY;
 import static org.apache.ignite.internal.visor.util.VisorTaskUtils.EVT_MAPPER;
+import static org.apache.ignite.internal.visor.util.VisorTaskUtils.MINIMAL_REBALANCE;
+import static org.apache.ignite.internal.visor.util.VisorTaskUtils.NOTHING_TO_REBALANCE;
+import static org.apache.ignite.internal.visor.util.VisorTaskUtils.REBALANCE_COMPLETE;
+import static org.apache.ignite.internal.visor.util.VisorTaskUtils.REBALANCE_NOT_AVAILABLE;
 import static org.apache.ignite.internal.visor.util.VisorTaskUtils.VISOR_TASK_EVTS;
 import static org.apache.ignite.internal.visor.util.VisorTaskUtils.checkExplicitTaskMonitoring;
 import static org.apache.ignite.internal.visor.util.VisorTaskUtils.collectEvents;
+import static org.apache.ignite.internal.visor.util.VisorTaskUtils.isProxyCache;
+import static org.apache.ignite.internal.visor.util.VisorTaskUtils.isRestartingCache;
 import static org.apache.ignite.internal.visor.util.VisorTaskUtils.log;
 
 /**
@@ -141,18 +148,6 @@
     }
 
     /**
-     * @param cacheName Cache name to check.
-     * @return {@code true} if cache on local node is not a data cache or near cache disabled.
-     */
-    private boolean proxyCache(String cacheName) {
-        GridDiscoveryManager discovery = ignite.context().discovery();
-
-        ClusterNode locNode = ignite.localNode();
-
-        return !(discovery.cacheAffinityNode(locNode, cacheName) || discovery.cacheNearNode(locNode, cacheName));
-    }
-
-    /**
      * Collect memory metrics.
      *
      * @param res Job result.
@@ -194,38 +189,51 @@
 
             List<VisorCache> resCaches = res.getCaches();
 
-            for (String cacheName : cacheProc.cacheNames()) {
-                if (proxyCache(cacheName))
-                    continue;
+            boolean rebalanceInProgress = false;
 
-                boolean sysCache = isSystemCache(cacheName);
+            for (CacheGroupContext grp : cacheProc.cacheGroups()) {
+                boolean first = true;
 
-                if (arg.getSystemCaches() || !(sysCache || isIgfsCache(cfg, cacheName))) {
+                for (GridCacheContext cache : grp.caches()) {
                     long start0 = U.currentTimeMillis();
 
+                    String cacheName = cache.name();
+
                     try {
+                        if (isProxyCache(ignite, cacheName) || isRestartingCache(ignite, cacheName))
+                            continue;
+
                         GridCacheAdapter ca = cacheProc.internalCache(cacheName);
 
                         if (ca == null || !ca.context().started())
                             continue;
 
-                        CacheMetrics cm = ca.localMetrics();
+                        if (first) {
+                            CacheMetrics cm = ca.localMetrics();
 
-                        partitions += cm.getTotalPartitionsCount();
+                            partitions += cm.getTotalPartitionsCount();
 
-                        long partTotal = cm.getEstimatedRebalancingKeys();
-                        long partReady = cm.getRebalancedKeys();
+                            long keysTotal = cm.getEstimatedRebalancingKeys();
+                            long keysReady = cm.getRebalancedKeys();
 
-                        if (partReady >= partTotal)
-                            partReady = Math.max(partTotal - 1, 0);
+                            if (keysReady >= keysTotal)
+                                keysReady = Math.max(keysTotal - 1, 0);
 
-                        total += partTotal;
-                        ready += partReady;
+                            total += keysTotal;
+                            ready += keysReady;
 
-                        if (all || cacheGrps.contains(ca.configuration().getGroupName()))
+                            if (!rebalanceInProgress && cm.getRebalancingPartitionsCount() > 0)
+                                rebalanceInProgress = true;
+
+                            first = false;
+                        }
+
+                        boolean addToRes = arg.getSystemCaches() || !(isSystemCache(cacheName) || isIgfsCache(cfg, cacheName));
+
+                        if (addToRes && (all || cacheGrps.contains(ca.configuration().getGroupName())))
                             resCaches.add(new VisorCache(ignite, ca, arg.isCollectCacheMetrics()));
                     }
-                    catch(IllegalStateException | IllegalArgumentException e) {
+                    catch (IllegalStateException | IllegalArgumentException e) {
                         if (debug && ignite.log() != null)
                             ignite.log().error("Ignored cache: " + cacheName, e);
                     }
@@ -237,11 +245,14 @@
             }
 
             if (partitions == 0)
-                res.setRebalance(-1);
+                res.setRebalance(NOTHING_TO_REBALANCE);
+            else if (total == 0 && rebalanceInProgress)
+                res.setRebalance(MINIMAL_REBALANCE);
             else
-                res.setRebalance(total > 0 ? ready / total : 1);
+                res.setRebalance(total > 0 ? Math.max(ready / total, MINIMAL_REBALANCE) : REBALANCE_COMPLETE);
         }
         catch (Exception e) {
+            res.setRebalance(REBALANCE_NOT_AVAILABLE);
             res.setCachesEx(new VisorExceptionWrapper(e));
         }
     }
@@ -260,7 +271,8 @@
 
                 FileSystemConfiguration igfsCfg = igfs.configuration();
 
-                if (proxyCache(igfsCfg.getDataCacheConfiguration().getName()) || proxyCache(igfsCfg.getMetaCacheConfiguration().getName()))
+                if (isProxyCache(ignite, igfsCfg.getDataCacheConfiguration().getName()) ||
+                    isProxyCache(ignite, igfsCfg.getMetaCacheConfiguration().getName()))
                     continue;
 
                 try {
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/visor/node/VisorNodeDataCollectorTaskResult.java b/modules/core/src/main/java/org/apache/ignite/internal/visor/node/VisorNodeDataCollectorTaskResult.java
index eb161f8..f8eb869 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/visor/node/VisorNodeDataCollectorTaskResult.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/visor/node/VisorNodeDataCollectorTaskResult.java
@@ -131,7 +131,8 @@
             readyTopVers.isEmpty() &&
             pendingExchanges.isEmpty() &&
             persistenceMetrics.isEmpty() &&
-            persistenceMetricsEx.isEmpty();
+            persistenceMetricsEx.isEmpty() &&
+            rebalance.isEmpty();
     }
 
     /**
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/visor/util/VisorTaskUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/visor/util/VisorTaskUtils.java
index fda9ba1..7ab1ffc 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/visor/util/VisorTaskUtils.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/visor/util/VisorTaskUtils.java
@@ -58,6 +58,10 @@
 import org.apache.ignite.cache.eviction.AbstractEvictionPolicyFactory;
 import org.apache.ignite.cluster.ClusterNode;
 import org.apache.ignite.events.Event;
+import org.apache.ignite.internal.IgniteEx;
+import org.apache.ignite.internal.managers.discovery.GridDiscoveryManager;
+import org.apache.ignite.internal.processors.cache.IgniteCacheProxy;
+import org.apache.ignite.internal.processors.cache.IgniteCacheProxyImpl;
 import org.apache.ignite.internal.processors.igfs.IgfsEx;
 import org.apache.ignite.internal.util.typedef.F;
 import org.apache.ignite.internal.util.typedef.X;
@@ -110,6 +114,19 @@
     public static final int LOG_FILES_COUNT_LIMIT = 5000;
 
     /** */
+    public static final int NOTHING_TO_REBALANCE = -1;
+
+    /** */
+    public static final int REBALANCE_NOT_AVAILABLE = -2;
+
+    /** */
+    public static final double MINIMAL_REBALANCE = 0.01;
+
+    /** */
+    public static final int REBALANCE_COMPLETE = 1;
+
+
+    /** */
     private static final int DFLT_BUFFER_SIZE = 4096;
 
     /** Only task event types that Visor should collect. */
@@ -1248,4 +1265,30 @@
 
         return Arrays.asList(addrs);
     }
+
+    /**
+     * @param ignite Ignite.
+     * @param cacheName Cache name to check.
+     * @return {@code true} if cache on local node is not a data cache or near cache disabled.
+     */
+    public static boolean isProxyCache(IgniteEx ignite, String cacheName) {
+        GridDiscoveryManager discovery = ignite.context().discovery();
+
+        ClusterNode locNode = ignite.localNode();
+
+        return !(discovery.cacheAffinityNode(locNode, cacheName) || discovery.cacheNearNode(locNode, cacheName));
+    }
+
+    /**
+     * Check whether cache restarting in progress.
+     *
+     * @param ignite Grid.
+     * @param cacheName Cache name to check.
+     * @return {@code true} when cache restarting in progress.
+     */
+    public static boolean isRestartingCache(IgniteEx ignite, String cacheName)  {
+        IgniteCacheProxy<Object, Object> proxy = ignite.context().cache().jcache(cacheName);
+
+        return proxy instanceof IgniteCacheProxyImpl && ((IgniteCacheProxyImpl) proxy).isRestarting();
+    }
 }
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/visor/verify/CacheFilterEnum.java b/modules/core/src/main/java/org/apache/ignite/internal/visor/verify/CacheFilterEnum.java
new file mode 100644
index 0000000..4e87d50
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/visor/verify/CacheFilterEnum.java
@@ -0,0 +1,52 @@
+/*
+ * 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.verify;
+
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * Represents a type of cache(s) that can be used for comparing update counters and checksums between primary and backup partitions.
+ * <br>
+ * @see org.apache.ignite.internal.processors.cache.verify.VerifyBackupPartitionsTaskV2
+ */
+public enum CacheFilterEnum {
+    /** All. */
+    ALL,
+
+    /** System. */
+    SYSTEM,
+
+    /** Persistent. */
+    PERSISTENT,
+
+    /** Not persistent. */
+    NOT_PERSISTENT;
+
+    /** Enumerated values. */
+    private static final CacheFilterEnum[] VALS = values();
+
+    /**
+     * Efficiently gets enumerated value from its ordinal.
+     *
+     * @param ord Ordinal value.
+     * @return Enumerated value or {@code null} if ordinal out of range.
+     */
+    public static @Nullable CacheFilterEnum fromOrdinal(int ord) {
+        return ord >= 0 && ord < VALS.length ? VALS[ord] : null;
+    }
+}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/visor/verify/VisorIdleVerifyDumpTaskArg.java b/modules/core/src/main/java/org/apache/ignite/internal/visor/verify/VisorIdleVerifyDumpTaskArg.java
index 6316c24..29dfb5b 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/visor/verify/VisorIdleVerifyDumpTaskArg.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/visor/verify/VisorIdleVerifyDumpTaskArg.java
@@ -22,6 +22,7 @@
 import java.io.ObjectOutput;
 import java.util.Set;
 import org.apache.ignite.internal.util.typedef.internal.S;
+import org.apache.ignite.internal.util.typedef.internal.U;
 
 /**
  * Arguments for {@link VisorIdleVerifyDumpTask}.
@@ -29,9 +30,13 @@
 public class VisorIdleVerifyDumpTaskArg extends VisorIdleVerifyTaskArg {
     /** */
     private static final long serialVersionUID = 0L;
+
     /** */
     private boolean skipZeros;
 
+    /** Cache kind. */
+    private CacheFilterEnum cacheFilterEnum;
+
     /**
      * Default constructor.
      */
@@ -41,10 +46,12 @@
     /**
      * @param caches Caches.
      * @param skipZeros Skip zeros partitions.
+     * @param cacheFilterEnum Cache kind.
      */
-    public VisorIdleVerifyDumpTaskArg(Set<String> caches, boolean skipZeros) {
+    public VisorIdleVerifyDumpTaskArg(Set<String> caches, boolean skipZeros, CacheFilterEnum cacheFilterEnum) {
         super(caches);
         this.skipZeros = skipZeros;
+        this.cacheFilterEnum = cacheFilterEnum;
     }
 
     /**
@@ -54,16 +61,37 @@
         return skipZeros;
     }
 
+    /**
+     * @return Kind fo cache.
+     */
+    public CacheFilterEnum getCacheFilterEnum() {
+        return cacheFilterEnum;
+    }
+
     /** {@inheritDoc} */
     @Override protected void writeExternalData(ObjectOutput out) throws IOException {
         super.writeExternalData(out);
+
         out.writeBoolean(skipZeros);
+
+        U.writeEnum(out, cacheFilterEnum);
     }
 
     /** {@inheritDoc} */
     @Override protected void readExternalData(byte protoVer, ObjectInput in) throws IOException, ClassNotFoundException {
         super.readExternalData(protoVer, in);
+
         skipZeros = in.readBoolean();
+
+        if (protoVer >= V2)
+            cacheFilterEnum = CacheFilterEnum.fromOrdinal(in.readByte());
+        else
+            cacheFilterEnum = CacheFilterEnum.ALL;
+    }
+
+    /** {@inheritDoc} */
+    @Override public byte getProtocolVersion() {
+        return V2;
     }
 
     /** {@inheritDoc} */
diff --git a/modules/core/src/main/java/org/apache/ignite/spi/discovery/DiscoveryDataBag.java b/modules/core/src/main/java/org/apache/ignite/spi/discovery/DiscoveryDataBag.java
index b8d8908..2b6bbca 100644
--- a/modules/core/src/main/java/org/apache/ignite/spi/discovery/DiscoveryDataBag.java
+++ b/modules/core/src/main/java/org/apache/ignite/spi/discovery/DiscoveryDataBag.java
@@ -23,6 +23,7 @@
 import java.util.Set;
 import java.util.UUID;
 import org.apache.ignite.internal.GridComponent;
+import org.apache.ignite.internal.util.typedef.internal.S;
 import org.jetbrains.annotations.Nullable;
 
 /**
@@ -312,4 +313,9 @@
     @Nullable public Map<Integer, Serializable> localNodeSpecificData() {
         return nodeSpecificData.get(DEFAULT_KEY);
     }
+
+    /** {@inheritDoc} */
+    @Override public String toString() {
+        return S.toString(DiscoveryDataBag.class, this);
+    }
 }
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 ce69e78..bab9ec0 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
@@ -261,6 +261,9 @@
     private final ConcurrentMap<InetSocketAddress, GridPingFutureAdapter<IgniteBiTuple<UUID, Boolean>>> pingMap =
         new ConcurrentHashMap<>();
 
+    /** Last listener future. */
+    private IgniteFuture<?> lastCustomEvtLsnrFut;
+
     /**
      * @param adapter Adapter.
      */
@@ -2157,6 +2160,20 @@
     }
 
     /**
+     * Wait for all the listeners from previous discovery message to be completed.
+     */
+    private void waitForLastCustomEventListenerFuture() {
+        if (lastCustomEvtLsnrFut != null) {
+            try {
+                lastCustomEvtLsnrFut.get();
+            }
+            finally {
+                lastCustomEvtLsnrFut = null;
+            }
+        }
+    }
+
+    /**
      * Discovery messages history used for client reconnect.
      */
     private class EnsuredMessageHistory {
@@ -4160,6 +4177,15 @@
         private void processNodeAddedMessage(TcpDiscoveryNodeAddedMessage msg) {
             assert msg != null;
 
+            blockingSectionBegin();
+
+            try {
+                waitForLastCustomEventListenerFuture();
+            }
+            finally {
+                blockingSectionEnd();
+            }
+
             TcpDiscoveryNode node = msg.node();
 
             assert node != null;
@@ -5606,8 +5632,19 @@
                     hist,
                     msgObj);
 
-                if (waitForNotification || msgObj.isMutable())
-                    fut.get();
+                if (waitForNotification || msgObj.isMutable()) {
+                    blockingSectionBegin();
+
+                    try {
+                        fut.get();
+                    }
+                    finally {
+                        blockingSectionEnd();
+                    }
+                }
+                else {
+                    lastCustomEvtLsnrFut = fut;
+                }
 
                 if (msgObj.isMutable()) {
                     try {
diff --git a/modules/core/src/test/java/org/apache/ignite/cache/store/CacheStoreListenerRWThroughDisabledTransactionalCacheTest.java b/modules/core/src/test/java/org/apache/ignite/cache/store/CacheStoreListenerRWThroughDisabledTransactionalCacheTest.java
index 45038154..faf30b7 100644
--- a/modules/core/src/test/java/org/apache/ignite/cache/store/CacheStoreListenerRWThroughDisabledTransactionalCacheTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/cache/store/CacheStoreListenerRWThroughDisabledTransactionalCacheTest.java
@@ -20,6 +20,7 @@
 import java.util.Random;
 import org.apache.ignite.IgniteCache;
 import org.apache.ignite.cache.CacheAtomicityMode;
+import org.apache.ignite.testframework.MvccFeatureChecker;
 import org.apache.ignite.transactions.Transaction;
 import org.apache.ignite.transactions.TransactionConcurrency;
 import org.apache.ignite.transactions.TransactionIsolation;
@@ -37,6 +38,13 @@
  */
 public class CacheStoreListenerRWThroughDisabledTransactionalCacheTest extends CacheStoreSessionListenerReadWriteThroughDisabledAbstractTest {
     /** {@inheritDoc} */
+    @Override public void setUp() throws Exception {
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.CACHE_STORE);
+
+        super.setUp();
+    }
+
+    /** {@inheritDoc} */
     @Override protected CacheAtomicityMode atomicityMode() {
         return TRANSACTIONAL;
     }
diff --git a/modules/core/src/test/java/org/apache/ignite/cache/store/CacheStoreSessionListenerLifecycleSelfTest.java b/modules/core/src/test/java/org/apache/ignite/cache/store/CacheStoreSessionListenerLifecycleSelfTest.java
index ff176c5..9bc3cdc 100644
--- a/modules/core/src/test/java/org/apache/ignite/cache/store/CacheStoreSessionListenerLifecycleSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/cache/store/CacheStoreSessionListenerLifecycleSelfTest.java
@@ -34,6 +34,7 @@
 import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
 import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder;
 import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
+import org.apache.ignite.testframework.MvccFeatureChecker;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
 import org.apache.ignite.transactions.Transaction;
 
@@ -50,6 +51,13 @@
     private static final Queue<String> evts = new ConcurrentLinkedDeque<>();
 
     /** {@inheritDoc} */
+    @Override public void setUp() throws Exception {
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.CACHE_STORE);
+
+        super.setUp();
+    }
+
+    /** {@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/cache/store/CacheStoreSessionListenerWriteBehindEnabledTest.java b/modules/core/src/test/java/org/apache/ignite/cache/store/CacheStoreSessionListenerWriteBehindEnabledTest.java
index 9314dbb..3ba4ec2 100644
--- a/modules/core/src/test/java/org/apache/ignite/cache/store/CacheStoreSessionListenerWriteBehindEnabledTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/cache/store/CacheStoreSessionListenerWriteBehindEnabledTest.java
@@ -44,6 +44,7 @@
 import org.apache.ignite.internal.processors.cache.store.GridCacheWriteBehindStore;
 import org.apache.ignite.resources.CacheStoreSessionResource;
 import org.apache.ignite.testframework.GridTestUtils;
+import org.apache.ignite.testframework.MvccFeatureChecker;
 
 /**
  * This class tests that calls of {@link CacheStoreSessionListener#onSessionStart(CacheStoreSession)}
@@ -67,6 +68,13 @@
     private static final AtomicInteger uninitializedListenerCnt = new AtomicInteger();
 
     /** {@inheritDoc} */
+    @Override public void setUp() throws Exception {
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.CACHE_STORE);
+
+        super.setUp();
+    }
+
+    /** {@inheritDoc} */
     @Override protected int gridCount() {
         return 1;
     }
diff --git a/modules/core/src/test/java/org/apache/ignite/cache/store/jdbc/CacheJdbcStoreSessionListenerSelfTest.java b/modules/core/src/test/java/org/apache/ignite/cache/store/jdbc/CacheJdbcStoreSessionListenerSelfTest.java
index 237cfeb..968dc08 100644
--- a/modules/core/src/test/java/org/apache/ignite/cache/store/jdbc/CacheJdbcStoreSessionListenerSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/cache/store/jdbc/CacheJdbcStoreSessionListenerSelfTest.java
@@ -32,6 +32,7 @@
 import org.apache.ignite.cache.store.CacheStoreSessionListenerAbstractSelfTest;
 import org.apache.ignite.lang.IgniteBiInClosure;
 import org.apache.ignite.resources.CacheStoreSessionResource;
+import org.apache.ignite.testframework.MvccFeatureChecker;
 import org.h2.jdbcx.JdbcConnectionPool;
 
 /**
@@ -39,6 +40,13 @@
  */
 public class CacheJdbcStoreSessionListenerSelfTest extends CacheStoreSessionListenerAbstractSelfTest {
     /** {@inheritDoc} */
+    @Override public void setUp() throws Exception {
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.CACHE_STORE);
+
+        super.setUp();
+    }
+
+    /** {@inheritDoc} */
     @Override protected Factory<? extends CacheStore<Integer, Integer>> storeFactory() {
         return new Factory<CacheStore<Integer, Integer>>() {
             @Override public CacheStore<Integer, Integer> create() {
diff --git a/modules/core/src/test/java/org/apache/ignite/igfs/IgfsFragmentizerTopologySelfTest.java b/modules/core/src/test/java/org/apache/ignite/igfs/IgfsFragmentizerTopologySelfTest.java
index 9cc5006..de97d2b 100644
--- a/modules/core/src/test/java/org/apache/ignite/igfs/IgfsFragmentizerTopologySelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/igfs/IgfsFragmentizerTopologySelfTest.java
@@ -18,11 +18,18 @@
 package org.apache.ignite.igfs;
 
 import org.apache.ignite.IgniteFileSystem;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 
 /**
  * Tests coordinator transfer from one node to other.
  */
 public class IgfsFragmentizerTopologySelfTest extends IgfsFragmentizerAbstractSelfTest {
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * @throws Exception If failed.
      */
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/GridFailFastNodeFailureDetectionSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/GridFailFastNodeFailureDetectionSelfTest.java
index 79dc81a..5d9b255 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/GridFailFastNodeFailureDetectionSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/GridFailFastNodeFailureDetectionSelfTest.java
@@ -22,6 +22,8 @@
 import org.apache.ignite.Ignite;
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.events.Event;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.util.typedef.internal.U;
 import org.apache.ignite.lang.IgnitePredicate;
 import org.apache.ignite.messaging.MessagingListenActor;
@@ -66,6 +68,11 @@
         stopAllGrids();
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * @throws Exception If failed.
      */
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/GridFailoverCustomTopologySelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/GridFailoverCustomTopologySelfTest.java
index 86bca80..6b733fb 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/GridFailoverCustomTopologySelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/GridFailoverCustomTopologySelfTest.java
@@ -34,6 +34,8 @@
 import org.apache.ignite.compute.ComputeTaskAdapter;
 import org.apache.ignite.compute.ComputeTaskFuture;
 import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.resources.IgniteInstanceResource;
 import org.apache.ignite.resources.LoggerResource;
 import org.apache.ignite.spi.failover.FailoverContext;
@@ -75,6 +77,11 @@
 
         return cfg;
     }
+
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
     /**
      * Tests that failover don't pick local node if it has been excluded from topology.
      *
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/GridFailoverSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/GridFailoverSelfTest.java
index 5ed2245..257db75 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/GridFailoverSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/GridFailoverSelfTest.java
@@ -35,6 +35,8 @@
 import org.apache.ignite.compute.ComputeTaskSessionFullSupport;
 import org.apache.ignite.compute.ComputeUserUndeclaredException;
 import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.resources.IgniteInstanceResource;
 import org.apache.ignite.resources.TaskSessionResource;
 import org.apache.ignite.spi.failover.always.AlwaysFailoverSpi;
@@ -63,6 +65,11 @@
         return cfg;
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * @throws Exception If failed.
      */
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/GridFailoverTaskWithPredicateSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/GridFailoverTaskWithPredicateSelfTest.java
index 84f31cb..797d48f 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/GridFailoverTaskWithPredicateSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/GridFailoverTaskWithPredicateSelfTest.java
@@ -37,6 +37,8 @@
 import org.apache.ignite.compute.ComputeTaskSessionFullSupport;
 import org.apache.ignite.compute.ComputeUserUndeclaredException;
 import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.lang.IgnitePredicate;
 import org.apache.ignite.resources.TaskSessionResource;
 import org.apache.ignite.spi.failover.FailoverContext;
@@ -92,6 +94,11 @@
         return cfg;
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * Tests that failover doesn't happen on two-node grid when the Task is applicable only for the first node
      * and fails on it.
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/GridFailoverTopologySelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/GridFailoverTopologySelfTest.java
index dd78768..5515fe2 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/GridFailoverTopologySelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/GridFailoverTopologySelfTest.java
@@ -32,6 +32,8 @@
 import org.apache.ignite.compute.ComputeJobResultPolicy;
 import org.apache.ignite.compute.ComputeTask;
 import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.resources.IgniteInstanceResource;
 import org.apache.ignite.spi.failover.FailoverContext;
 import org.apache.ignite.spi.failover.always.AlwaysFailoverSpi;
@@ -87,6 +89,11 @@
         return cfg;
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * Tests that failover don't pick local node if it has been excluded from topology.
      *
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/GridTaskFailoverSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/GridTaskFailoverSelfTest.java
index bc0af82..6e446a0 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/GridTaskFailoverSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/GridTaskFailoverSelfTest.java
@@ -29,6 +29,8 @@
 import org.apache.ignite.compute.ComputeJobResultPolicy;
 import org.apache.ignite.compute.ComputeTaskFuture;
 import org.apache.ignite.compute.ComputeTaskSplitAdapter;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.resources.LoggerResource;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
 import org.apache.ignite.testframework.junits.common.GridCommonTest;
@@ -71,6 +73,11 @@
         }
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /** */
     @SuppressWarnings({"PublicInnerClass"})
     public static class GridFailoverTestTask extends ComputeTaskSplitAdapter<Serializable, Integer> {
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/IgniteClientReconnectAbstractTest.java b/modules/core/src/test/java/org/apache/ignite/internal/IgniteClientReconnectAbstractTest.java
index 0d89da2..ff6efe1 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/IgniteClientReconnectAbstractTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/IgniteClientReconnectAbstractTest.java
@@ -38,6 +38,8 @@
 import org.apache.ignite.cluster.ClusterNode;
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.events.Event;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.managers.communication.GridIoMessage;
 import org.apache.ignite.internal.managers.discovery.IgniteDiscoverySpi;
 import org.apache.ignite.internal.util.typedef.G;
@@ -100,6 +102,11 @@
         return cfg;
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * @param latch Latch.
      * @throws Exception If failed.
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/IgniteClientReconnectApiExceptionTest.java b/modules/core/src/test/java/org/apache/ignite/internal/IgniteClientReconnectApiExceptionTest.java
index 8f68a1f..f77bf12 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/IgniteClientReconnectApiExceptionTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/IgniteClientReconnectApiExceptionTest.java
@@ -63,7 +63,6 @@
  *
  */
 public class IgniteClientReconnectApiExceptionTest extends IgniteClientReconnectAbstractTest {
-
     /** Cache key for test put and invoke operation after reconnect */
     private static final int CACHE_PUT_INVOKE_KEY = 10010;
 
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/IgniteComputeTopologyExceptionTest.java b/modules/core/src/test/java/org/apache/ignite/internal/IgniteComputeTopologyExceptionTest.java
index a82373b..eeeaf91 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/IgniteComputeTopologyExceptionTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/IgniteComputeTopologyExceptionTest.java
@@ -22,6 +22,8 @@
 import org.apache.ignite.IgniteCompute;
 import org.apache.ignite.cluster.ClusterNode;
 import org.apache.ignite.cluster.ClusterTopologyException;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.cluster.ClusterTopologyCheckedException;
 import org.apache.ignite.internal.util.typedef.F;
 import org.apache.ignite.lang.IgniteCallable;
@@ -43,6 +45,11 @@
         stopAllGrids();
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * @throws Exception If failed.
      */
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/IgniteRoundRobinErrorAfterClientReconnectTest.java b/modules/core/src/test/java/org/apache/ignite/internal/IgniteRoundRobinErrorAfterClientReconnectTest.java
index 00a33a6..2b8bdea 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/IgniteRoundRobinErrorAfterClientReconnectTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/IgniteRoundRobinErrorAfterClientReconnectTest.java
@@ -21,6 +21,8 @@
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.events.Event;
 import org.apache.ignite.events.EventType;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.util.future.GridFutureAdapter;
 import org.apache.ignite.lang.IgniteClosure;
 import org.apache.ignite.lang.IgnitePredicate;
@@ -62,6 +64,11 @@
         return 60000;
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * @throws Exception If failed.
      */
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 bda24d1..e5ff639 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
@@ -38,6 +38,7 @@
 import static org.apache.ignite.internal.commandline.CommandHandler.VI_CHECK_THROUGH;
 import static org.apache.ignite.internal.commandline.CommandHandler.WAL_DELETE;
 import static org.apache.ignite.internal.commandline.CommandHandler.WAL_PRINT;
+import static org.junit.Assert.assertArrayEquals;
 
 /**
  * Tests Command Handler parsing arguments.
@@ -167,6 +168,44 @@
     }
 
     /**
+     * Tests parsing and validation for the SSL arguments.
+     */
+    public void testParseAndValidateSSLArguments() {
+        CommandHandler hnd = new CommandHandler();
+
+        for (Command cmd : Command.values()) {
+
+            if (cmd == Command.CACHE || cmd == Command.WAL)
+                continue; // --cache subcommand requires its own specific arguments.
+
+            try {
+                hnd.parseAndValidate(asList("--truststore"));
+
+                fail("expected exception: Expected truststore");
+            }
+            catch (IllegalArgumentException e) {
+                e.printStackTrace();
+            }
+
+            Arguments args = hnd.parseAndValidate(asList("--keystore", "testKeystore", "--keystore-password", "testKeystorePassword", "--keystore-type", "testKeystoreType",
+                "--truststore", "testTruststore", "--truststore-password", "testTruststorePassword", "--truststore-type", "testTruststoreType",
+                "--ssl-key-algorithm", "testSSLKeyAlgorithm", "--ssl-protocol", "testSSLProtocol", cmd.text()));
+
+            assertEquals("testSSLProtocol", args.sslProtocol());
+            assertEquals("testSSLKeyAlgorithm", args.sslKeyAlgorithm());
+            assertEquals("testKeystore", args.sslKeyStorePath());
+            assertArrayEquals("testKeystorePassword".toCharArray(), args.sslKeyStorePassword());
+            assertEquals("testKeystoreType", args.sslKeyStoreType());
+            assertEquals("testTruststore", args.sslTrustStorePath());
+            assertArrayEquals("testTruststorePassword".toCharArray(), args.sslTrustStorePassword());
+            assertEquals("testTruststoreType", args.sslTrustStoreType());
+
+            assertEquals(cmd, args.command());
+        }
+    }
+
+
+    /**
      * Tests parsing and validation for user and password arguments.
      */
     public void testParseAndValidateUserAndPassword() {
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/encryption/EncryptedCacheCreateTest.java b/modules/core/src/test/java/org/apache/ignite/internal/encryption/EncryptedCacheCreateTest.java
index 47d8d8f..d9958e4 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/encryption/EncryptedCacheCreateTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/encryption/EncryptedCacheCreateTest.java
@@ -96,8 +96,6 @@
 
     /** @throws Exception If failed. */
     public void testCreateEncryptedNotPersistedCacheFail() throws Exception {
-        fail("https://issues.apache.org/jira/browse/IGNITE-8640");
-
         GridTestUtils.assertThrowsWithCause(() -> {
             CacheConfiguration<Long, String> ccfg = new CacheConfiguration<>(NO_PERSISTENCE_REGION);
 
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/managers/deployment/DeploymentRequestOfUnknownClassProcessingTest.java b/modules/core/src/test/java/org/apache/ignite/internal/managers/deployment/DeploymentRequestOfUnknownClassProcessingTest.java
new file mode 100644
index 0000000..f1f080b
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/internal/managers/deployment/DeploymentRequestOfUnknownClassProcessingTest.java
@@ -0,0 +1,151 @@
+/*
+ * 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.managers.deployment;
+
+import java.net.URL;
+import java.util.UUID;
+import java.util.concurrent.TimeUnit;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.internal.IgniteEx;
+import org.apache.ignite.internal.managers.communication.GridIoPolicy;
+import org.apache.ignite.internal.managers.communication.GridMessageListener;
+import org.apache.ignite.internal.util.future.GridFutureAdapter;
+import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
+import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder;
+import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
+import org.apache.ignite.testframework.GridTestExternalClassLoader;
+import org.apache.ignite.testframework.ListeningTestLogger;
+import org.apache.ignite.testframework.LogListener;
+import org.apache.ignite.testframework.config.GridTestProperties;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+
+import static org.apache.ignite.internal.GridTopic.TOPIC_CLASSLOAD;
+
+/**
+ * Tests the processing of deployment request with an attempt to load a class with an unknown class name.
+ */
+public class DeploymentRequestOfUnknownClassProcessingTest extends GridCommonAbstractTest {
+    /** */
+    private static final TcpDiscoveryIpFinder IP_FINDER = new TcpDiscoveryVmIpFinder(true);
+
+    /** */
+    private static final String TEST_TOPIC_NAME = "TEST_TOPIC_NAME";
+
+    /** */
+    private static final String UNKNOWN_CLASS_NAME = "unknown.UnknownClassName";
+
+    /** */
+    private final ListeningTestLogger remNodeLog = new ListeningTestLogger(false, log);
+
+    /** {@inheritDoc} */
+    @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception {
+        IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName);
+
+        cfg.setPeerClassLoadingEnabled(true);
+
+        TcpDiscoverySpi discoSpi = new TcpDiscoverySpi();
+
+        discoSpi.setIpFinder(IP_FINDER);
+
+        cfg.setDiscoverySpi(discoSpi);
+
+        return cfg;
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void beforeTest() throws Exception {
+        super.beforeTest();
+
+        startGrid(getConfiguration(getTestIgniteInstanceName(0)));
+
+        IgniteConfiguration cfg = getConfiguration(getTestIgniteInstanceName(1));
+
+        cfg.setGridLogger(remNodeLog);
+
+        startGrid(cfg);
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void afterTest() throws Exception {
+        super.afterTest();
+
+        stopAllGrids();
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testResponseReceivingOnDeploymentRequestOfUnknownClass() throws Exception {
+        IgniteEx locNode = grid(0);
+        IgniteEx remNode = grid(1);
+
+        // Register deployment on remote node for attemt to load class on request receiving
+        GridTestExternalClassLoader ldr = new GridTestExternalClassLoader(new URL[] {
+            new URL(GridTestProperties.getProperty("p2p.uri.cls"))
+        });
+
+        Class task = ldr.loadClass("org.apache.ignite.tests.p2p.P2PTestTaskExternalPath1");
+
+        GridDeployment locDep = remNode.context().deploy().deploy(task, task.getClassLoader());
+
+        final GridFutureAdapter<Void> testResultFut = new GridFutureAdapter<>();
+
+        final LogListener remNodeLogLsnr = LogListener
+            .matches(s -> s.startsWith("Failed to resolve class: " + UNKNOWN_CLASS_NAME)).build();
+
+        remNodeLog.registerListener(remNodeLogLsnr);
+
+        locNode.context().io().addMessageListener(TEST_TOPIC_NAME, new GridMessageListener() {
+            @Override public void onMessage(UUID nodeId, Object msg, byte plc) {
+                try {
+                    assertTrue(msg instanceof GridDeploymentResponse);
+
+                    GridDeploymentResponse resp = (GridDeploymentResponse)msg;
+
+                    assertFalse("Unexpected response result, success=" + resp.success(), resp.success());
+
+                    String errMsg = resp.errorMessage();
+
+                    assertNotNull("Response should contain an error message.", errMsg);
+
+                    assertTrue("Response contains unexpected error message, errorMessage=" + errMsg,
+                        errMsg.startsWith("Requested resource not found (ignoring locally): " + UNKNOWN_CLASS_NAME));
+
+                    testResultFut.onDone();
+                }
+                catch (Error e) {
+                    testResultFut.onDone(e);
+                }
+            }
+        });
+
+        GridDeploymentRequest req = new GridDeploymentRequest(TEST_TOPIC_NAME, locDep.classLoaderId(),
+            UNKNOWN_CLASS_NAME, false);
+
+        req.responseTopicBytes(U.marshal(locNode.context(), req.responseTopic()));
+
+        locNode.context().io().sendToGridTopic(remNode.localNode(), TOPIC_CLASSLOAD, req, GridIoPolicy.P2P_POOL);
+
+        // Сhecks that the expected response has been received.
+        testResultFut.get(5_000, TimeUnit.MILLISECONDS);
+
+        // Checks that error has been logged on remote node.
+        assertTrue(remNodeLogLsnr.check());
+    }
+}
\ No newline at end of file
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/managers/discovery/GridDiscoveryManagerAliveCacheSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/managers/discovery/GridDiscoveryManagerAliveCacheSelfTest.java
index 8fad640..0c21325 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/managers/discovery/GridDiscoveryManagerAliveCacheSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/managers/discovery/GridDiscoveryManagerAliveCacheSelfTest.java
@@ -28,6 +28,8 @@
 import org.apache.ignite.configuration.NearCacheConfiguration;
 import org.apache.ignite.events.Event;
 import org.apache.ignite.events.EventType;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.util.typedef.F;
 import org.apache.ignite.internal.util.typedef.G;
 import org.apache.ignite.lang.IgnitePredicate;
@@ -133,6 +135,11 @@
         stopAllGrids();
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * @throws Exception If failed.
      */
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/managers/discovery/GridDiscoveryManagerAttributesSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/managers/discovery/GridDiscoveryManagerAttributesSelfTest.java
index d19ae72..762bc92 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/managers/discovery/GridDiscoveryManagerAttributesSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/managers/discovery/GridDiscoveryManagerAttributesSelfTest.java
@@ -21,6 +21,8 @@
 import org.apache.ignite.IgniteCheckedException;
 import org.apache.ignite.configuration.DeploymentMode;
 import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.IgniteEx;
 import org.apache.ignite.internal.binary.BinaryMarshaller;
 import org.apache.ignite.internal.marshaller.optimized.OptimizedMarshaller;
@@ -91,6 +93,11 @@
         stopAllGrids();
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * @throws Exception If failed.
      */
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/managers/discovery/IgniteTopologyPrintFormatSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/managers/discovery/IgniteTopologyPrintFormatSelfTest.java
index 4041d6e..a7f5d69 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/managers/discovery/IgniteTopologyPrintFormatSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/managers/discovery/IgniteTopologyPrintFormatSelfTest.java
@@ -21,6 +21,8 @@
 import java.util.List;
 import org.apache.ignite.Ignite;
 import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.IgniteKernal;
 import org.apache.ignite.internal.managers.GridManagerAdapter;
 import org.apache.ignite.internal.util.typedef.F;
@@ -83,6 +85,11 @@
             ((MockLogger)log).clear();
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * @throws Exception If failed.
      */
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/marshaller/optimized/OptimizedMarshallerNodeFailoverTest.java b/modules/core/src/test/java/org/apache/ignite/internal/marshaller/optimized/OptimizedMarshallerNodeFailoverTest.java
index 7bd0a5d..31751c3 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/marshaller/optimized/OptimizedMarshallerNodeFailoverTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/marshaller/optimized/OptimizedMarshallerNodeFailoverTest.java
@@ -26,6 +26,8 @@
 import org.apache.ignite.IgniteCache;
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.IgniteInternalFuture;
 import org.apache.ignite.internal.marshaller.optimized.OptimizedMarshaller;
 import org.apache.ignite.internal.util.typedef.internal.U;
@@ -81,6 +83,11 @@
         return cfg;
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * @throws Exception If failed.
      */
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/marshaller/optimized/OptimizedMarshallerTest.java b/modules/core/src/test/java/org/apache/ignite/internal/marshaller/optimized/OptimizedMarshallerTest.java
index 94c854f..c0997b1 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/marshaller/optimized/OptimizedMarshallerTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/marshaller/optimized/OptimizedMarshallerTest.java
@@ -149,7 +149,7 @@
         assertFalse(ipFinder.isShared());
     }
 
-     /**
+    /**
      * Tests ability to marshal non-serializable objects.
      *
      * @throws IgniteCheckedException If marshalling failed.
@@ -168,7 +168,7 @@
         assertTrue(bean.isFlag());
     }
 
-     /**
+    /**
      * Tests ability to marshal non-serializable objects.
      *
      * @throws IgniteCheckedException If marshalling failed.
@@ -850,4 +850,4 @@
             terminalId = U.readString(in);
         }
     }
-}
\ No newline at end of file
+}
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/GridCacheTxLoadFromStoreOnLockSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/GridCacheTxLoadFromStoreOnLockSelfTest.java
index 6293723..a1f18a7 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/GridCacheTxLoadFromStoreOnLockSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/GridCacheTxLoadFromStoreOnLockSelfTest.java
@@ -33,6 +33,7 @@
 import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
 import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder;
 import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
+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;
@@ -46,6 +47,13 @@
     private static final TcpDiscoveryIpFinder IP_FINDER = new TcpDiscoveryVmIpFinder(true);
 
     /** {@inheritDoc} */
+    @Override public void setUp() throws Exception {
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.CACHE_STORE);
+
+        super.setUp();
+    }
+
+    /** {@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/CacheClientStoreSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheClientStoreSelfTest.java
index 8703791..ecf9d2e 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheClientStoreSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheClientStoreSelfTest.java
@@ -40,6 +40,7 @@
 import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
 import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder;
 import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
+import org.apache.ignite.testframework.MvccFeatureChecker;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
 
 import static org.apache.ignite.IgniteSystemProperties.IGNITE_SKIP_CONFIGURATION_CONSISTENCY_CHECK;
@@ -67,6 +68,13 @@
     private static volatile boolean loadedFromClient;
 
     /** {@inheritDoc} */
+    @Override public void setUp() throws Exception {
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.CACHE_STORE);
+
+        super.setUp();
+    }
+
+    /** {@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/CacheConnectionLeakStoreTxTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheConnectionLeakStoreTxTest.java
index 27dbe62..db08d53 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheConnectionLeakStoreTxTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheConnectionLeakStoreTxTest.java
@@ -170,6 +170,26 @@
     }
 
     /**
+     * @throws Exception If failed.
+     */
+    public void testConnectionLeakOneBackupMvccPessimisticRepeatableRead() throws Exception {
+        fail("https://issues.apache.org/jira/browse/IGNITE-8582");
+
+        checkConnectionLeak(CacheAtomicityMode.TRANSACTIONAL_SNAPSHOT, PESSIMISTIC, REPEATABLE_READ);
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testConnectionLeakOneBackupMvccPessimisticRepeatableReadLoadFromStore() throws Exception {
+        fail("https://issues.apache.org/jira/browse/IGNITE-8582");
+
+        isLoadFromStore = true;
+
+        checkConnectionLeak(CacheAtomicityMode.TRANSACTIONAL_SNAPSHOT, PESSIMISTIC, REPEATABLE_READ);
+    }
+
+    /**
      * @param atomicityMode Atomicity mode.
      * @param txConcurrency Transaction concurrency.
      * @param txIsolation Transaction isolation.
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheDataRegionConfigurationTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheDataRegionConfigurationTest.java
index 614c900..94fbbc6 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheDataRegionConfigurationTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheDataRegionConfigurationTest.java
@@ -24,6 +24,8 @@
 import org.apache.ignite.configuration.DataRegionConfiguration;
 import org.apache.ignite.configuration.DataStorageConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.IgniteEx;
 import org.apache.ignite.internal.mem.IgniteOutOfMemoryException;
 import org.apache.ignite.testframework.GridTestUtils;
@@ -64,6 +66,11 @@
         stopAllGrids();
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /** */
     private void checkStartGridException(Class<? extends Throwable> ex, String message) {
         GridTestUtils.assertThrows(log(), new Callable<Object>() {
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CashEventWithTxLabelTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheEventWithTxLabelTest.java
similarity index 97%
rename from modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CashEventWithTxLabelTest.java
rename to modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheEventWithTxLabelTest.java
index da25288..dabf0db 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CashEventWithTxLabelTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheEventWithTxLabelTest.java
@@ -38,6 +38,7 @@
 import org.apache.ignite.internal.IgniteKernal;
 import org.apache.ignite.internal.util.lang.IgnitePair;
 import org.apache.ignite.lang.IgnitePredicate;
+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;
@@ -52,7 +53,7 @@
  * Test to check passing transaction's label for EVT_CACHE_OBJECT_READ, EVT_CACHE_OBJECT_PUT,
  * EVT_CACHE_OBJECT_REMOVED events.
  */
-public class CashEventWithTxLabelTest extends GridCommonAbstractTest {
+public class CacheEventWithTxLabelTest extends GridCommonAbstractTest {
     /** Types event to be checked. */
     private static final int[] CACHE_EVENT_TYPES = {EVT_CACHE_OBJECT_READ, EVT_CACHE_OBJECT_PUT, EVT_CACHE_OBJECT_REMOVED};
 
@@ -105,6 +106,9 @@
 
     /** {@inheritDoc} */
     @Override protected void beforeTestsStarted() throws Exception {
+        if (MvccFeatureChecker.forcedMvcc())
+            fail("https://issues.apache.org/jira/browse/IGNITE-10270");
+
         super.beforeTestsStarted();
 
         client = false;
@@ -148,6 +152,9 @@
                 for (TransactionConcurrency concurrency : TransactionConcurrency.values()) {
                     this.concurrency = concurrency;
 
+                    if (MvccFeatureChecker.forcedMvcc() && !MvccFeatureChecker.isSupported(concurrency, isolation))
+                        continue;
+
                     for (int i = 0; i < nodes.length - 1; i++) {
                         Ignite nodeForPut = nodes[i];
                         Ignite nodeForGet = nodes[i + 1];
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheGetEntryAbstractTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheGetEntryAbstractTest.java
index f347525..3e7b791 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheGetEntryAbstractTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheGetEntryAbstractTest.java
@@ -170,8 +170,6 @@
      * @throws Exception If failed.
      */
     public void testLocalTransactional() throws Exception {
-        // TODO: fails since d13520e9a05bd9e9b987529472d6317951b72f96, need to review changes.
-
         CacheConfiguration cfg = new CacheConfiguration(DEFAULT_CACHE_NAME);
 
         cfg.setWriteSynchronizationMode(FULL_SYNC);
@@ -214,7 +212,7 @@
      * @param cfg Cache configuration.
      * @throws Exception If failed.
      */
-    private void test(CacheConfiguration cfg) throws Exception {
+    protected void test(CacheConfiguration cfg) throws Exception {
         test(cfg, true);
 
         test(cfg, false);
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheGetEntryOptimisticReadCommittedSeltTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheGetEntryOptimisticReadCommittedSelfTest.java
similarity index 95%
rename from modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheGetEntryOptimisticReadCommittedSeltTest.java
rename to modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheGetEntryOptimisticReadCommittedSelfTest.java
index c04612d..0927546 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheGetEntryOptimisticReadCommittedSeltTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheGetEntryOptimisticReadCommittedSelfTest.java
@@ -23,7 +23,7 @@
 /**
  * Test getEntry and getEntries methods.
  */
-public class CacheGetEntryOptimisticReadCommittedSeltTest extends CacheGetEntryAbstractTest {
+public class CacheGetEntryOptimisticReadCommittedSelfTest extends CacheGetEntryAbstractTest {
     /** {@inheritDoc} */
     @Override protected TransactionConcurrency concurrency() {
         return TransactionConcurrency.OPTIMISTIC;
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheGetEntryOptimisticRepeatableReadSeltTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheGetEntryOptimisticRepeatableReadSelfTest.java
similarity index 95%
rename from modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheGetEntryOptimisticRepeatableReadSeltTest.java
rename to modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheGetEntryOptimisticRepeatableReadSelfTest.java
index 6153869..2c6a204 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheGetEntryOptimisticRepeatableReadSeltTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheGetEntryOptimisticRepeatableReadSelfTest.java
@@ -23,7 +23,7 @@
 /**
  * Test getEntry and getEntries methods.
  */
-public class CacheGetEntryOptimisticRepeatableReadSeltTest extends CacheGetEntryAbstractTest {
+public class CacheGetEntryOptimisticRepeatableReadSelfTest extends CacheGetEntryAbstractTest {
     /** {@inheritDoc} */
     @Override protected TransactionConcurrency concurrency() {
         return TransactionConcurrency.OPTIMISTIC;
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheGetEntryOptimisticSerializableSeltTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheGetEntryOptimisticSerializableSelfTest.java
similarity index 95%
rename from modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheGetEntryOptimisticSerializableSeltTest.java
rename to modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheGetEntryOptimisticSerializableSelfTest.java
index 6ded4a9..63161e2 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheGetEntryOptimisticSerializableSeltTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheGetEntryOptimisticSerializableSelfTest.java
@@ -23,7 +23,7 @@
 /**
  * Test getEntry and getEntries methods.
  */
-public class CacheGetEntryOptimisticSerializableSeltTest extends CacheGetEntryAbstractTest {
+public class CacheGetEntryOptimisticSerializableSelfTest extends CacheGetEntryAbstractTest {
     /** {@inheritDoc} */
     @Override protected TransactionConcurrency concurrency() {
         return TransactionConcurrency.OPTIMISTIC;
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheGetEntryPessimisticReadCommittedSeltTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheGetEntryPessimisticReadCommittedSelfTest.java
similarity index 95%
rename from modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheGetEntryPessimisticReadCommittedSeltTest.java
rename to modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheGetEntryPessimisticReadCommittedSelfTest.java
index 975d271..0a291f7 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheGetEntryPessimisticReadCommittedSeltTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheGetEntryPessimisticReadCommittedSelfTest.java
@@ -23,7 +23,7 @@
 /**
  * Test getEntry and getEntries methods.
  */
-public class CacheGetEntryPessimisticReadCommittedSeltTest extends CacheGetEntryAbstractTest {
+public class CacheGetEntryPessimisticReadCommittedSelfTest extends CacheGetEntryAbstractTest {
     /** {@inheritDoc} */
     @Override protected TransactionConcurrency concurrency() {
         return TransactionConcurrency.PESSIMISTIC;
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheGetEntryPessimisticRepeatableReadSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheGetEntryPessimisticRepeatableReadSelfTest.java
new file mode 100644
index 0000000..906b726
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheGetEntryPessimisticRepeatableReadSelfTest.java
@@ -0,0 +1,105 @@
+/*
+ * 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.cache;
+
+import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.configuration.NearCacheConfiguration;
+import org.apache.ignite.transactions.TransactionConcurrency;
+import org.apache.ignite.transactions.TransactionIsolation;
+
+import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL_SNAPSHOT;
+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.CacheWriteSynchronizationMode.FULL_SYNC;
+
+/**
+ * Test getEntry and getEntries methods.
+ */
+public class CacheGetEntryPessimisticRepeatableReadSelfTest extends CacheGetEntryAbstractTest {
+    /** {@inheritDoc} */
+    @Override protected TransactionConcurrency concurrency() {
+        return TransactionConcurrency.PESSIMISTIC;
+    }
+
+    /** {@inheritDoc} */
+    @Override protected TransactionIsolation isolation() {
+        return TransactionIsolation.REPEATABLE_READ;
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testNearTransactionalMvcc() throws Exception {
+        fail("https://issues.apache.org/jira/browse/IGNITE-7187");
+
+        CacheConfiguration cfg = new CacheConfiguration(DEFAULT_CACHE_NAME);
+
+        cfg.setWriteSynchronizationMode(FULL_SYNC);
+        cfg.setCacheMode(PARTITIONED);
+        cfg.setAtomicityMode(TRANSACTIONAL_SNAPSHOT);
+        cfg.setName("nearT");
+        cfg.setNearConfiguration(new NearCacheConfiguration());
+
+        test(cfg);
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testPartitionedTransactionalMvcc() throws Exception {
+        CacheConfiguration cfg = new CacheConfiguration(DEFAULT_CACHE_NAME);
+
+        cfg.setWriteSynchronizationMode(FULL_SYNC);
+        cfg.setCacheMode(PARTITIONED);
+        cfg.setAtomicityMode(TRANSACTIONAL_SNAPSHOT);
+        cfg.setName("partitionedT");
+
+        test(cfg);
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testLocalTransactionalMvcc() throws Exception {
+        fail("https://issues.apache.org/jira/browse/IGNITE-9530");
+
+        CacheConfiguration cfg = new CacheConfiguration(DEFAULT_CACHE_NAME);
+
+        cfg.setWriteSynchronizationMode(FULL_SYNC);
+        cfg.setCacheMode(LOCAL);
+        cfg.setAtomicityMode(TRANSACTIONAL_SNAPSHOT);
+        cfg.setName("localT");
+
+        test(cfg);
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testReplicatedTransactionalMvcc() throws Exception {
+        CacheConfiguration cfg = new CacheConfiguration(DEFAULT_CACHE_NAME);
+
+        cfg.setWriteSynchronizationMode(FULL_SYNC);
+        cfg.setCacheMode(REPLICATED);
+        cfg.setAtomicityMode(TRANSACTIONAL_SNAPSHOT);
+        cfg.setName("replicatedT");
+
+        test(cfg);
+    }
+}
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheGetEntryPessimisticRepeatableReadSeltTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheGetEntryPessimisticRepeatableReadSeltTest.java
deleted file mode 100644
index 4aa693c..0000000
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheGetEntryPessimisticRepeatableReadSeltTest.java
+++ /dev/null
@@ -1,40 +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.cache;
-
-import org.apache.ignite.transactions.TransactionConcurrency;
-import org.apache.ignite.transactions.TransactionIsolation;
-
-/**
- * Test getEntry and getEntries methods.
- */
-public class CacheGetEntryPessimisticRepeatableReadSeltTest extends CacheGetEntryAbstractTest {
-    /** {@inheritDoc} */
-    @Override protected TransactionConcurrency concurrency() {
-        return TransactionConcurrency.PESSIMISTIC;
-    }
-
-    /** {@inheritDoc} */
-    @Override protected TransactionIsolation isolation() {
-        return TransactionIsolation.REPEATABLE_READ;
-    }
-
-    @Override public void testReplicatedTransactional() throws Exception {
-        super.testReplicatedTransactional();
-    }
-}
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheGetEntryPessimisticSerializableSeltTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheGetEntryPessimisticSerializableSelfTest.java
similarity index 95%
rename from modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheGetEntryPessimisticSerializableSeltTest.java
rename to modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheGetEntryPessimisticSerializableSelfTest.java
index 70f71ce..dfaed7e 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheGetEntryPessimisticSerializableSeltTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheGetEntryPessimisticSerializableSelfTest.java
@@ -23,7 +23,7 @@
 /**
  * Test getEntry and getEntries methods.
  */
-public class CacheGetEntryPessimisticSerializableSeltTest extends CacheGetEntryAbstractTest {
+public class CacheGetEntryPessimisticSerializableSelfTest extends CacheGetEntryAbstractTest {
     /** {@inheritDoc} */
     @Override protected TransactionConcurrency concurrency() {
         return TransactionConcurrency.PESSIMISTIC;
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheGetsDistributionAbstractTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheGetsDistributionAbstractTest.java
new file mode 100644
index 0000000..559a719
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheGetsDistributionAbstractTest.java
@@ -0,0 +1,375 @@
+/*
+ * 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.cache;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.UUID;
+import org.apache.ignite.Ignite;
+import org.apache.ignite.IgniteCache;
+import org.apache.ignite.cache.CacheAtomicityMode;
+import org.apache.ignite.cache.CacheMode;
+import org.apache.ignite.cluster.ClusterNode;
+import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.configuration.TransactionConfiguration;
+import org.apache.ignite.internal.IgniteEx;
+import org.apache.ignite.internal.util.lang.GridAbsPredicate;
+import org.apache.ignite.internal.util.typedef.G;
+import org.apache.ignite.spi.discovery.tcp.internal.TcpDiscoveryNode;
+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.TransactionConcurrency;
+import org.apache.ignite.transactions.TransactionIsolation;
+
+import static org.apache.ignite.cache.CacheWriteSynchronizationMode.FULL_SYNC;
+import static org.apache.ignite.internal.IgniteNodeAttributes.ATTR_MACS;
+import static org.apache.ignite.transactions.TransactionConcurrency.PESSIMISTIC;
+import static org.apache.ignite.transactions.TransactionIsolation.REPEATABLE_READ;
+
+/**
+ * Tests of replicated cache's 'get' requests distribution.
+ */
+public abstract class CacheGetsDistributionAbstractTest extends GridCommonAbstractTest {
+    /** Client nodes instance's name. */
+    private static final String CLIENT_NAME = "client";
+
+    /** Value prefix. */
+    private static final String VAL_PREFIX = "val";
+
+    /** */
+    private static final int PRIMARY_KEYS_NUMBER = 1_000;
+
+    /** {@inheritDoc} */
+    @Override protected void beforeTestsStarted() throws Exception {
+        super.beforeTestsStarted();
+
+        assert gridCount() >= 1 : "At least one grid must be started";
+
+        startGridsMultiThreaded(gridCount());
+
+        IgniteConfiguration clientCfg = getConfiguration(CLIENT_NAME);
+
+        clientCfg.setClientMode(true);
+
+        startGrid(clientCfg);
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void afterTestsStopped() throws Exception {
+        stopAllGrids();
+
+        super.afterTestsStopped();
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void beforeTest() throws Exception {
+        super.beforeTest();
+
+        IgniteCache cache = ignite(0).cache(DEFAULT_CACHE_NAME);
+
+        if (cache != null)
+            cache.destroy();
+
+        // Setting different MAC addresses for all nodes
+        Map<UUID, String> macs = getClusterMacs();
+
+        int idx = 0;
+
+        for (Map.Entry<UUID, String> entry : macs.entrySet())
+            entry.setValue("x2-xx-xx-xx-xx-x" + idx++);
+
+        replaceMacAddresses(G.allGrids(), macs);
+    }
+
+    /** {@inheritDoc} */
+    @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception {
+        IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName);
+
+        TransactionConfiguration txCfg = new TransactionConfiguration()
+            .setDefaultTxIsolation(transactionIsolation())
+            .setDefaultTxConcurrency(transactionConcurrency());
+
+        cfg.setTransactionConfiguration(txCfg);
+
+        return cfg;
+    }
+
+    /**
+     * @return Grids count to start.
+     */
+    protected int gridCount() {
+        return 4;
+    }
+
+    /**
+     * @return Cache configuration.
+     */
+    protected <K, V> CacheConfiguration<K, V> cacheConfiguration() {
+        CacheConfiguration<K, V> ccfg = defaultCacheConfiguration();
+
+        ccfg.setCacheMode(cacheMode());
+        ccfg.setAtomicityMode(atomicityMode());
+        ccfg.setWriteSynchronizationMode(FULL_SYNC);
+        ccfg.setReadFromBackup(true);
+        ccfg.setStatisticsEnabled(true);
+
+        if (cacheMode() == CacheMode.PARTITIONED)
+            ccfg.setBackups(backupsCount());
+
+        return ccfg;
+    }
+
+    /**
+     * @return Cache mode.
+     */
+    protected abstract CacheMode cacheMode();
+
+    /**
+     * @return Cache atomicity mode.
+     */
+    protected abstract CacheAtomicityMode atomicityMode();
+
+    /**
+     * @return Cache transaction isolation.
+     */
+    protected TransactionIsolation transactionIsolation() {
+        return REPEATABLE_READ;
+    }
+
+    /**
+     * @return Cache transaction concurrency.
+     */
+    protected TransactionConcurrency transactionConcurrency() {
+        return PESSIMISTIC;
+    }
+
+    /**
+     * @return Backups count.
+     */
+    protected int backupsCount() {
+        return gridCount() - 1;
+    }
+
+    /**
+     * Test 'get' operations requests generator distribution.
+     *
+     * @throws Exception In case of an error.
+     * @see #runTestBalancingDistribution(boolean)
+     */
+    public void testGetRequestsGeneratorDistribution() throws Exception {
+        runTestBalancingDistribution(false);
+    }
+
+    /**
+     * Test 'getAll' operations requests generator distribution.
+     *
+     * @throws Exception In case of an error.
+     * @see #runTestBalancingDistribution(boolean)
+     */
+    public void testGetAllRequestsGeneratorDistribution() throws Exception {
+        runTestBalancingDistribution(true);
+    }
+
+    /**
+     * @param batchMode Whenever 'get' or 'getAll' operations are used in the test.
+     * @throws Exception In case of an error.
+     */
+    protected void runTestBalancingDistribution(boolean batchMode) throws Exception {
+        IgniteCache<Integer, String> cache = grid(0).createCache(cacheConfiguration());
+
+        List<Integer> keys = primaryKeys(cache, PRIMARY_KEYS_NUMBER);
+
+        for (Integer key : keys)
+            cache.put(key, VAL_PREFIX + key);
+
+        IgniteCache<Integer, String> clientCache = grid(CLIENT_NAME).cache(DEFAULT_CACHE_NAME)
+            .withAllowAtomicOpsInTx();
+
+        assertTrue(GridTestUtils.waitForCondition(
+            new GridAbsPredicate() {
+                int batchSize = 10;
+                int idx = 0;
+
+                @Override public boolean apply() {
+                    if (idx >= PRIMARY_KEYS_NUMBER)
+                        idx = 0;
+
+                    try (Transaction tx = grid(CLIENT_NAME).transactions().txStart()) {
+                        if (batchMode) {
+                            Set<Integer> keys0 = new TreeSet<>();
+
+                            for (int i = idx; i < idx + batchSize && i < PRIMARY_KEYS_NUMBER; i++)
+                                keys0.add(keys.get(i));
+
+                            idx += batchSize;
+
+                            Map<Integer, String> results = clientCache.getAll(keys0);
+
+                            for (Map.Entry<Integer, String> entry : results.entrySet())
+                                assertEquals(VAL_PREFIX + entry.getKey(), entry.getValue());
+                        }
+                        else {
+                            for (int i = idx; i < idx + gridCount() && i < PRIMARY_KEYS_NUMBER; i++) {
+                                Integer key = keys.get(i);
+
+                                assertEquals(VAL_PREFIX + key, clientCache.get(key));
+                            }
+
+                            idx += gridCount();
+                        }
+
+                        tx.commit();
+                    }
+
+                    for (int i = 0; i < gridCount(); i++) {
+                        IgniteEx ignite = grid(i);
+
+                        long getsCnt = ignite.cache(DEFAULT_CACHE_NAME).localMetrics().getCacheGets();
+
+                        if (getsCnt == 0)
+                            return false;
+                    }
+
+                    return true;
+                }
+            },
+            getTestTimeout())
+        );
+    }
+
+    /**
+     * Tests that the 'get' operation requests are routed to node with same MAC address as at requester.
+     *
+     * @throws Exception In case of an error.
+     * @see #runTestSameHostDistribution(UUID, boolean)
+     */
+    public void testGetRequestsDistribution() throws Exception {
+        UUID destId = grid(0).localNode().id();
+
+        runTestSameHostDistribution(destId, false);
+    }
+
+    /**
+     * Tests that the 'getAll' operation requests are routed to node with same MAC address as at requester.
+     *
+     * @throws Exception In case of an error.
+     * @see #runTestSameHostDistribution(UUID, boolean)
+     */
+    public void testGetAllRequestsDistribution() throws Exception {
+        UUID destId = grid(gridCount() - 1).localNode().id();
+
+        runTestSameHostDistribution(destId, true);
+    }
+
+    /**
+     * Tests that the 'get' and 'getAll' requests are routed to node with same MAC address as at requester.
+     *
+     * @param destId Destination Ignite instance id for requests distribution.
+     * @param batchMode Test mode.
+     * @throws Exception In case of an error.
+     */
+    protected void runTestSameHostDistribution(final UUID destId, final boolean batchMode) throws Exception {
+        Map<UUID, String> macs = getClusterMacs();
+
+        String clientMac = macs.get(grid(CLIENT_NAME).localNode().id());
+
+        macs.put(destId, clientMac);
+
+        replaceMacAddresses(G.allGrids(), macs);
+
+        IgniteCache<Integer, String> cache = grid(0).createCache(cacheConfiguration());
+
+        List<Integer> keys = primaryKeys(cache, PRIMARY_KEYS_NUMBER);
+
+        for (Integer key : keys)
+            cache.put(key, VAL_PREFIX + key);
+
+        IgniteCache<Integer, String> clientCache = grid(CLIENT_NAME).cache(DEFAULT_CACHE_NAME)
+            .withAllowAtomicOpsInTx();
+
+        try (Transaction tx = grid(CLIENT_NAME).transactions().txStart()) {
+            if (batchMode) {
+                Map<Integer, String> results = clientCache.getAll(new TreeSet<>(keys));
+
+                for (Map.Entry<Integer, String> entry : results.entrySet())
+                    assertEquals(VAL_PREFIX + entry.getKey(), entry.getValue());
+            }
+            else {
+                for (Integer key : keys)
+                    assertEquals(VAL_PREFIX + key, clientCache.get(key));
+            }
+
+            tx.commit();
+        }
+
+        for (int i = 0; i < gridCount(); i++) {
+            IgniteEx ignite = grid(i);
+
+            long getsCnt = ignite.cache(DEFAULT_CACHE_NAME).localMetrics().getCacheGets();
+
+            if (destId.equals(ignite.localNode().id()))
+                assertEquals(PRIMARY_KEYS_NUMBER, getsCnt);
+            else
+                assertEquals(0L, getsCnt);
+        }
+    }
+
+    /**
+     * @param instances Started Ignite instances.
+     * @param macs Mapping MAC addresses to UUID.
+     */
+    private void replaceMacAddresses(List<Ignite> instances, Map<UUID, String> macs) {
+        for (Ignite ignite : instances) {
+            for (ClusterNode node : ignite.cluster().nodes()) {
+                String mac = macs.get(node.id());
+
+                assertNotNull(mac);
+
+                Map<String, Object> attrs = new HashMap<>(node.attributes());
+
+                attrs.put(ATTR_MACS, mac);
+
+                ((TcpDiscoveryNode)node).setAttributes(attrs);
+            }
+        }
+    }
+
+    /**
+     * @return Cluster nodes MAC addresses.
+     */
+    private Map<UUID, String> getClusterMacs() {
+        Map<UUID, String> macs = new HashMap<>();
+
+        for (Ignite ignite : G.allGrids()) {
+            ClusterNode node = ignite.cluster().localNode();
+
+            String mac = node.attribute(ATTR_MACS);
+
+            assert mac != null;
+
+            macs.put(node.id(), mac);
+        }
+
+        return macs;
+    }
+}
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheGroupMetricsMBeanTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheGroupMetricsMBeanTest.java
index f8108eb..3cd730f 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheGroupMetricsMBeanTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheGroupMetricsMBeanTest.java
@@ -34,6 +34,7 @@
 import org.apache.ignite.Ignite;
 import org.apache.ignite.IgniteCache;
 import org.apache.ignite.IgniteDataStreamer;
+import org.apache.ignite.cache.CacheAtomicityMode;
 import org.apache.ignite.cache.CacheMode;
 import org.apache.ignite.cache.affinity.AffinityFunction;
 import org.apache.ignite.cache.affinity.AffinityFunctionContext;
@@ -132,21 +133,25 @@
             .setGroupName("group1")
             .setCacheMode(CacheMode.PARTITIONED)
             .setBackups(3)
-            .setAffinity(new RoundRobinVariableSizeAffinityFunction());
+            .setAffinity(new RoundRobinVariableSizeAffinityFunction())
+            .setAtomicityMode(atomicityMode());
 
         CacheConfiguration cCfg2 = new CacheConfiguration()
             .setName("cache2")
             .setGroupName("group2")
-            .setCacheMode(CacheMode.REPLICATED);
+            .setCacheMode(CacheMode.REPLICATED)
+            .setAtomicityMode(atomicityMode());
 
         CacheConfiguration cCfg3 = new CacheConfiguration()
             .setName("cache3")
             .setGroupName("group2")
-            .setCacheMode(CacheMode.REPLICATED);
+            .setCacheMode(CacheMode.REPLICATED)
+            .setAtomicityMode(atomicityMode());
 
         CacheConfiguration cCfg4 = new CacheConfiguration()
             .setName("cache4")
-            .setCacheMode(CacheMode.PARTITIONED);
+            .setCacheMode(CacheMode.PARTITIONED)
+            .setAtomicityMode(atomicityMode());
 
         cfg.setCacheConfiguration(cCfg1, cCfg2, cCfg3, cCfg4);
 
@@ -163,6 +168,13 @@
         return cfg;
     }
 
+    /**
+     * @return Cache atomicity mode.
+     */
+    protected CacheAtomicityMode atomicityMode() {
+        return CacheAtomicityMode.ATOMIC;
+    }
+
     /** {@inheritDoc} */
     @Override protected void afterTest() throws Exception {
         stopAllGrids();
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheInterceptorPartitionCounterLocalSanityTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheInterceptorPartitionCounterLocalSanityTest.java
index acb929b..3be51e9 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheInterceptorPartitionCounterLocalSanityTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheInterceptorPartitionCounterLocalSanityTest.java
@@ -52,6 +52,7 @@
 import static java.util.concurrent.TimeUnit.SECONDS;
 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.LOCAL;
 import static org.apache.ignite.transactions.TransactionIsolation.READ_COMMITTED;
 import static org.apache.ignite.transactions.TransactionIsolation.REPEATABLE_READ;
@@ -138,6 +139,28 @@
     }
 
     /**
+     * @throws Exception If failed.
+     */
+    public void testLocalMvccTx() throws Exception {
+        fail("https://issues.apache.org/jira/browse/IGNITE-9530");
+
+        CacheConfiguration<Object, Object> ccfg = cacheConfiguration(TRANSACTIONAL_SNAPSHOT,false);
+
+        doTestPartitionCounterOperation(ccfg);
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testLocalMvccTxWithStore() throws Exception {
+        fail("https://issues.apache.org/jira/browse/IGNITE-9530");
+
+        CacheConfiguration<Object, Object> ccfg = cacheConfiguration(TRANSACTIONAL_SNAPSHOT,true);
+
+        doTestPartitionCounterOperation(ccfg);
+    }
+
+    /**
      * @param ccfg Cache configuration.
      * @throws Exception If failed.
      */
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheInterceptorPartitionCounterRandomOperationsTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheInterceptorPartitionCounterRandomOperationsTest.java
index 74170a6..385091a 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheInterceptorPartitionCounterRandomOperationsTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheInterceptorPartitionCounterRandomOperationsTest.java
@@ -62,6 +62,7 @@
 import static java.util.concurrent.TimeUnit.SECONDS;
 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;
@@ -291,11 +292,110 @@
     }
 
     /**
+     * @throws Exception If failed.
+     */
+    public void testMvccTx() throws Exception {
+        CacheConfiguration<Object, Object> ccfg = cacheConfiguration(PARTITIONED,
+            1,
+            TRANSACTIONAL_SNAPSHOT,
+            false);
+
+        doTestPartitionCounterOperation(ccfg);
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testMvccTxWithStore() throws Exception {
+        CacheConfiguration<Object, Object> ccfg = cacheConfiguration(PARTITIONED,
+            1,
+            TRANSACTIONAL_SNAPSHOT,
+            true);
+
+        doTestPartitionCounterOperation(ccfg);
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testMvccTxExplicit() throws Exception {
+        CacheConfiguration<Object, Object> ccfg = cacheConfiguration(PARTITIONED,
+            1,
+            TRANSACTIONAL_SNAPSHOT,
+            false);
+
+        doTestPartitionCounterOperation(ccfg);
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testMvccTxReplicated() throws Exception {
+        CacheConfiguration<Object, Object> ccfg = cacheConfiguration(REPLICATED,
+            0,
+            TRANSACTIONAL_SNAPSHOT,
+            false);
+
+        doTestPartitionCounterOperation(ccfg);
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testMvccTxReplicatedWithStore() throws Exception {
+        CacheConfiguration<Object, Object> ccfg = cacheConfiguration(REPLICATED,
+            0,
+            TRANSACTIONAL_SNAPSHOT,
+            true);
+
+        doTestPartitionCounterOperation(ccfg);
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testMvccTxNoBackups() throws Exception {
+        CacheConfiguration<Object, Object> ccfg = cacheConfiguration(PARTITIONED,
+            0,
+            TRANSACTIONAL_SNAPSHOT,
+            false);
+
+        doTestPartitionCounterOperation(ccfg);
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testMvccTxNoBackupsWithStore() throws Exception {
+        CacheConfiguration<Object, Object> ccfg = cacheConfiguration(PARTITIONED,
+            0,
+            TRANSACTIONAL_SNAPSHOT,
+            true);
+
+        doTestPartitionCounterOperation(ccfg);
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testMvccTxNoBackupsExplicit() throws Exception {
+        CacheConfiguration<Object, Object> ccfg = cacheConfiguration(PARTITIONED,
+            0,
+            TRANSACTIONAL_SNAPSHOT,
+            false);
+
+        doTestPartitionCounterOperation(ccfg);
+    }
+
+    /**
      * @param ccfg Cache configuration.
      * @throws Exception If failed.
      */
     protected void doTestPartitionCounterOperation(CacheConfiguration<Object, Object> ccfg)
         throws Exception {
+        if (ccfg.getAtomicityMode() == TRANSACTIONAL_SNAPSHOT)
+            fail("https://issues.apache.org/jira/browse/IGNITE-9323");
+
         ignite(0).createCache(ccfg);
 
         try {
@@ -345,7 +445,9 @@
 
         Transaction tx = null;
 
-        if (cache.getConfiguration(CacheConfiguration.class).getAtomicityMode() == TRANSACTIONAL && rnd.nextBoolean())
+        CacheAtomicityMode atomicityMode = cache.getConfiguration(CacheConfiguration.class).getAtomicityMode();
+
+        if (atomicityMode == TRANSACTIONAL && rnd.nextBoolean())
             tx = ignite.transactions().txStart(txRandomConcurrency(rnd), txRandomIsolation(rnd));
 
         try {
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheKeepBinaryTransactionTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheKeepBinaryTransactionTest.java
index 841e49c..43e0578 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheKeepBinaryTransactionTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheKeepBinaryTransactionTest.java
@@ -26,6 +26,7 @@
 import org.apache.ignite.configuration.TransactionConfiguration;
 import org.apache.ignite.internal.IgniteEx;
 import org.apache.ignite.internal.binary.BinaryMarshaller;
+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;
@@ -40,8 +41,11 @@
         IgniteConfiguration cfg = super.getConfiguration(gridName);
 
         TransactionConfiguration txCfg = new TransactionConfiguration();
-        txCfg.setDefaultTxConcurrency(TransactionConcurrency.OPTIMISTIC);
-        txCfg.setDefaultTxIsolation(TransactionIsolation.REPEATABLE_READ);
+
+        if (!MvccFeatureChecker.forcedMvcc()) {
+            txCfg.setDefaultTxConcurrency(TransactionConcurrency.OPTIMISTIC);
+            txCfg.setDefaultTxIsolation(TransactionIsolation.REPEATABLE_READ);
+        }
 
         cfg.setTransactionConfiguration(txCfg);
 
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheMetricsForClusterGroupSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheMetricsForClusterGroupSelfTest.java
index 3f196a5..df60c42 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheMetricsForClusterGroupSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheMetricsForClusterGroupSelfTest.java
@@ -21,6 +21,7 @@
 import java.util.Map;
 import java.util.concurrent.CountDownLatch;
 import org.apache.ignite.IgniteCache;
+import org.apache.ignite.IgniteSystemProperties;
 import org.apache.ignite.cache.CacheMetrics;
 import org.apache.ignite.cluster.ClusterNode;
 import org.apache.ignite.configuration.CacheConfiguration;
@@ -71,22 +72,15 @@
         return cfg;
     }
 
-    /** {@inheritDoc} */
-    @Override protected void beforeTestsStarted() throws Exception {
-        startGrids(GRID_CNT);
-
-        daemon = true;
-
-        startGrid(GRID_CNT);
-    }
-
     /**
      * Test cluster group metrics in case of statistics enabled.
      */
     public void testMetricsStatisticsEnabled() throws Exception {
-        createCaches(true);
+        startGrids();
 
         try {
+            createCaches(true);
+
             populateCacheData(cache1, ENTRY_CNT_CACHE1);
             populateCacheData(cache2, ENTRY_CNT_CACHE2);
 
@@ -107,7 +101,7 @@
             assertMetrics(cache2, true);
         }
         finally {
-            destroyCaches();
+            stopAllGrids();
         }
     }
 
@@ -117,9 +111,11 @@
      * @throws Exception If failed.
      */
     public void testMetricsStatisticsDisabled() throws Exception {
-        createCaches(false);
+        startGrids();
 
         try {
+            createCaches(false);
+
             populateCacheData(cache1, ENTRY_CNT_CACHE1);
             populateCacheData(cache2, ENTRY_CNT_CACHE2);
 
@@ -140,11 +136,62 @@
             assertMetrics(cache2, false);
         }
         finally {
-            destroyCaches();
+            stopAllGrids();
         }
     }
 
     /**
+     * Tests that only local metrics are updating if discovery updates disabled.
+     */
+    public void testMetricsDiscoveryUpdatesDisabled() throws Exception {
+        System.setProperty(IgniteSystemProperties.IGNITE_DISCOVERY_DISABLE_CACHE_METRICS_UPDATE, "true");
+
+        try {
+            startGrids();
+
+            try {
+                createCaches(true);
+
+                populateCacheData(cache1, ENTRY_CNT_CACHE1);
+                populateCacheData(cache2, ENTRY_CNT_CACHE2);
+
+                readCacheData(cache1, ENTRY_CNT_CACHE1);
+                readCacheData(cache2, ENTRY_CNT_CACHE2);
+
+                awaitMetricsUpdate();
+
+                Collection<ClusterNode> nodes = grid(0).cluster().forRemotes().nodes();
+
+                for (ClusterNode node : nodes) {
+                    Map<Integer, CacheMetrics> metrics = ((IgniteClusterNode)node).cacheMetrics();
+                    assertNotNull(metrics);
+                    assertTrue(metrics.isEmpty());
+                }
+
+                assertOnlyLocalMetricsUpdating(CACHE1);
+                assertOnlyLocalMetricsUpdating(CACHE2);
+            }
+            finally {
+                stopAllGrids();
+            }
+        }
+        finally {
+            System.setProperty(IgniteSystemProperties.IGNITE_DISCOVERY_DISABLE_CACHE_METRICS_UPDATE, "false");
+        }
+    }
+
+    /**
+     * Start grids.
+     */
+    private void startGrids() throws Exception {
+        startGrids(GRID_CNT);
+
+        daemon = true;
+
+        startGrid(GRID_CNT);
+    }
+
+    /**
      * @param statisticsEnabled Statistics enabled.
      */
     private void createCaches(boolean statisticsEnabled) {
@@ -268,6 +315,34 @@
     }
 
     /**
+     * Asserts that only local metrics are updating.
+     *
+     * @param cacheName Cache name.
+     */
+    private void assertOnlyLocalMetricsUpdating(String cacheName) {
+        for (int i = 0; i < GRID_CNT; i++) {
+            IgniteCache cache = grid(i).cache(cacheName);
+
+            CacheMetrics clusterMetrics = cache.metrics(grid(i).cluster().forCacheNodes(cacheName));
+            CacheMetrics locMetrics = cache.localMetrics();
+
+            assertEquals(clusterMetrics.name(), locMetrics.name());
+
+            assertEquals(0L, clusterMetrics.getCacheGets());
+            assertEquals(0L, cache.mxBean().getCacheGets());
+            assertEquals(locMetrics.getCacheGets(), cache.localMxBean().getCacheGets());
+
+            assertEquals(0L, clusterMetrics.getCachePuts());
+            assertEquals(0L, cache.mxBean().getCachePuts());
+            assertEquals(locMetrics.getCachePuts(), cache.localMxBean().getCachePuts());
+
+            assertEquals(0L, clusterMetrics.getCacheHits());
+            assertEquals(0L, cache.mxBean().getCacheHits());
+            assertEquals(locMetrics.getCacheHits(), cache.localMxBean().getCacheHits());
+        }
+    }
+
+    /**
      * @param ms Milliseconds.
      * @param f Function.
      * @param expectNonZero Check if each value is non-zero.
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheMetricsManageTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheMetricsManageTest.java
index ae00ac9..94830be 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheMetricsManageTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheMetricsManageTest.java
@@ -52,6 +52,7 @@
 import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder;
 import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
 import org.apache.ignite.testframework.GridTestUtils;
+import org.apache.ignite.testframework.MvccFeatureChecker;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
 
 /**
@@ -80,6 +81,9 @@
      * @throws Exception If failed.
      */
     public void testJmxNoPdsStatisticsEnable() throws Exception {
+        if (MvccFeatureChecker.forcedMvcc())
+            fail("https://issues.apache.org/jira/browse/IGNITE-9224");
+
         testJmxStatisticsEnable(false);
     }
 
@@ -87,6 +91,9 @@
      * @throws Exception If failed.
      */
     public void testJmxPdsStatisticsEnable() throws Exception {
+        if (MvccFeatureChecker.forcedMvcc())
+            fail("https://issues.apache.org/jira/browse/IGNITE-10421");
+
         testJmxStatisticsEnable(true);
     }
 
@@ -101,7 +108,7 @@
             .setName(CACHE1)
             .setGroupName(GROUP)
             .setCacheMode(CacheMode.PARTITIONED)
-            .setAtomicityMode(CacheAtomicityMode.ATOMIC);
+            .setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL);
 
         mgr1.createCache(CACHE1, cfg1);
 
@@ -490,7 +497,7 @@
             .setName(CACHE1)
             .setGroupName(GROUP)
             .setCacheMode(CacheMode.PARTITIONED)
-            .setAtomicityMode(CacheAtomicityMode.ATOMIC)
+            .setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL)
             .setWriteSynchronizationMode(CacheWriteSynchronizationMode.FULL_SYNC);
 
         cfg.setCacheConfiguration(cacheCfg);
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheNearReaderUpdateTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheNearReaderUpdateTest.java
index 96167f5..e47ebb3 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheNearReaderUpdateTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheNearReaderUpdateTest.java
@@ -43,6 +43,7 @@
 import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder;
 import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
 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;
@@ -91,6 +92,8 @@
 
     /** {@inheritDoc} */
     @Override protected void beforeTestsStarted() throws Exception {
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.NEAR_CACHE);
+
         super.beforeTestsStarted();
 
         startGridsMultiThreaded(SRVS);
@@ -336,6 +339,9 @@
         int backups,
         boolean storeEnabled,
         boolean nearCache) {
+        if (storeEnabled)
+            MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.CACHE_STORE);
+
         CacheConfiguration<Integer, Integer> ccfg = new CacheConfiguration<>(DEFAULT_CACHE_NAME);
 
         ccfg.setCacheMode(cacheMode);
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheNearUpdateTopologyChangeAbstractTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheNearUpdateTopologyChangeAbstractTest.java
index 21b3c72..e8d3433 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheNearUpdateTopologyChangeAbstractTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheNearUpdateTopologyChangeAbstractTest.java
@@ -25,6 +25,8 @@
 import org.apache.ignite.cache.affinity.Affinity;
 import org.apache.ignite.cluster.ClusterNode;
 import org.apache.ignite.configuration.NearCacheConfiguration;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.util.lang.GridAbsPredicate;
 import org.apache.ignite.testframework.GridTestUtils;
 
@@ -50,6 +52,11 @@
         return new NearCacheConfiguration();
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * @throws Exception If failed.
      */
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheNoAffinityExchangeTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheNoAffinityExchangeTest.java
index 45c6f25..15cd5ee 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheNoAffinityExchangeTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheNoAffinityExchangeTest.java
@@ -35,6 +35,7 @@
 import org.apache.ignite.spi.discovery.tcp.messages.TcpDiscoveryNodeFailedMessage;
 import org.apache.ignite.spi.discovery.tcp.messages.TcpDiscoveryNodeLeftMessage;
 import org.apache.ignite.testframework.GridTestUtils;
+import org.apache.ignite.testframework.MvccFeatureChecker;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
 
 /**
@@ -52,6 +53,13 @@
         .setAddresses(Collections.singleton("127.0.0.1:47500"));
 
     /** {@inheritDoc} */
+    @Override protected void beforeTestsStarted() throws Exception {
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.ENTRY_LOCK);
+
+        super.beforeTestsStarted();
+    }
+
+    /** {@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/CacheOffheapMapEntrySelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheOffheapMapEntrySelfTest.java
index e520d45..f2e12ad 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheOffheapMapEntrySelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheOffheapMapEntrySelfTest.java
@@ -25,9 +25,11 @@
 import org.apache.ignite.internal.processors.cache.distributed.dht.GridDhtCacheEntry;
 import org.apache.ignite.internal.processors.cache.distributed.near.GridNearCacheEntry;
 import org.apache.ignite.internal.processors.cache.local.GridLocalCacheEntry;
+import org.apache.ignite.testframework.MvccFeatureChecker;
 
 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.LOCAL;
 import static org.apache.ignite.cache.CacheMode.PARTITIONED;
 import static org.apache.ignite.cache.CacheMode.REPLICATED;
@@ -76,6 +78,9 @@
         cfg.setAtomicityMode(atomicityMode);
         cfg.setName(cacheName);
 
+        if (atomicityMode == TRANSACTIONAL_SNAPSHOT && !MvccFeatureChecker.isSupported(MvccFeatureChecker.Feature.NEAR_CACHE))
+            cfg.setNearConfiguration(null);
+
         return cfg;
     }
 
@@ -87,13 +92,22 @@
 
         checkCacheMapEntry(TRANSACTIONAL, LOCAL, GridLocalCacheEntry.class);
 
+        if (MvccFeatureChecker.isSupported(MvccFeatureChecker.Feature.LOCAL_CACHE))
+            checkCacheMapEntry(TRANSACTIONAL_SNAPSHOT, LOCAL, GridLocalCacheEntry.class);
+
         checkCacheMapEntry(ATOMIC, PARTITIONED, GridNearCacheEntry.class);
 
         checkCacheMapEntry(TRANSACTIONAL, PARTITIONED, GridNearCacheEntry.class);
 
+        if (MvccFeatureChecker.isSupported(MvccFeatureChecker.Feature.CACHE_STORE))
+            checkCacheMapEntry(TRANSACTIONAL_SNAPSHOT, PARTITIONED, GridDhtCacheEntry.class);
+
         checkCacheMapEntry(ATOMIC, REPLICATED, GridDhtCacheEntry.class);
 
         checkCacheMapEntry(TRANSACTIONAL, REPLICATED, GridDhtCacheEntry.class);
+
+        if (MvccFeatureChecker.isSupported(MvccFeatureChecker.Feature.CACHE_STORE))
+            checkCacheMapEntry(TRANSACTIONAL_SNAPSHOT, REPLICATED, GridDhtCacheEntry.class);
     }
 
     /**
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CachePutEventListenerErrorSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CachePutEventListenerErrorSelfTest.java
index 8891f64..e14f472 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CachePutEventListenerErrorSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CachePutEventListenerErrorSelfTest.java
@@ -28,6 +28,8 @@
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.events.Event;
 import org.apache.ignite.events.EventType;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.lang.IgniteBiPredicate;
 import org.apache.ignite.lang.IgniteFuture;
 import org.apache.ignite.lang.IgnitePredicate;
@@ -86,6 +88,11 @@
         }
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * @throws Exception If failed.
      */
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CachePutIfAbsentTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CachePutIfAbsentTest.java
index 00ba25f..a70d3c3 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CachePutIfAbsentTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CachePutIfAbsentTest.java
@@ -30,6 +30,7 @@
 import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
 import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder;
 import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
+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;
@@ -129,6 +130,9 @@
 
                     for (TransactionConcurrency concurrency : TransactionConcurrency.values()) {
                         for (TransactionIsolation isolation : TransactionIsolation.values()) {
+                            if (MvccFeatureChecker.forcedMvcc() && !MvccFeatureChecker.isSupported(concurrency, isolation))
+                                continue;
+
                             try (Transaction tx = txs.txStart(concurrency, isolation)) {
                                 Object old = cache.getAndPutIfAbsent(key, 3);
 
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheReadThroughLocalRestartSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheReadThroughLocalRestartSelfTest.java
index 58fa8d6..5e8b1eb 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheReadThroughLocalRestartSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheReadThroughLocalRestartSelfTest.java
@@ -18,6 +18,7 @@
 package org.apache.ignite.internal.processors.cache;
 
 import org.apache.ignite.cache.CacheMode;
+import org.apache.ignite.testframework.MvccFeatureChecker;
 
 import static org.apache.ignite.cache.CacheMode.LOCAL;
 
@@ -29,4 +30,11 @@
     @Override protected CacheMode cacheMode() {
         return LOCAL;
     }
+
+    /** {@inheritDoc} */
+    @Override public void setUp() throws Exception {
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.LOCAL_CACHE);
+
+        super.setUp();
+    }
 }
\ No newline at end of file
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheReadThroughRestartSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheReadThroughRestartSelfTest.java
index 422ed58..5b79f7f 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheReadThroughRestartSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheReadThroughRestartSelfTest.java
@@ -27,6 +27,7 @@
 import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
 import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder;
 import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
+import org.apache.ignite.testframework.MvccFeatureChecker;
 import org.apache.ignite.transactions.Transaction;
 import org.apache.ignite.transactions.TransactionConcurrency;
 import org.apache.ignite.transactions.TransactionIsolation;
@@ -42,6 +43,13 @@
     private static final TcpDiscoveryIpFinder IP_FINDER = new TcpDiscoveryVmIpFinder(true);
 
     /** {@inheritDoc} */
+    @Override public void setUp() throws Exception {
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.CACHE_STORE);
+
+        super.setUp();
+    }
+
+    /** {@inheritDoc} */
     @Override protected int gridCount() {
         return 2;
     }
@@ -116,6 +124,9 @@
 
         for (TransactionConcurrency txConcurrency : TransactionConcurrency.values()) {
             for (TransactionIsolation txIsolation : TransactionIsolation.values()) {
+                if (MvccFeatureChecker.forcedMvcc() && !MvccFeatureChecker.isSupported(txConcurrency, txIsolation))
+                    continue;
+
                 try (Transaction tx = ignite.transactions().txStart(txConcurrency, txIsolation, 100000, 1000)) {
                     for (int k = 0; k < 1000; k++) {
                         String key = "key" + k;
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheRebalancingSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheRebalancingSelfTest.java
index 75e6296..469a676 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheRebalancingSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheRebalancingSelfTest.java
@@ -35,6 +35,7 @@
 import org.apache.ignite.internal.util.lang.GridAbsPredicate;
 import org.apache.ignite.lang.IgniteFuture;
 import org.apache.ignite.testframework.GridTestUtils;
+import org.apache.ignite.testframework.MvccFeatureChecker;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
 
 /**
@@ -48,12 +49,12 @@
     @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception {
         IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName);
 
-        CacheConfiguration<Integer,Integer> rebalabceCacheCfg = new CacheConfiguration<>();
-        rebalabceCacheCfg.setBackups(1);
-        rebalabceCacheCfg.setName(REBALANCE_TEST_CACHE_NAME);
-        rebalabceCacheCfg.setWriteSynchronizationMode(CacheWriteSynchronizationMode.FULL_SYNC);
+        CacheConfiguration<Integer,Integer> ccfg = new CacheConfiguration<>();
+        ccfg.setBackups(1);
+        ccfg.setName(REBALANCE_TEST_CACHE_NAME);
+        ccfg.setWriteSynchronizationMode(CacheWriteSynchronizationMode.FULL_SYNC);
 
-        cfg.setCacheConfiguration(new CacheConfiguration(DEFAULT_CACHE_NAME), rebalabceCacheCfg);
+        cfg.setCacheConfiguration(new CacheConfiguration(DEFAULT_CACHE_NAME), ccfg);
 
         return cfg;
     }
@@ -69,6 +70,8 @@
      * @throws Exception If fails.
      */
     public void testRebalanceLocalCacheFuture() throws Exception {
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.LOCAL_CACHE);
+
         startGrid(
             getTestIgniteInstanceName(0),
             getConfiguration(getTestIgniteInstanceName(0))
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheRemoveAllSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheRemoveAllSelfTest.java
index a27bdda..cccb92a 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheRemoveAllSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheRemoveAllSelfTest.java
@@ -24,12 +24,21 @@
 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;
 
 /**
  * Test remove all method.
  */
 public class CacheRemoveAllSelfTest extends GridCacheAbstractSelfTest {
     /** {@inheritDoc} */
+    @Override public void setUp() throws Exception {
+        if (MvccFeatureChecker.forcedMvcc())
+            fail("https://issues.apache.org/jira/browse/IGNITE-10082");
+
+        super.setUp();
+    }
+
+    /** {@inheritDoc} */
     @Override protected long getTestTimeout() {
         return 2 * 60 * 1000;
     }
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheSerializableTransactionsTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheSerializableTransactionsTest.java
index 0afd4ba..2945a0e 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheSerializableTransactionsTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheSerializableTransactionsTest.java
@@ -58,6 +58,8 @@
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.configuration.NearCacheConfiguration;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.IgniteInternalFuture;
 import org.apache.ignite.internal.cluster.ClusterTopologyCheckedException;
 import org.apache.ignite.internal.util.typedef.F;
@@ -141,6 +143,11 @@
     }
 
     /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
+    /** {@inheritDoc} */
     @Override protected long getTestTimeout() {
         return 5 * 60_000;
     }
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheStopAndDestroySelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheStopAndDestroySelfTest.java
index 6239b52..a204ddf 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheStopAndDestroySelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheStopAndDestroySelfTest.java
@@ -29,6 +29,7 @@
 import org.apache.ignite.Ignite;
 import org.apache.ignite.IgniteCache;
 import org.apache.ignite.IgniteException;
+import org.apache.ignite.cache.CacheAtomicityMode;
 import org.apache.ignite.cluster.ClusterNode;
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.DataStorageConfiguration;
@@ -47,6 +48,7 @@
 import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder;
 import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
 import org.apache.ignite.testframework.GridTestUtils;
+import org.apache.ignite.testframework.MvccFeatureChecker;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
 
 import static org.apache.ignite.cache.CacheMode.LOCAL;
@@ -150,6 +152,7 @@
 
         cfg.setName(CACHE_NAME_DHT);
         cfg.setCacheMode(PARTITIONED);
+        cfg.setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL);
         cfg.setNearConfiguration(null);
 
         return cfg;
@@ -163,6 +166,7 @@
 
         cfg.setName(CACHE_NAME_CLIENT);
         cfg.setCacheMode(PARTITIONED);
+        cfg.setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL);
         cfg.setNearConfiguration(null);
 
         return cfg;
@@ -176,6 +180,7 @@
 
         cfg.setName(CACHE_NAME_NEAR);
         cfg.setCacheMode(PARTITIONED);
+        cfg.setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL);
         cfg.setNearConfiguration(new NearCacheConfiguration());
 
         return cfg;
@@ -190,6 +195,7 @@
         cfg.setName(CACHE_NAME_LOC);
         cfg.setCacheMode(LOCAL);
         cfg.setNearConfiguration(null);
+        cfg.setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL);
 
         return cfg;
     }
@@ -280,6 +286,8 @@
      * @throws Exception If failed.
      */
     public void testNearDoubleDestroy() throws Exception {
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.NEAR_CACHE);
+
         startGridsMultiThreaded(gridCount());
 
         nearDestroy();
@@ -320,6 +328,8 @@
      * @throws Exception If failed.
      */
     public void testLocalDoubleDestroy() throws Exception {
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.LOCAL_CACHE);
+
         startGridsMultiThreaded(gridCount());
 
         localDestroy();
@@ -563,6 +573,8 @@
      * @throws Exception If failed.
      */
     public void testNearClose() throws Exception {
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.NEAR_CACHE);
+
         startGridsMultiThreaded(gridCount());
 
         IgniteCache<String, String> cache0 = grid(0).getOrCreateCache(getNearConfig());
@@ -636,6 +648,8 @@
      * @throws Exception If failed.
      */
     public void testNearCloseWithTry() throws Exception {
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.NEAR_CACHE);
+
         startGridsMultiThreaded(gridCount());
 
         String curVal = null;
@@ -674,6 +688,8 @@
      * @throws Exception If failed.
      */
     public void testLocalClose() throws Exception {
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.LOCAL_CACHE);
+
         memCfg = new DataStorageConfiguration();
 
         startGridsMultiThreaded(gridCount());
@@ -725,6 +741,8 @@
      * @throws Exception If failed.
      */
     public void testLocalCloseWithTry() throws Exception {
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.LOCAL_CACHE);
+
         memCfg = new DataStorageConfiguration();
 
         startGridsMultiThreaded(gridCount());
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheStoreUsageMultinodeDynamicStartTxTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheStoreUsageMultinodeDynamicStartTxTest.java
index 4511fc5..e217a1f 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheStoreUsageMultinodeDynamicStartTxTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheStoreUsageMultinodeDynamicStartTxTest.java
@@ -18,6 +18,7 @@
 package org.apache.ignite.internal.processors.cache;
 
 import org.apache.ignite.cache.CacheAtomicityMode;
+import org.apache.ignite.testframework.MvccFeatureChecker;
 
 import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL;
 
@@ -26,6 +27,13 @@
  */
 public class CacheStoreUsageMultinodeDynamicStartTxTest extends CacheStoreUsageMultinodeDynamicStartAbstractTest {
     /** {@inheritDoc} */
+    @Override public void setUp() throws Exception {
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.CACHE_STORE);
+
+        super.setUp();
+    }
+
+    /** {@inheritDoc} */
     @Override protected CacheAtomicityMode atomicityMode() {
         return TRANSACTIONAL;
     }
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheStoreUsageMultinodeStaticStartTxTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheStoreUsageMultinodeStaticStartTxTest.java
index 2f11fc8..8fa7e65 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheStoreUsageMultinodeStaticStartTxTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheStoreUsageMultinodeStaticStartTxTest.java
@@ -18,6 +18,7 @@
 package org.apache.ignite.internal.processors.cache;
 
 import org.apache.ignite.cache.CacheAtomicityMode;
+import org.apache.ignite.testframework.MvccFeatureChecker;
 
 import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL;
 
@@ -26,6 +27,13 @@
  */
 public class CacheStoreUsageMultinodeStaticStartTxTest extends CacheStoreUsageMultinodeStaticStartAbstractTest {
     /** {@inheritDoc} */
+    @Override public void setUp() throws Exception {
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.CACHE_STORE);
+
+        super.setUp();
+    }
+
+    /** {@inheritDoc} */
     @Override protected CacheAtomicityMode atomicityMode() {
         return TRANSACTIONAL;
     }
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheTxNotAllowReadFromBackupTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheTxNotAllowReadFromBackupTest.java
index f0ec084..fad2c61 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheTxNotAllowReadFromBackupTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheTxNotAllowReadFromBackupTest.java
@@ -189,6 +189,72 @@
     }
 
     /**
+     * @throws Exception If failed.
+     */
+    public void testBackupConsistencyReplicatedMvcc() throws Exception {
+        CacheConfiguration<Integer, Integer> cfg = new CacheConfiguration<>("test-cache");
+
+        cfg.setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL_SNAPSHOT);
+        cfg.setWriteSynchronizationMode(CacheWriteSynchronizationMode.PRIMARY_SYNC);
+        cfg.setCacheMode(CacheMode.REPLICATED);
+        cfg.setReadFromBackup(false);
+
+        checkBackupConsistency(cfg, TransactionConcurrency.PESSIMISTIC, TransactionIsolation.REPEATABLE_READ);
+
+        checkBackupConsistencyGetAll(cfg, TransactionConcurrency.PESSIMISTIC, TransactionIsolation.REPEATABLE_READ);
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testBackupConsistencyReplicatedFullSyncMvcc() throws Exception {
+        CacheConfiguration<Integer, Integer> cfg = new CacheConfiguration<>("test-cache");
+
+        cfg.setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL_SNAPSHOT);
+        cfg.setWriteSynchronizationMode(CacheWriteSynchronizationMode.FULL_SYNC);
+        cfg.setCacheMode(CacheMode.REPLICATED);
+        cfg.setReadFromBackup(false);
+
+        checkBackupConsistency(cfg, TransactionConcurrency.PESSIMISTIC, TransactionIsolation.REPEATABLE_READ);
+
+        checkBackupConsistencyGetAll(cfg, TransactionConcurrency.PESSIMISTIC, TransactionIsolation.REPEATABLE_READ);
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testBackupConsistencyPartitionedMvcc() throws Exception {
+        CacheConfiguration<Integer, Integer> cfg = new CacheConfiguration<>("test-cache");
+
+        cfg.setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL_SNAPSHOT);
+        cfg.setWriteSynchronizationMode(CacheWriteSynchronizationMode.PRIMARY_SYNC);
+        cfg.setCacheMode(CacheMode.PARTITIONED);
+        cfg.setBackups(NODES - 1);
+        cfg.setReadFromBackup(false);
+
+        checkBackupConsistency(cfg, TransactionConcurrency.PESSIMISTIC, TransactionIsolation.REPEATABLE_READ);
+
+        checkBackupConsistencyGetAll(cfg, TransactionConcurrency.PESSIMISTIC, TransactionIsolation.REPEATABLE_READ);
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testBackupConsistencyPartitionedFullSyncMvcc() throws Exception {
+        CacheConfiguration<Integer, Integer> cfg = new CacheConfiguration<>("test-cache");
+
+        cfg.setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL_SNAPSHOT);
+        cfg.setWriteSynchronizationMode(CacheWriteSynchronizationMode.FULL_SYNC);
+        cfg.setCacheMode(CacheMode.PARTITIONED);
+        cfg.setBackups(NODES - 1);
+        cfg.setReadFromBackup(false);
+
+        checkBackupConsistency(cfg, TransactionConcurrency.PESSIMISTIC, TransactionIsolation.REPEATABLE_READ);
+
+        checkBackupConsistencyGetAll(cfg, TransactionConcurrency.PESSIMISTIC, TransactionIsolation.REPEATABLE_READ);
+    }
+
+    /**
      * @param ccfg Cache configuration.
      * @throws Exception If failed.
      */
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/ClusterReadOnlyModeAbstractTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/ClusterReadOnlyModeAbstractTest.java
index 7cb9649..3134f1c 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/ClusterReadOnlyModeAbstractTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/ClusterReadOnlyModeAbstractTest.java
@@ -30,6 +30,7 @@
 
 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;
 
@@ -46,12 +47,18 @@
     /** Replicated transactional cache. */
     private static final String REPL_TX_CACHE = "repl_tx_cache";
 
+    /** Replicated transactional cache. */
+    private static final String REPL_MVCC_CACHE = "repl_mvcc_cache";
+
     /** Partitioned atomic cache. */
     private static final String PART_ATOMIC_CACHE = "part_atomic_cache";
 
     /** Partitioned transactional cache. */
     private static final String PART_TX_CACHE = "part_tx_cache";
 
+    /** Partitioned mvcc transactional cache. */
+    private static final String PART_MVCC_CACHE = "part_mvcc_cache";
+
     /** Cache names. */
     protected static final Collection<String> CACHE_NAMES = F.asList(REPL_ATOMIC_CACHE, REPL_TX_CACHE,
         PART_ATOMIC_CACHE, PART_TX_CACHE);
@@ -77,8 +84,10 @@
         cfg.setCacheConfiguration(
             cacheConfiguration(REPL_ATOMIC_CACHE, REPLICATED, ATOMIC, null),
             cacheConfiguration(REPL_TX_CACHE, REPLICATED, TRANSACTIONAL, null),
+            cacheConfiguration(REPL_MVCC_CACHE, REPLICATED, TRANSACTIONAL_SNAPSHOT, "mvcc_repl_grp"),
             cacheConfiguration(PART_ATOMIC_CACHE, PARTITIONED, ATOMIC, "part_grp"),
-            cacheConfiguration(PART_TX_CACHE, PARTITIONED, TRANSACTIONAL, "part_grp")
+            cacheConfiguration(PART_TX_CACHE, PARTITIONED, TRANSACTIONAL, "part_grp"),
+            cacheConfiguration(PART_MVCC_CACHE, PARTITIONED, TRANSACTIONAL_SNAPSHOT, "mvcc_part_grp")
         );
 
         return cfg;
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CrossCacheLockTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CrossCacheLockTest.java
index 8f0e20f..d609ec7 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CrossCacheLockTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CrossCacheLockTest.java
@@ -25,6 +25,7 @@
 import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
 import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder;
 import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
+import org.apache.ignite.testframework.MvccFeatureChecker;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
 
 import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL;
@@ -46,6 +47,13 @@
     private static final String CACHE2 = "cache2";
 
     /** {@inheritDoc} */
+    @Override public void setUp() throws Exception {
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.ENTRY_LOCK);
+
+        super.setUp();
+    }
+
+    /** {@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/EntryVersionConsistencyReadThroughTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/EntryVersionConsistencyReadThroughTest.java
index ebf253d..9e6f627e 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/EntryVersionConsistencyReadThroughTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/EntryVersionConsistencyReadThroughTest.java
@@ -38,10 +38,12 @@
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.internal.IgniteEx;
 import org.apache.ignite.internal.processors.cache.version.GridCacheVersion;
+import org.apache.ignite.testframework.MvccFeatureChecker;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
 
 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.CacheWriteSynchronizationMode.FULL_SYNC;
 
@@ -109,6 +111,16 @@
     /**
      * @throws Exception If failed.
      */
+    public void testInvokeAllMvccTxCache() throws Exception {
+        if (!MvccFeatureChecker.isSupported(MvccFeatureChecker.Feature.CACHE_STORE))
+            fail("https://issues.apache.org/jira/browse/IGNITE-8582");
+
+        check(false, createCacheConfiguration(TRANSACTIONAL_SNAPSHOT));
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
     public void testInvokeAllAtomicCache() throws Exception {
         check(false, createCacheConfiguration(ATOMIC));
     }
@@ -128,6 +140,16 @@
     }
 
     /**
+     * @throws Exception If failed.
+     */
+    public void testInvokeMvccTxCache() throws Exception {
+        if (!MvccFeatureChecker.isSupported(MvccFeatureChecker.Feature.CACHE_STORE))
+            fail("https://issues.apache.org/jira/browse/IGNITE-8582");
+
+        check(true, createCacheConfiguration(TRANSACTIONAL_SNAPSHOT));
+    }
+
+    /**
      * Tests entry's versions consistency after invokeAll.
      *
      * @param single Single invoke or invokeAll.
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheAbstractFailoverSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheAbstractFailoverSelfTest.java
index 5c204c7..b4abd66 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheAbstractFailoverSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheAbstractFailoverSelfTest.java
@@ -27,6 +27,8 @@
 import org.apache.ignite.cache.CachePartialUpdateException;
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.IgniteInternalFuture;
 import org.apache.ignite.internal.cluster.ClusterTopologyCheckedException;
 import org.apache.ignite.internal.util.lang.GridAbsPredicate;
@@ -126,6 +128,11 @@
         stopAllGrids();
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * @throws Exception If failed.
      */
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheAbstractFullApiSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheAbstractFullApiSelfTest.java
index 5f4f349..29e3fe4 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheAbstractFullApiSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheAbstractFullApiSelfTest.java
@@ -70,6 +70,8 @@
 import org.apache.ignite.events.CacheEvent;
 import org.apache.ignite.events.Event;
 import org.apache.ignite.events.EventType;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.IgniteEx;
 import org.apache.ignite.internal.IgniteKernal;
 import org.apache.ignite.internal.IgnitionEx;
@@ -269,6 +271,11 @@
             info("Grid " + i + ": " + grid(i).localNode().id());
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * Checks that any invoke returns result.
      *
@@ -6006,6 +6013,8 @@
             doTransformResourceInjectionInTx(ignite, cache, true, false);
             doTransformResourceInjectionInTx(ignite, cache, true, true);
         }
+
+        grid(0).services( grid(0).cluster()).cancel(SERVICE_NAME1);
     }
 
     /**
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheAbstractRemoveFailureTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheAbstractRemoveFailureTest.java
index d7406c0..f71a377 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheAbstractRemoveFailureTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheAbstractRemoveFailureTest.java
@@ -38,6 +38,8 @@
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.configuration.NearCacheConfiguration;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.IgniteInternalFuture;
 import org.apache.ignite.internal.cluster.ClusterTopologyCheckedException;
 import org.apache.ignite.internal.util.lang.GridTuple;
@@ -126,6 +128,11 @@
         return DUR + 60_000;
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * @return Cache mode.
      */
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheAbstractSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheAbstractSelfTest.java
index 346e9f9..2e64c52 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheAbstractSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheAbstractSelfTest.java
@@ -53,6 +53,7 @@
 import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder;
 import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
 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.jetbrains.annotations.Nullable;
@@ -92,7 +93,8 @@
 
         assert cnt >= 1 : "At least one grid must be started";
 
-        initStoreStrategy();
+        if (!MvccFeatureChecker.forcedMvcc() || MvccFeatureChecker.isSupported(MvccFeatureChecker.Feature.CACHE_STORE))
+            initStoreStrategy();
 
         startGrids(cnt);
 
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheAtomicEntryProcessorDeploymentSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheAtomicEntryProcessorDeploymentSelfTest.java
index 4f513b3..f616b6e 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheAtomicEntryProcessorDeploymentSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheAtomicEntryProcessorDeploymentSelfTest.java
@@ -30,6 +30,7 @@
 import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
 import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder;
 import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
+import org.apache.ignite.testframework.MvccFeatureChecker;
 import org.apache.ignite.testframework.config.GridTestProperties;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
 
@@ -54,6 +55,16 @@
     /** */
     protected boolean clientMode;
 
+    /** {@inheritDoc} */
+    @Override protected void beforeTestsStarted() throws Exception {
+        if (MvccFeatureChecker.forcedMvcc()) {
+            assert atomicityMode() != ATOMIC;
+
+            fail("https://issues.apache.org/jira/browse/IGNITE-10359");
+        }
+
+        super.beforeTestsStarted();
+    }
 
     /** {@inheritDoc} */
     @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception {
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheEntryVersionSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheEntryVersionSelfTest.java
index 9e933be..8a4196b 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheEntryVersionSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheEntryVersionSelfTest.java
@@ -31,6 +31,7 @@
 
 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.CacheWriteSynchronizationMode.FULL_SYNC;
 import static org.apache.ignite.internal.processors.cache.version.GridCacheVersionManager.TOP_VER_BASE_TIME;
@@ -88,6 +89,15 @@
     /**
      * @throws Exception If failed.
      */
+    public void testVersionMvccTx() throws Exception {
+        atomicityMode = TRANSACTIONAL_SNAPSHOT;
+
+        checkVersion();
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
     private void checkVersion() throws Exception {
         startGridsMultiThreaded(3);
 
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheInterceptorAbstractSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheInterceptorAbstractSelfTest.java
index 432011e..12e8042 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheInterceptorAbstractSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheInterceptorAbstractSelfTest.java
@@ -40,6 +40,7 @@
 import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
 import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder;
 import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
+import org.apache.ignite.testframework.MvccFeatureChecker;
 import org.apache.ignite.transactions.Transaction;
 import org.apache.ignite.transactions.TransactionConcurrency;
 import org.apache.ignite.transactions.TransactionIsolation;
@@ -68,6 +69,14 @@
 
     /** {@inheritDoc} */
     @Override protected void beforeTestsStarted() throws Exception {
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.INTERCEPTOR);
+
+        if (nearEnabled())
+            MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.NEAR_CACHE);
+
+        if (storeEnabled())
+            MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.CACHE_STORE);
+
         interceptor = new Interceptor();
 
         super.beforeTestsStarted();
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheInterceptorLocalSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheInterceptorLocalSelfTest.java
index b317ba3..24c38b2 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheInterceptorLocalSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheInterceptorLocalSelfTest.java
@@ -19,6 +19,7 @@
 
 import org.apache.ignite.cache.CacheAtomicityMode;
 import org.apache.ignite.cache.CacheMode;
+import org.apache.ignite.testframework.MvccFeatureChecker;
 
 import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL;
 import static org.apache.ignite.cache.CacheMode.LOCAL;
@@ -28,6 +29,13 @@
  */
 public class GridCacheInterceptorLocalSelfTest extends GridCacheInterceptorAbstractSelfTest {
     /** {@inheritDoc} */
+    @Override public void setUp() throws Exception {
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.LOCAL_CACHE);
+
+        super.setUp();
+    }
+
+    /** {@inheritDoc} */
     @Override protected CacheAtomicityMode atomicityMode() {
         return TRANSACTIONAL;
     }
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheInterceptorLocalWithStoreSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheInterceptorLocalWithStoreSelfTest.java
index 15679b0..6375aa6 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheInterceptorLocalWithStoreSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheInterceptorLocalWithStoreSelfTest.java
@@ -17,11 +17,20 @@
 
 package org.apache.ignite.internal.processors.cache;
 
+import org.apache.ignite.testframework.MvccFeatureChecker;
+
 /**
  * Tests {@link org.apache.ignite.cache.CacheInterceptor}.
  */
 public class GridCacheInterceptorLocalWithStoreSelfTest extends GridCacheInterceptorLocalSelfTest {
     /** {@inheritDoc} */
+    @Override public void setUp() throws Exception {
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.CACHE_STORE);
+
+        super.setUp();
+    }
+
+    /** {@inheritDoc} */
     @Override protected boolean storeEnabled() {
         return true;
     }
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheInterceptorTransactionalRebalanceTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheInterceptorTransactionalRebalanceTest.java
index 87c3f32..d82b14d 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheInterceptorTransactionalRebalanceTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheInterceptorTransactionalRebalanceTest.java
@@ -18,12 +18,20 @@
 package org.apache.ignite.internal.processors.cache;
 
 import org.apache.ignite.cache.CacheAtomicityMode;
+import org.apache.ignite.testframework.MvccFeatureChecker;
 
 /**
  *
  */
 public class GridCacheInterceptorTransactionalRebalanceTest extends GridAbstractCacheInterceptorRebalanceTest {
     /** {@inheritDoc} */
+    @Override protected void beforeTestsStarted() throws Exception {
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.INTERCEPTOR);
+
+        super.beforeTestsStarted();
+    }
+
+    /** {@inheritDoc} */
     @Override protected CacheAtomicityMode atomicityMode() {
         return CacheAtomicityMode.TRANSACTIONAL;
     }
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheMarshallingNodeJoinSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheMarshallingNodeJoinSelfTest.java
index df3430f..c837e21 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheMarshallingNodeJoinSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheMarshallingNodeJoinSelfTest.java
@@ -39,6 +39,7 @@
 import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
 import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder;
 import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
+import org.apache.ignite.testframework.MvccFeatureChecker;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
 import org.apache.ignite.transactions.Transaction;
 
@@ -52,6 +53,13 @@
     private static final TcpDiscoveryIpFinder IP_FINDER = new TcpDiscoveryVmIpFinder(true);
 
     /** {@inheritDoc} */
+    @Override public void setUp() throws Exception {
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.CACHE_STORE);
+
+        super.setUp();
+    }
+
+    /** {@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/GridCacheMultinodeUpdateAbstractSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheMultinodeUpdateAbstractSelfTest.java
index 800f4ba..2027117 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheMultinodeUpdateAbstractSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheMultinodeUpdateAbstractSelfTest.java
@@ -29,6 +29,7 @@
 
 import static org.apache.ignite.cache.CacheAtomicityMode.ATOMIC;
 import static org.apache.ignite.cache.CacheMode.PARTITIONED;
+import static org.apache.ignite.testframework.MvccFeatureChecker.assertMvccWriteConflict;
 
 /**
  * Multinode update test.
@@ -97,8 +98,20 @@
 
                     final IgniteCache<Integer, Integer> cache = grid(idx).cache(DEFAULT_CACHE_NAME);
 
-                    for (int i = 0; i < ITERATIONS_PER_THREAD && !failed; i++)
-                        cache.invoke(key, new IncProcessor());
+                        for (int i = 0; i < ITERATIONS_PER_THREAD && !failed; i++) {
+                            boolean updated = false;
+
+                            while (!updated) {
+                                try {
+                                    cache.invoke(key, new IncProcessor());
+
+                                    updated = true;
+                                }
+                                catch (Exception e) {
+                                    assertMvccWriteConflict(e);
+                                }
+                            }
+                        }
 
                     return null;
                 }
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheMultinodeUpdateNearEnabledNoBackupsSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheMultinodeUpdateNearEnabledNoBackupsSelfTest.java
index fbfb994..aa9f029 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheMultinodeUpdateNearEnabledNoBackupsSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheMultinodeUpdateNearEnabledNoBackupsSelfTest.java
@@ -18,6 +18,7 @@
 package org.apache.ignite.internal.processors.cache;
 
 import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.testframework.MvccFeatureChecker;
 
 /**
  *
@@ -39,6 +40,9 @@
 
     /** {@inheritDoc} */
     @Override public void testInvoke() throws Exception {
-        fail("https://issues.apache.org/jira/browse/IGNITE-809");
+        if (!MvccFeatureChecker.forcedMvcc())
+            fail("https://issues.apache.org/jira/browse/IGNITE-809");
+        else
+            super.testInvoke();
     }
 }
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheMultinodeUpdateNearEnabledSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheMultinodeUpdateNearEnabledSelfTest.java
index 4cdc7a4..c0738a3 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheMultinodeUpdateNearEnabledSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheMultinodeUpdateNearEnabledSelfTest.java
@@ -19,6 +19,7 @@
 
 import org.apache.ignite.cache.CacheAtomicityMode;
 import org.apache.ignite.configuration.NearCacheConfiguration;
+import org.apache.ignite.testframework.MvccFeatureChecker;
 
 import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL;
 
@@ -27,6 +28,13 @@
  */
 public class GridCacheMultinodeUpdateNearEnabledSelfTest extends GridCacheMultinodeUpdateAbstractSelfTest {
     /** {@inheritDoc} */
+    @Override public void setUp() throws Exception {
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.NEAR_CACHE);
+
+        super.setUp();
+    }
+
+    /** {@inheritDoc} */
     @Override protected NearCacheConfiguration nearConfiguration() {
         return new NearCacheConfiguration();
     }
@@ -38,6 +46,9 @@
 
     /** {@inheritDoc} */
     @Override public void testInvoke() throws Exception {
-        fail("https://issues.apache.org/jira/browse/IGNITE-809");
+        if (!MvccFeatureChecker.forcedMvcc())
+            fail("https://issues.apache.org/jira/browse/IGNITE-809");
+        else
+            super.testInvoke();
     }
 }
\ No newline at end of file
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCachePartitionedWritesTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCachePartitionedWritesTest.java
index 0d00bef..a0c1669 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCachePartitionedWritesTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCachePartitionedWritesTest.java
@@ -27,6 +27,7 @@
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
 import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
+import org.apache.ignite.testframework.MvccFeatureChecker;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
 import org.apache.ignite.transactions.Transaction;
 
@@ -43,6 +44,13 @@
     private CacheStore store;
 
     /** {@inheritDoc} */
+    @Override protected void beforeTestsStarted() throws Exception {
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.CACHE_STORE);
+
+        super.beforeTestsStarted();
+    }
+
+    /** {@inheritDoc} */
     @Override protected final IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception {
         IgniteConfiguration c = super.getConfiguration(igniteInstanceName);
 
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCachePutAllFailoverSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCachePutAllFailoverSelfTest.java
index c15a0f8..af86195 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCachePutAllFailoverSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCachePutAllFailoverSelfTest.java
@@ -46,6 +46,8 @@
 import org.apache.ignite.configuration.DeploymentMode;
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.configuration.NearCacheConfiguration;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.IgniteKernal;
 import org.apache.ignite.internal.util.typedef.CI1;
 import org.apache.ignite.internal.util.typedef.F;
@@ -131,6 +133,11 @@
         System.clearProperty(IgniteSystemProperties.IGNITE_ENABLE_FORCIBLE_NODE_KILL);
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * @throws Exception If failed.
      */
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheReferenceCleanupSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheReferenceCleanupSelfTest.java
index 09da79e..36dc3ac 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheReferenceCleanupSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheReferenceCleanupSelfTest.java
@@ -37,6 +37,7 @@
 import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder;
 import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
 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;
 
@@ -80,6 +81,9 @@
 
     /** @throws Exception If failed. */
     public void testAtomicLongPartitioned() throws Exception {
+        if (MvccFeatureChecker.forcedMvcc())
+            fail("https://issues.apache.org/jira/browse/IGNITE-10391");
+
         mode = CacheMode.PARTITIONED;
 
         startGrids(2);
@@ -94,6 +98,9 @@
 
     /** @throws Exception If failed. */
     public void testAtomicLongReplicated() throws Exception {
+        if (MvccFeatureChecker.forcedMvcc())
+            fail("https://issues.apache.org/jira/browse/IGNITE-10391");
+
         mode = CacheMode.REPLICATED;
 
         startGrids(2);
@@ -108,6 +115,8 @@
 
     /** @throws Exception If failed. */
     public void testAtomicLongLocal() throws Exception {
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.LOCAL_CACHE);
+
         mode = CacheMode.LOCAL;
 
         try {
@@ -148,6 +157,8 @@
 
     /** @throws Exception If failed. */
     public void testOneAsyncOpLocal() throws Exception {
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.LOCAL_CACHE);
+
         mode = CacheMode.LOCAL;
 
         try {
@@ -188,6 +199,8 @@
 
     /** @throws Exception If failed. */
     public void testSeveralAsyncOpsLocal() throws Exception {
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.LOCAL_CACHE);
+
         mode = CacheMode.LOCAL;
 
         try {
@@ -228,6 +241,8 @@
 
     /** @throws Exception If failed. */
     public void testSyncOpAsyncCommitLocal() throws Exception {
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.LOCAL_CACHE);
+
         mode = CacheMode.LOCAL;
 
         try {
@@ -268,6 +283,8 @@
 
     /** @throws Exception If failed. */
     public void testAsyncOpsAsyncCommitLocal() throws Exception {
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.LOCAL_CACHE);
+
         mode = CacheMode.LOCAL;
 
         try {
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheReloadSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheReloadSelfTest.java
index 50bed2a..b960383 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheReloadSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheReloadSelfTest.java
@@ -30,6 +30,7 @@
 import org.apache.ignite.configuration.NearCacheConfiguration;
 import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
 import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
+import org.apache.ignite.testframework.MvccFeatureChecker;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
 
 import static org.apache.ignite.cache.CacheMode.PARTITIONED;
@@ -54,6 +55,17 @@
     private boolean nearEnabled = true;
 
     /** {@inheritDoc} */
+    @Override protected void beforeTestsStarted() throws Exception {
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.CACHE_STORE);
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.EVICTION);
+
+        if (nearEnabled)
+            MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.NEAR_CACHE);
+
+        super.beforeTestsStarted();
+    }
+
+    /** {@inheritDoc} */
     @Override protected void afterTest() throws Exception {
         cacheMode = null;
         nearEnabled = true;
@@ -119,6 +131,8 @@
      * @throws Exception If error occurs.
      */
     public void testReloadEvictionLocalCache() throws Exception {
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.LOCAL_CACHE);
+
         cacheMode = CacheMode.LOCAL;
 
         doTest();
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheStoreManagerDeserializationTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheStoreManagerDeserializationTest.java
index c63f242..124e284 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheStoreManagerDeserializationTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheStoreManagerDeserializationTest.java
@@ -42,6 +42,7 @@
 import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
 import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder;
 import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
+import org.apache.ignite.testframework.MvccFeatureChecker;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
 
 import static org.apache.ignite.cache.CacheMode.PARTITIONED;
@@ -66,6 +67,13 @@
     /** Test cache name. */
     protected static final String CACHE_NAME = "cache_name";
 
+    /** {@inheritDoc} */
+    @Override public void setUp() throws Exception {
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.CACHE_STORE);
+
+        super.setUp();
+    }
+
     /**
      * @return Cache mode.
      */
@@ -123,7 +131,7 @@
 
         cc.setBackups(0);
 
-        cc.setAtomicityMode(CacheAtomicityMode.ATOMIC);
+        cc.setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL);
 
         return cc;
     }
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheValueConsistencyAbstractSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheValueConsistencyAbstractSelfTest.java
index aba3250..6ef6ed4 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheValueConsistencyAbstractSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheValueConsistencyAbstractSelfTest.java
@@ -27,6 +27,7 @@
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.NearCacheConfiguration;
 import org.apache.ignite.testframework.GridTestUtils.SF;
+import org.apache.ignite.testframework.MvccFeatureChecker;
 
 import static org.apache.ignite.IgniteSystemProperties.IGNITE_ATOMIC_CACHE_DELETE_HISTORY_SIZE;
 import static org.apache.ignite.cache.CacheMode.PARTITIONED;
@@ -69,6 +70,11 @@
 
     /** {@inheritDoc} */
     @Override protected void beforeTestsStarted() throws Exception {
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.CACHE_STORE);
+
+        if (nearEnabled())
+            MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.NEAR_CACHE);
+
         // Need to increase value set in GridAbstractTest
         sizePropVal = System.getProperty(IGNITE_ATOMIC_CACHE_DELETE_HISTORY_SIZE);
 
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheVariableTopologySelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheVariableTopologySelfTest.java
index b9f7a35..24529ce 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheVariableTopologySelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheVariableTopologySelfTest.java
@@ -26,6 +26,8 @@
 import org.apache.ignite.cluster.ClusterTopologyException;
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.IgniteInternalFuture;
 import org.apache.ignite.internal.cluster.ClusterTopologyCheckedException;
 import org.apache.ignite.internal.util.typedef.CAX;
@@ -98,6 +100,11 @@
         assert G.allGrids().isEmpty();
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * @param cnt Number of grids to starts.
      * @param startIdx Start grid index.
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheVersionMultinodeTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheVersionMultinodeTest.java
index 0fd3fb9..ccecfb7 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheVersionMultinodeTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheVersionMultinodeTest.java
@@ -33,6 +33,7 @@
 
 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.transactions.TransactionConcurrency.OPTIMISTIC;
 import static org.apache.ignite.transactions.TransactionConcurrency.PESSIMISTIC;
@@ -109,6 +110,30 @@
     /**
      * @throws Exception If failed.
      */
+    public void testVersionMvccTx() throws Exception {
+        fail("https://issues.apache.org/jira/browse/IGNITE-8582");
+
+        atomicityMode = TRANSACTIONAL_SNAPSHOT;
+
+        checkVersion();
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testVersionMvccTxNearEnabled() throws Exception {
+        fail("https://issues.apache.org/jira/browse/IGNITE-7187");
+
+        atomicityMode = TRANSACTIONAL_SNAPSHOT;
+
+        near = true;
+
+        checkVersion();
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
     public void testVersionAtomicPrimary() throws Exception {
         atomicityMode = ATOMIC;
 
@@ -138,17 +163,19 @@
             checkVersion(String.valueOf(i), null); // Update.
         }
 
-        if (atomicityMode == TRANSACTIONAL) {
+        if (atomicityMode != ATOMIC) {
             for (int i = 100; i < 200; i++) {
                 checkVersion(String.valueOf(i), PESSIMISTIC); // Create.
 
                 checkVersion(String.valueOf(i), PESSIMISTIC); // Update.
             }
 
-            for (int i = 200; i < 300; i++) {
-                checkVersion(String.valueOf(i), OPTIMISTIC); // Create.
+            if (atomicityMode != TRANSACTIONAL_SNAPSHOT) {
+                for (int i = 200; i < 300; i++) {
+                    checkVersion(String.valueOf(i), OPTIMISTIC); // Create.
 
-                checkVersion(String.valueOf(i), OPTIMISTIC); // Update.
+                    checkVersion(String.valueOf(i), OPTIMISTIC); // Update.
+                }
             }
         }
     }
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheVersionTopologyChangeTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheVersionTopologyChangeTest.java
index 9de2338..5e92173 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheVersionTopologyChangeTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheVersionTopologyChangeTest.java
@@ -32,6 +32,8 @@
 import org.apache.ignite.cache.affinity.rendezvous.RendezvousAffinityFunction;
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
 import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder;
 import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
@@ -40,6 +42,7 @@
 
 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.CacheWriteSynchronizationMode.FULL_SYNC;
 
 /**
@@ -65,6 +68,11 @@
         super.afterTest();
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * @throws Exception If failed.
      */
@@ -80,6 +88,13 @@
     }
 
     /**
+     * @throws Exception If failed.
+     */
+    public void testVersionIncreaseMvccTx() throws Exception {
+        checkVersionIncrease(cacheConfigurations(TRANSACTIONAL_SNAPSHOT));
+    }
+
+    /**
      * @param ccfgs Cache configurations.
      * @throws Exception If failed.
      */
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteAbstractDynamicCacheStartFailTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteAbstractDynamicCacheStartFailTest.java
index d506224..018d04a 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteAbstractDynamicCacheStartFailTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteAbstractDynamicCacheStartFailTest.java
@@ -63,6 +63,8 @@
 import org.apache.ignite.cluster.ClusterNode;
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.IgniteInternalFuture;
 import org.apache.ignite.lang.IgnitePredicate;
 import org.apache.ignite.resources.IgniteInstanceResource;
@@ -95,6 +97,11 @@
         return 3;
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * Returns {@code true} if persistence is enabled.
      *
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheGroupsTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheGroupsTest.java
index 3d16dd2..3fe67d6 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheGroupsTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheGroupsTest.java
@@ -17,6 +17,7 @@
 
 package org.apache.ignite.internal.processors.cache;
 
+import com.google.common.collect.Sets;
 import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -49,7 +50,6 @@
 import javax.cache.integration.CacheWriterException;
 import javax.cache.processor.EntryProcessorException;
 import javax.cache.processor.MutableEntry;
-import com.google.common.collect.Sets;
 import org.apache.ignite.Ignite;
 import org.apache.ignite.IgniteCache;
 import org.apache.ignite.IgniteCheckedException;
@@ -75,6 +75,8 @@
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.configuration.NearCacheConfiguration;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.IgniteInternalFuture;
 import org.apache.ignite.internal.IgniteKernal;
 import org.apache.ignite.internal.binary.BinaryMarshaller;
@@ -105,6 +107,7 @@
 
 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.LOCAL;
 import static org.apache.ignite.cache.CacheMode.PARTITIONED;
 import static org.apache.ignite.cache.CacheMode.REPLICATED;
@@ -129,6 +132,9 @@
     private static final String GROUP2 = "grp2";
 
     /** */
+    private static final String GROUP3 = "grp3";
+
+    /** */
     private static final String CACHE1 = "cache1";
 
     /** */
@@ -172,6 +178,11 @@
         super.afterTest();
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * @throws Exception If failed.
      */
@@ -255,6 +266,13 @@
     /**
      * @throws Exception If failed.
      */
+    public void testCreateDestroyCachesMvccTxPartitioned() throws Exception {
+        createDestroyCaches(PARTITIONED, TRANSACTIONAL_SNAPSHOT);
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
     public void testCreateDestroyCachesAtomicReplicated() throws Exception {
         createDestroyCaches(REPLICATED, ATOMIC);
     }
@@ -269,6 +287,13 @@
     /**
      * @throws Exception If failed.
      */
+    public void testCreateDestroyCachesMvccTxReplicated() throws Exception {
+        createDestroyCaches(REPLICATED, TRANSACTIONAL_SNAPSHOT);
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
     public void testScanQueryAtomicPartitioned() throws Exception {
         scanQuery(PARTITIONED, ATOMIC);
     }
@@ -283,6 +308,13 @@
     /**
      * @throws Exception If failed.
      */
+    public void testScanQueryMvccTxPartitioned() throws Exception {
+        scanQuery(PARTITIONED, TRANSACTIONAL_SNAPSHOT);
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
     public void testScanQueryAtomicReplicated() throws Exception {
         scanQuery(REPLICATED, ATOMIC);
     }
@@ -297,6 +329,14 @@
     /**
      * @throws Exception If failed.
      */
+    public void testScanQueryMvccTxReplicated() throws Exception {
+        scanQuery(REPLICATED, TRANSACTIONAL_SNAPSHOT);
+    }
+
+
+    /**
+     * @throws Exception If failed.
+     */
     public void testScanQueryAtomicLocal() throws Exception {
         scanQuery(LOCAL, ATOMIC);
     }
@@ -311,6 +351,15 @@
     /**
      * @throws Exception If failed.
      */
+    public void testScanQueryMvccTxLocal() throws Exception {
+        fail("https://issues.apache.org/jira/browse/IGNITE-9530");
+
+        scanQuery(LOCAL, TRANSACTIONAL_SNAPSHOT);
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
     public void testEntriesTtlAtomicPartitioned() throws Exception {
         entriesTtl(PARTITIONED, ATOMIC);
     }
@@ -325,6 +374,15 @@
     /**
      * @throws Exception If failed.
      */
+    public void testEntriesTtlMvccTxPartitioned() throws Exception {
+        fail("https://issues.apache.org/jira/browse/IGNITE-7311");
+
+        entriesTtl(PARTITIONED, TRANSACTIONAL_SNAPSHOT);
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
     public void testEntriesTtlAtomicReplicated() throws Exception {
         entriesTtl(REPLICATED, ATOMIC);
     }
@@ -339,6 +397,15 @@
     /**
      * @throws Exception If failed.
      */
+    public void testEntriesTtlMvccTxReplicated() throws Exception {
+        fail("https://issues.apache.org/jira/browse/IGNITE-7311");
+
+        entriesTtl(REPLICATED, TRANSACTIONAL_SNAPSHOT);
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
     public void testEntriesTtlAtomicLocal() throws Exception {
         entriesTtl(LOCAL, ATOMIC);
     }
@@ -353,6 +420,16 @@
     /**
      * @throws Exception If failed.
      */
+    public void testEntriesTtlMvccTxLocal() throws Exception {
+        fail("https://issues.apache.org/jira/browse/IGNITE-9530");
+        fail("https://issues.apache.org/jira/browse/IGNITE-7311");
+
+        entriesTtl(LOCAL, TRANSACTIONAL_SNAPSHOT);
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
     public void testCacheIteratorAtomicPartitioned() throws Exception {
         cacheIterator(PARTITIONED, ATOMIC);
     }
@@ -367,6 +444,13 @@
     /**
      * @throws Exception If failed.
      */
+    public void testCacheIteratorMvccTxPartitioned() throws Exception {
+        cacheIterator(PARTITIONED, TRANSACTIONAL_SNAPSHOT);
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
     public void testCacheIteratorAtomicReplicated() throws Exception {
         cacheIterator(REPLICATED, ATOMIC);
     }
@@ -381,6 +465,13 @@
     /**
      * @throws Exception If failed.
      */
+    public void testCacheIteratorMvccTxReplicated() throws Exception {
+        cacheIterator(REPLICATED, TRANSACTIONAL_SNAPSHOT);
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
     public void testCacheIteratorAtomicLocal() throws Exception {
         cacheIterator(LOCAL, ATOMIC);
     }
@@ -395,6 +486,15 @@
     /**
      * @throws Exception If failed.
      */
+    public void testCacheIteratorMvccTxLocal() throws Exception {
+        fail("https://issues.apache.org/jira/browse/IGNITE-9530");
+
+        cacheIterator(LOCAL, TRANSACTIONAL_SNAPSHOT);
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
     public void testScanQueryMultiplePartitionsAtomicPartitioned() throws Exception {
         scanQueryMultiplePartitions(PARTITIONED, ATOMIC);
     }
@@ -409,6 +509,13 @@
     /**
      * @throws Exception If failed.
      */
+    public void testScanQueryMultiplePartitionsMvccTxPartitioned() throws Exception {
+        scanQueryMultiplePartitions(PARTITIONED, TRANSACTIONAL_SNAPSHOT);
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
     public void testScanQueryMultiplePartitionsAtomicReplicated() throws Exception {
         scanQueryMultiplePartitions(REPLICATED, ATOMIC);
     }
@@ -423,6 +530,13 @@
     /**
      * @throws Exception If failed.
      */
+    public void testScanQueryMultiplePartitionsMvccTxReplicated() throws Exception {
+        scanQueryMultiplePartitions(REPLICATED, TRANSACTIONAL_SNAPSHOT);
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
     public void testContinuousQueryTxReplicated() throws Exception {
         continuousQuery(REPLICATED, TRANSACTIONAL);
     }
@@ -430,6 +544,13 @@
     /**
      * @throws Exception If failed.
      */
+    public void testContinuousQueryMvccTxReplicated() throws Exception {
+        continuousQuery(REPLICATED, TRANSACTIONAL_SNAPSHOT);
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
     public void testContinuousQueryTxPartitioned() throws Exception {
         continuousQuery(PARTITIONED, TRANSACTIONAL);
     }
@@ -437,6 +558,13 @@
     /**
      * @throws Exception If failed.
      */
+    public void testContinuousQueryMvccTxPartitioned() throws Exception {
+        continuousQuery(PARTITIONED, TRANSACTIONAL_SNAPSHOT);
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
     public void testContinuousQueryTxLocal() throws Exception {
         continuousQuery(LOCAL, TRANSACTIONAL);
     }
@@ -444,6 +572,15 @@
     /**
      * @throws Exception If failed.
      */
+    public void testContinuousQueryMvccTxLocal() throws Exception {
+        fail("https://issues.apache.org/jira/browse/IGNITE-9530");
+
+        continuousQuery(LOCAL, TRANSACTIONAL_SNAPSHOT);
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
     public void testContinuousQueryAtomicReplicated() throws Exception {
         continuousQuery(REPLICATED, ATOMIC);
     }
@@ -1342,6 +1479,10 @@
             srv0.createCache(cacheConfiguration(GROUP2, "c3", PARTITIONED, TRANSACTIONAL, 2, false));
         IgniteCache<Object, Object> srv0Cache4 =
             srv0.createCache(cacheConfiguration(GROUP2, "c4", PARTITIONED, TRANSACTIONAL, 2, false));
+        IgniteCache<Object, Object> srv0Cache5 =
+            srv0.createCache(cacheConfiguration(GROUP3, "c5", PARTITIONED, TRANSACTIONAL_SNAPSHOT, 2, false));
+        IgniteCache<Object, Object> srv0Cache6 =
+            srv0.createCache(cacheConfiguration(GROUP3, "c6", PARTITIONED, TRANSACTIONAL_SNAPSHOT, 2, false));
 
         final int ITEMS = 1_000;
 
@@ -1350,6 +1491,9 @@
 
             srv0Cache3.put(new Key1(i), i);
             srv0Cache4.put(new Key1(i), -i);
+
+            srv0Cache5.put(new Key1(i), i);
+            srv0Cache6.put(new Key1(i), -i);
         }
 
         assertEquals(ITEMS, srv0Cache1.size());
@@ -1357,6 +1501,8 @@
         assertEquals(0, srv0Cache2.size());
         assertEquals(ITEMS, srv0Cache3.size());
         assertEquals(ITEMS, srv0Cache4.localSize());
+        assertEquals(ITEMS, srv0Cache5.size());
+        assertEquals(ITEMS, srv0Cache6.localSize());
 
         startGrid(1);
 
@@ -1369,6 +1515,8 @@
             IgniteCache<Object, Object> cache2 = node.cache("c2");
             IgniteCache<Object, Object> cache3 = node.cache("c3");
             IgniteCache<Object, Object> cache4 = node.cache("c4");
+            IgniteCache<Object, Object> cache5 = node.cache("c5");
+            IgniteCache<Object, Object> cache6 = node.cache("c6");
 
             assertEquals(ITEMS * 2, cache1.size(CachePeekMode.ALL));
             assertEquals(ITEMS, cache1.localSize(CachePeekMode.ALL));
@@ -1381,11 +1529,20 @@
             assertEquals(ITEMS * 2, cache4.size(CachePeekMode.ALL));
             assertEquals(ITEMS, cache4.localSize(CachePeekMode.ALL));
 
+            assertEquals(ITEMS * 2, cache5.size(CachePeekMode.ALL));
+            assertEquals(ITEMS, cache5.localSize(CachePeekMode.ALL));
+
+            assertEquals(ITEMS * 2, cache6.size(CachePeekMode.ALL));
+            assertEquals(ITEMS, cache6.localSize(CachePeekMode.ALL));
+
+
             for (int k = 0; k < ITEMS; k++) {
                 assertEquals(i, cache1.localPeek(new Key1(i)));
                 assertNull(cache2.localPeek(new Key1(i)));
                 assertEquals(i, cache3.localPeek(new Key1(i)));
                 assertEquals(-i, cache4.localPeek(new Key1(i)));
+                assertEquals(i, cache5.localPeek(new Key1(i)));
+                assertEquals(-i, cache6.localPeek(new Key1(i)));
             }
         }
 
@@ -1403,6 +1560,8 @@
             IgniteCache<Object, Object> cache2 = node.cache("c2");
             IgniteCache<Object, Object> cache3 = node.cache("c3");
             IgniteCache<Object, Object> cache4 = node.cache("c4");
+            IgniteCache<Object, Object> cache5 = node.cache("c5");
+            IgniteCache<Object, Object> cache6 = node.cache("c6");
 
             assertEquals(ITEMS * 3, cache1.size(CachePeekMode.ALL));
             assertEquals(ITEMS, cache1.localSize(CachePeekMode.ALL));
@@ -1410,6 +1569,8 @@
             assertEquals(ITEMS * 2, cache2.localSize(CachePeekMode.ALL));
             assertEquals(ITEMS, cache3.localSize(CachePeekMode.ALL));
             assertEquals(ITEMS, cache4.localSize(CachePeekMode.ALL));
+            assertEquals(ITEMS, cache5.localSize(CachePeekMode.ALL));
+            assertEquals(ITEMS, cache6.localSize(CachePeekMode.ALL));
         }
 
         IgniteCache<Object, Object> srv2Cache1 = srv2.cache("c1");
@@ -1515,6 +1676,13 @@
     /**
      * @throws Exception If failed.
      */
+    public void testNoKeyIntersectMvccTx() throws Exception {
+        testNoKeyIntersect(TRANSACTIONAL_SNAPSHOT);
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
     public void testNoKeyIntersectAtomic() throws Exception {
         testNoKeyIntersect(ATOMIC);
     }
@@ -1833,6 +2001,15 @@
     /**
      * @throws Exception If failed.
      */
+    public void testCacheApiMvccTxPartitioned() throws Exception {
+        fail("https://issues.apache.org/jira/browse/IGNITE-7952");
+
+        cacheApiTest(PARTITIONED, TRANSACTIONAL_SNAPSHOT);
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
     public void testCacheApiTxReplicated() throws Exception {
         cacheApiTest(REPLICATED, TRANSACTIONAL);
     }
@@ -1840,6 +2017,15 @@
     /**
      * @throws Exception If failed.
      */
+    public void testCacheApiMvccTxReplicated() throws Exception {
+        fail("https://issues.apache.org/jira/browse/IGNITE-7952");
+
+        cacheApiTest(REPLICATED, TRANSACTIONAL_SNAPSHOT);
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
     public void testCacheApiAtomicPartitioned() throws Exception {
         cacheApiTest(PARTITIONED, ATOMIC);
     }
@@ -2660,6 +2846,15 @@
     /**
      * @throws Exception If failed.
      */
+    public void testLoadCacheMvccTxPartitioned() throws Exception {
+        fail("https://issues.apache.org/jira/browse/IGNITE-7954");
+
+        loadCache(PARTITIONED, TRANSACTIONAL_SNAPSHOT);
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
     public void testLoadCacheTxReplicated() throws Exception {
         loadCache(REPLICATED, TRANSACTIONAL);
     }
@@ -2667,6 +2862,15 @@
     /**
      * @throws Exception If failed.
      */
+    public void testLoadCacheMvccTxReplicated() throws Exception {
+        fail("https://issues.apache.org/jira/browse/IGNITE-7954");
+
+        loadCache(REPLICATED, TRANSACTIONAL_SNAPSHOT);
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
     public void testLoadCacheAtomicLocal() throws Exception {
         loadCache(LOCAL, ATOMIC);
     }
@@ -2679,6 +2883,15 @@
     }
 
     /**
+     * @throws Exception If failed.
+     */
+    public void testLoadCacheMvccTxLocal() throws Exception {
+        fail("https://issues.apache.org/jira/browse/IGNITE-9530");
+
+        loadCache(LOCAL, TRANSACTIONAL_SNAPSHOT);
+    }
+
+    /**
      * @param cacheMode Cache mode.
      * @param atomicityMode Atomicity mode.
      * @throws Exception If failed.
@@ -2855,6 +3068,8 @@
 
             srv0.createCache(
                 cacheConfiguration(GROUP2, GROUP2 + "-" + i, PARTITIONED, TRANSACTIONAL, grp2Backups, i % 2 == 0));
+
+            // TODO IGNITE-7164: add Mvcc cache to test.
         }
 
         final AtomicInteger idx = new AtomicInteger();
@@ -3306,6 +3521,16 @@
                 assertTrue("Unexpected message: " + e.getMessage(),
                     e.getMessage().contains("Backups mismatch for caches related to the same group [groupName=grp1"));
             }
+
+            try {
+                ignite(i).createCache(cacheConfiguration(GROUP1, "c2", PARTITIONED, TRANSACTIONAL_SNAPSHOT, 1, false));
+
+                fail();
+            }
+            catch (CacheException e) {
+                assertTrue("Unexpected message: " + e.getMessage(),
+                    e.getMessage().contains("Atomicity mode mismatch for caches related to the same group [groupName=grp1"));
+            }
         }
     }
 
@@ -3322,6 +3547,8 @@
         ccfgs[4] = cacheConfiguration(GROUP1, "c5", PARTITIONED, ATOMIC, 2, false);
         ccfgs[5] = cacheConfiguration(GROUP1, "c6", PARTITIONED, TRANSACTIONAL, 2, false);
 
+        //TODO IGNITE-9323: Check Mvcc mode.
+
         return ccfgs;
     }
 
@@ -3385,6 +3612,8 @@
         ccfgs[4] = cacheConfiguration(GROUP1, "c5", PARTITIONED, ATOMIC, 2, false);
         ccfgs[5] = cacheConfiguration(GROUP1, "c6", PARTITIONED, TRANSACTIONAL, 2, false);
 
+        //TODO IGNITE-8582: Check Mvcc mode.
+
         return ccfgs;
     }
 
@@ -3560,7 +3789,9 @@
         client.createCache(cacheConfiguration(null, "c7", PARTITIONED, ATOMIC, 1, false));
         client.createCache(cacheConfiguration(null, "c8", PARTITIONED, TRANSACTIONAL, 1, false));
 
-        String[] cacheNames = {"c1", "c2", "c3", "c4", "c5", "c6", "c7", "c8"};
+        client.createCache(cacheConfiguration(GROUP3, "c9", PARTITIONED, TRANSACTIONAL_SNAPSHOT, 1, false));
+
+        String[] cacheNames = {"c1", "c2", "c3", "c4", "c5", "c6", "c7", "c8", "c9"};
 
         AtomicInteger c1 = registerListener(client, "c1");
 
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheInterceptorSelfTestSuite.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheInterceptorSelfTestSuite.java
index f457e5d..37b8d40 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheInterceptorSelfTestSuite.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheInterceptorSelfTestSuite.java
@@ -17,7 +17,9 @@
 
 package org.apache.ignite.internal.processors.cache;
 
+import java.util.Collection;
 import junit.framework.TestSuite;
+import org.apache.ignite.testframework.GridTestUtils;
 
 /**
  * Cache interceptor suite.
@@ -25,41 +27,48 @@
 public class IgniteCacheInterceptorSelfTestSuite extends TestSuite {
     /**
      * @return Cache API test suite.
-     * @throws Exception If failed.
      */
-    public static TestSuite suite() throws Exception {
+    public static TestSuite suite() {
+        return suite(null);
+    }
+
+    /**
+     * @param ignoredTests Ignored tests.
+     * @return IgniteCache test suite.
+     */
+    public static TestSuite suite(Collection<Class> ignoredTests) {
         TestSuite suite = new TestSuite("CacheInterceptor Test Suite");
 
-        suite.addTestSuite(GridCacheInterceptorLocalSelfTest.class);
-        suite.addTestSuite(GridCacheInterceptorLocalWithStoreSelfTest.class);
+        GridTestUtils.addTestIfNeeded(suite,GridCacheInterceptorLocalSelfTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite,GridCacheInterceptorLocalWithStoreSelfTest.class, ignoredTests);
 
-        suite.addTestSuite(GridCacheInterceptorLocalAtomicSelfTest.class);
-        suite.addTestSuite(GridCacheInterceptorLocalAtomicWithStoreSelfTest.class);
+        GridTestUtils.addTestIfNeeded(suite,GridCacheInterceptorLocalAtomicSelfTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite,GridCacheInterceptorLocalAtomicWithStoreSelfTest.class, ignoredTests);
 
-        suite.addTestSuite(GridCacheInterceptorAtomicSelfTest.class);
-        suite.addTestSuite(GridCacheInterceptorAtomicNearEnabledSelfTest.class);
-        suite.addTestSuite(GridCacheInterceptorAtomicWithStoreSelfTest.class);
+        GridTestUtils.addTestIfNeeded(suite,GridCacheInterceptorAtomicSelfTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite,GridCacheInterceptorAtomicNearEnabledSelfTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite,GridCacheInterceptorAtomicWithStoreSelfTest.class, ignoredTests);
 
-        suite.addTestSuite(GridCacheInterceptorAtomicReplicatedSelfTest.class);
-        suite.addTestSuite(GridCacheInterceptorAtomicWithStoreReplicatedSelfTest.class);
+        GridTestUtils.addTestIfNeeded(suite,GridCacheInterceptorAtomicReplicatedSelfTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite,GridCacheInterceptorAtomicWithStoreReplicatedSelfTest.class, ignoredTests);
 
-        suite.addTestSuite(GridCacheInterceptorSelfTest.class);
-        suite.addTestSuite(GridCacheInterceptorNearEnabledSelfTest.class);
-        suite.addTestSuite(GridCacheInterceptorWithStoreSelfTest.class);
-        suite.addTestSuite(GridCacheInterceptorReplicatedSelfTest.class);
-        suite.addTestSuite(GridCacheInterceptorReplicatedWithStoreSelfTest.class);
+        GridTestUtils.addTestIfNeeded(suite,GridCacheInterceptorSelfTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite,GridCacheInterceptorNearEnabledSelfTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite,GridCacheInterceptorWithStoreSelfTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite,GridCacheInterceptorReplicatedSelfTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite,GridCacheInterceptorReplicatedWithStoreSelfTest.class, ignoredTests);
 
 // TODO GG-11141.
-//        suite.addTestSuite(GridCacheOnCopyFlagTxPartitionedSelfTest.class);
-//        suite.addTestSuite(GridCacheOnCopyFlagReplicatedSelfTest.class);
-//        suite.addTestSuite(GridCacheOnCopyFlagLocalSelfTest.class);
-//        suite.addTestSuite(GridCacheOnCopyFlagAtomicSelfTest.class);
+//        GridTestUtils.addTestIfNeeded(suite,GridCacheOnCopyFlagTxPartitionedSelfTest.class, ignoredTests);
+//        GridTestUtils.addTestIfNeeded(suite,GridCacheOnCopyFlagReplicatedSelfTest.class, ignoredTests);
+//        GridTestUtils.addTestIfNeeded(suite,GridCacheOnCopyFlagLocalSelfTest.class, ignoredTests);
+//        GridTestUtils.addTestIfNeeded(suite,GridCacheOnCopyFlagAtomicSelfTest.class, ignoredTests);
 
-        suite.addTestSuite(CacheInterceptorPartitionCounterRandomOperationsTest.class);
-        suite.addTestSuite(CacheInterceptorPartitionCounterLocalSanityTest.class);
+        GridTestUtils.addTestIfNeeded(suite,CacheInterceptorPartitionCounterRandomOperationsTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite,CacheInterceptorPartitionCounterLocalSanityTest.class, ignoredTests);
 
-        suite.addTestSuite(GridCacheInterceptorAtomicRebalanceTest.class);
-        suite.addTestSuite(GridCacheInterceptorTransactionalRebalanceTest.class);
+        GridTestUtils.addTestIfNeeded(suite,GridCacheInterceptorAtomicRebalanceTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite,GridCacheInterceptorTransactionalRebalanceTest.class, ignoredTests);
 
         return suite;
     }
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheInvokeReadThroughSingleNodeTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheInvokeReadThroughSingleNodeTest.java
index 406e5af..cb4410a 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheInvokeReadThroughSingleNodeTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheInvokeReadThroughSingleNodeTest.java
@@ -17,8 +17,11 @@
 
 package org.apache.ignite.internal.processors.cache;
 
+import org.apache.ignite.testframework.MvccFeatureChecker;
+
 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.LOCAL;
 import static org.apache.ignite.cache.CacheMode.PARTITIONED;
 import static org.apache.ignite.cache.CacheMode.REPLICATED;
@@ -28,6 +31,13 @@
  */
 public class IgniteCacheInvokeReadThroughSingleNodeTest extends IgniteCacheInvokeReadThroughAbstractTest {
     /** {@inheritDoc} */
+    @Override public void setUp() throws Exception {
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.CACHE_STORE);
+
+        super.setUp();
+    }
+
+    /** {@inheritDoc} */
     @Override protected void startNodes() throws Exception {
         startGrid(0);
     }
@@ -87,4 +97,40 @@
     public void testInvokeReadThroughTxLocal() throws Exception {
         invokeReadThrough(cacheConfiguration(LOCAL, TRANSACTIONAL, 0, false));
     }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testInvokeReadThroughMvccTx() throws Exception {
+        fail("https://issues.apache.org/jira/browse/IGNITE-8582");
+
+        invokeReadThrough(cacheConfiguration(PARTITIONED, TRANSACTIONAL_SNAPSHOT, 1, false));
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testInvokeReadThroughMvccTxNearCache() throws Exception {
+        fail("https://issues.apache.org/jira/browse/IGNITE-8582");
+
+        invokeReadThrough(cacheConfiguration(PARTITIONED, TRANSACTIONAL_SNAPSHOT, 1, true));
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testInvokeReadThroughMvccTxReplicated() throws Exception {
+        fail("https://issues.apache.org/jira/browse/IGNITE-8582");
+
+        invokeReadThrough(cacheConfiguration(REPLICATED, TRANSACTIONAL_SNAPSHOT, 0, false));
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testInvokeReadThroughMvccTxLocal() throws Exception {
+        fail("https://issues.apache.org/jira/browse/IGNITE-8582");
+
+        invokeReadThrough(cacheConfiguration(LOCAL, TRANSACTIONAL_SNAPSHOT, 0, false));
+    }
 }
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheInvokeReadThroughTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheInvokeReadThroughTest.java
index 8fd3758..3866a18 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheInvokeReadThroughTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheInvokeReadThroughTest.java
@@ -17,8 +17,11 @@
 
 package org.apache.ignite.internal.processors.cache;
 
+import org.apache.ignite.testframework.MvccFeatureChecker;
+
 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;
 
@@ -27,6 +30,13 @@
  */
 public class IgniteCacheInvokeReadThroughTest extends IgniteCacheInvokeReadThroughAbstractTest {
     /** {@inheritDoc} */
+    @Override public void setUp() throws Exception {
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.CACHE_STORE);
+
+        super.setUp();
+    }
+
+    /** {@inheritDoc} */
     @Override protected void startNodes() throws Exception {
         startGridsMultiThreaded(4);
 
@@ -104,4 +114,49 @@
     public void testInvokeReadThroughTxReplicated() throws Exception {
         invokeReadThrough(cacheConfiguration(REPLICATED, TRANSACTIONAL, 0, false));
     }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testInvokeReadThroughMvccTx0() throws Exception {
+        fail("https://issues.apache.org/jira/browse/IGNITE-8582");
+
+        invokeReadThrough(cacheConfiguration(PARTITIONED, TRANSACTIONAL_SNAPSHOT, 0, false));
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testInvokeReadThroughMvccTx1() throws Exception {
+        fail("https://issues.apache.org/jira/browse/IGNITE-8582");
+
+        invokeReadThrough(cacheConfiguration(PARTITIONED, TRANSACTIONAL_SNAPSHOT, 1, false));
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testInvokeReadThroughMvccTx2() throws Exception {
+        fail("https://issues.apache.org/jira/browse/IGNITE-8582");
+
+        invokeReadThrough(cacheConfiguration(PARTITIONED, TRANSACTIONAL_SNAPSHOT, 2, false));
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testInvokeReadThroughMvccTxNearCache() throws Exception {
+        fail("https://issues.apache.org/jira/browse/IGNITE-8582");
+
+        invokeReadThrough(cacheConfiguration(PARTITIONED, TRANSACTIONAL_SNAPSHOT, 1, true));
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testInvokeReadThroughMvccTxReplicated() throws Exception {
+        fail("https://issues.apache.org/jira/browse/IGNITE-8582");
+
+        invokeReadThrough(cacheConfiguration(REPLICATED, TRANSACTIONAL_SNAPSHOT, 0, false));
+    }
 }
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheReadThroughEvictionSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheReadThroughEvictionSelfTest.java
index 00431b1..fe186b7 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheReadThroughEvictionSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheReadThroughEvictionSelfTest.java
@@ -28,6 +28,7 @@
 import org.apache.ignite.internal.util.typedef.PA;
 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.IgniteCacheConfigVariationsAbstractTest;
 
 import javax.cache.configuration.Factory;
@@ -49,6 +50,13 @@
     private static final int KEYS = 100;
 
     /** {@inheritDoc} */
+    @Override public void setUp() throws Exception {
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.CACHE_STORE);
+
+        super.setUp();
+    }
+
+    /** {@inheritDoc} */
     @Override protected void afterTest() throws Exception {
         storeStgy.resetStore();
     }
@@ -57,6 +65,8 @@
      * @throws Exception if failed.
      */
     public void testReadThroughWithExpirePolicy() throws Exception {
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.EXPIRATION);
+
         Ignite ig = testedGrid();
 
         CacheConfiguration<Object, Object> cc = variationConfig("expire");
@@ -97,6 +107,8 @@
      * @throws Exception if failed.
      */
     public void testReadThroughExpirePolicyConfigured() throws Exception {
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.EXPIRATION);
+
         Ignite ig = testedGrid();
 
         CacheConfiguration<Object, Object> cc = variationConfig("expireConfig");
@@ -150,6 +162,8 @@
      * @throws Exception if failed.
      */
     public void testReadThroughEvictionPolicy() throws Exception {
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.EVICTION);
+
         Ignite ig = testedGrid();
 
         CacheConfiguration<Object, Object> cc = variationConfig("eviction");
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheReadThroughEvictionsVariationsSuite.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheReadThroughEvictionsVariationsSuite.java
index 400b2e9..a390e12 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheReadThroughEvictionsVariationsSuite.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheReadThroughEvictionsVariationsSuite.java
@@ -29,9 +29,8 @@
 public class IgniteCacheReadThroughEvictionsVariationsSuite extends TestSuite {
     /**
      * @return Cache API test suite.
-     * @throws Exception If failed.
      */
-    public static TestSuite suite() throws Exception {
+    public static TestSuite suite() {
         return new ConfigVariationsTestSuiteBuilder(
             "Cache Read Through Variations Test",
             IgniteCacheReadThroughEvictionSelfTest.class)
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheReadThroughStoreCallTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheReadThroughStoreCallTest.java
index 423c4a1..834be7f 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheReadThroughStoreCallTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheReadThroughStoreCallTest.java
@@ -39,6 +39,7 @@
 import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
 import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder;
 import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
+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;
@@ -65,6 +66,13 @@
     protected boolean client;
 
     /** {@inheritDoc} */
+    @Override public void setUp() throws Exception {
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.CACHE_STORE);
+
+        super.setUp();
+    }
+
+    /** {@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/IgniteCacheStoreCollectionTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheStoreCollectionTest.java
index 13841e3..4210822 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheStoreCollectionTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheStoreCollectionTest.java
@@ -32,6 +32,7 @@
 
 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.CacheWriteSynchronizationMode.*;
 
 /**
@@ -41,25 +42,34 @@
     /** */
     private static final TcpDiscoveryIpFinder ipFinder = new TcpDiscoveryVmIpFinder(true);
 
+    /** */
+    private static final String CACHE1 = "cache1";
+
+    /** */
+    private static final String CACHE2 = "cache2";
+
+    /** */
+    private static final String CACHE3 = "cache3";
+
     /** {@inheritDoc} */
     @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception {
         IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName);
 
         ((TcpDiscoverySpi)cfg.getDiscoverySpi()).setIpFinder(ipFinder);
 
-        CacheConfiguration<Object, Object> ccfg1 = new CacheConfiguration<>(DEFAULT_CACHE_NAME);
-        ccfg1.setName("cache1");
+        CacheConfiguration<Object, Object> ccfg1 = new CacheConfiguration<>(CACHE1);
         ccfg1.setAtomicityMode(ATOMIC);
         ccfg1.setWriteSynchronizationMode(FULL_SYNC);
 
-        CacheConfiguration<Object, Object> ccfg2 = new CacheConfiguration<>(DEFAULT_CACHE_NAME);
-        ccfg2.setName("cache2");
+        CacheConfiguration<Object, Object> ccfg2 = new CacheConfiguration<>(CACHE2);
         ccfg2.setAtomicityMode(TRANSACTIONAL);
         ccfg2.setWriteSynchronizationMode(FULL_SYNC);
 
-        cfg.setCacheConfiguration(ccfg1, ccfg2);
+        CacheConfiguration<Object, Object> ccfg3 = new CacheConfiguration<>(CACHE3);
+        ccfg3.setAtomicityMode(TRANSACTIONAL_SNAPSHOT);
+        ccfg3.setWriteSynchronizationMode(FULL_SYNC);
 
-        cfg.setMarshaller(null);
+        cfg.setCacheConfiguration(ccfg1, ccfg2, ccfg3);
 
         return cfg;
     }
@@ -75,11 +85,13 @@
      * @throws Exception If failed.
      */
     public void testStoreMap() throws Exception {
-        IgniteCache<Object, Object> cache1 = ignite(0).cache("cache1");
-        IgniteCache<Object, Object> cache2 = ignite(0).cache("cache2");
+        IgniteCache<Object, Object> cache1 = ignite(0).cache(CACHE1);
+        IgniteCache<Object, Object> cache2 = ignite(0).cache(CACHE2);
+        IgniteCache<Object, Object> cache3 = ignite(0).cache(CACHE3);
 
         checkStoreMap(cache1);
         checkStoreMap(cache2);
+        checkStoreMap(cache3);
     }
 
     /**
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheTxCopyOnReadDisabledTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheTxCopyOnReadDisabledTest.java
index 2909f0a..27bf171 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheTxCopyOnReadDisabledTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheTxCopyOnReadDisabledTest.java
@@ -18,6 +18,7 @@
 package org.apache.ignite.internal.processors.cache;
 
 import org.apache.ignite.cache.CacheAtomicityMode;
+import org.apache.ignite.testframework.MvccFeatureChecker;
 
 import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL;
 
@@ -26,6 +27,12 @@
  */
 public class IgniteCacheTxCopyOnReadDisabledTest extends IgniteCacheCopyOnReadDisabledAbstractTest {
     /** {@inheritDoc} */
+    @Override public void setUp() throws Exception {
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.CACHE_STORE);
+
+        super.setUp();
+    }
+    /** {@inheritDoc} */
     @Override protected CacheAtomicityMode atomicityMode() {
         return TRANSACTIONAL;
     }
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheTxLocalPeekModesTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheTxLocalPeekModesTest.java
index 3439590..26dbb7e 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheTxLocalPeekModesTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheTxLocalPeekModesTest.java
@@ -19,6 +19,7 @@
 
 import org.apache.ignite.cache.CacheAtomicityMode;
 import org.apache.ignite.cache.CacheMode;
+import org.apache.ignite.testframework.MvccFeatureChecker;
 
 import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL;
 import static org.apache.ignite.cache.CacheMode.LOCAL;
@@ -28,6 +29,13 @@
  */
 public class IgniteCacheTxLocalPeekModesTest extends IgniteCachePeekModesAbstractTest {
     /** {@inheritDoc} */
+    @Override public void setUp() throws Exception {
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.LOCAL_CACHE);
+
+        super.setUp();
+    }
+
+    /** {@inheritDoc} */
     @Override protected CacheAtomicityMode atomicityMode() {
         return TRANSACTIONAL;
     }
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheTxLocalStoreValueTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheTxLocalStoreValueTest.java
index b398726..a25fd90 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheTxLocalStoreValueTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheTxLocalStoreValueTest.java
@@ -20,6 +20,7 @@
 import org.apache.ignite.cache.CacheAtomicityMode;
 import org.apache.ignite.cache.CacheMode;
 import org.apache.ignite.configuration.NearCacheConfiguration;
+import org.apache.ignite.testframework.MvccFeatureChecker;
 
 import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL;
 import static org.apache.ignite.cache.CacheMode.LOCAL;
@@ -29,6 +30,13 @@
  */
 public class IgniteCacheTxLocalStoreValueTest extends IgniteCacheStoreValueAbstractTest {
     /** {@inheritDoc} */
+    @Override public void setUp() throws Exception {
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.CACHE_STORE);
+
+        super.setUp();
+    }
+
+    /** {@inheritDoc} */
     @Override protected int gridCount() {
         return 1;
     }
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheTxNearEnabledStoreValueTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheTxNearEnabledStoreValueTest.java
index fc719fa..4dc2cf3 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheTxNearEnabledStoreValueTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheTxNearEnabledStoreValueTest.java
@@ -18,12 +18,20 @@
 package org.apache.ignite.internal.processors.cache;
 
 import org.apache.ignite.configuration.NearCacheConfiguration;
+import org.apache.ignite.testframework.MvccFeatureChecker;
 
 /**
  *
  */
 public class IgniteCacheTxNearEnabledStoreValueTest extends IgniteCacheTxStoreValueTest {
     /** {@inheritDoc} */
+    @Override public void setUp() throws Exception {
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.NEAR_CACHE);
+
+        super.setUp();
+    }
+
+    /** {@inheritDoc} */
     @Override protected NearCacheConfiguration nearConfiguration() {
         return new NearCacheConfiguration();
     }
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheTxNearPeekModesTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheTxNearPeekModesTest.java
index aa4faaf..bd03983 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheTxNearPeekModesTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheTxNearPeekModesTest.java
@@ -17,11 +17,20 @@
 
 package org.apache.ignite.internal.processors.cache;
 
+import org.apache.ignite.testframework.MvccFeatureChecker;
+
 /**
  * Tests peek modes with near tx cache.
  */
 public class IgniteCacheTxNearPeekModesTest extends IgniteCacheTxPeekModesTest {
     /** {@inheritDoc} */
+    @Override public void setUp() throws Exception {
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.NEAR_CACHE);
+
+        super.setUp();
+    }
+
+    /** {@inheritDoc} */
     @Override protected boolean hasNearCache() {
         return true;
     }
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheTxPeekModesTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheTxPeekModesTest.java
index ea22f53..b43ab9a 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheTxPeekModesTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheTxPeekModesTest.java
@@ -19,6 +19,7 @@
 
 import org.apache.ignite.cache.CacheAtomicityMode;
 import org.apache.ignite.cache.CacheMode;
+import org.apache.ignite.testframework.MvccFeatureChecker;
 
 import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL;
 import static org.apache.ignite.cache.CacheMode.PARTITIONED;
@@ -43,10 +44,10 @@
     }
 
     /** {@inheritDoc} */
-    @Override public void testLocalPeek() throws Exception {
-        // TODO: uncomment and re-open ticket if fails.
-//        fail("https://issues.apache.org/jira/browse/IGNITE-1824");
+    @Override public void testLocalEntries() throws Exception {
+         if (MvccFeatureChecker.forcedMvcc())
+             fail("https://issues.apache.org/jira/browse/IGNITE-10167");
 
-        super.testLocalPeek();
+        super.testLocalEntries();
     }
 }
\ No newline at end of file
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheTxStoreValueTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheTxStoreValueTest.java
index f3f52eb..f137e52 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheTxStoreValueTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheTxStoreValueTest.java
@@ -20,6 +20,7 @@
 import org.apache.ignite.cache.CacheAtomicityMode;
 import org.apache.ignite.cache.CacheMode;
 import org.apache.ignite.configuration.NearCacheConfiguration;
+import org.apache.ignite.testframework.MvccFeatureChecker;
 
 import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL;
 import static org.apache.ignite.cache.CacheMode.PARTITIONED;
@@ -29,6 +30,13 @@
  */
 public class IgniteCacheTxStoreValueTest extends IgniteCacheStoreValueAbstractTest {
     /** {@inheritDoc} */
+    @Override public void setUp() throws Exception {
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.INTERCEPTOR);
+
+        super.setUp();
+    }
+
+    /** {@inheritDoc} */
     @Override protected int gridCount() {
         return 4;
     }
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 5432257..c6179fb 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
@@ -39,6 +39,7 @@
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.configuration.NearCacheConfiguration;
 import org.apache.ignite.internal.GridKernalContext;
+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;
@@ -78,12 +79,18 @@
     /** Tx cache name. */
     private static final String TX_CACHE_NAME = "tx-cache";
 
+    /** Mvcc tx cache name. */
+    private static final String MVCC_TX_CACHE_NAME = "mvcc-tx-cache";
+
     /** Near atomic cache name. */
     private static final String NEAR_ATOMIC_CACHE_NAME = "near-atomic-cache";
 
     /** Near tx cache name. */
     private static final String NEAR_TX_CACHE_NAME = "near-tx-cache";
 
+    /** Near mvcc tx cache name. */
+    private static final String NEAR_MVCC_TX_CACHE_NAME = "near-mvcc-tx-cache";
+
     /** Failed caches. */
     private static final Set<String> FAILED_CACHES;
 
@@ -94,6 +101,8 @@
         set.add(TX_CACHE_NAME);
         set.add(NEAR_ATOMIC_CACHE_NAME);
         set.add(NEAR_TX_CACHE_NAME);
+        set.add(MVCC_TX_CACHE_NAME);
+        set.add(NEAR_MVCC_TX_CACHE_NAME);
 
         FAILED_CACHES = Collections.unmodifiableSet(set);
     }
@@ -121,7 +130,13 @@
             ccfg2.setName(TX_CACHE_NAME);
             ccfg2.setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL);
 
-            cfg.setCacheConfiguration(ccfg1, ccfg2);
+            CacheConfiguration<Integer, String> ccfg3 = new CacheConfiguration<>();
+
+            ccfg3.setIndexedTypes(Integer.class, String.class);
+            ccfg3.setName(MVCC_TX_CACHE_NAME);
+            ccfg3.setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL_SNAPSHOT);
+
+            cfg.setCacheConfiguration(ccfg1, ccfg2, ccfg3);
         }
         else {
             GridQueryProcessor.idxCls = FailedIndexing.class;
@@ -149,6 +164,13 @@
     /**
      * @throws Exception If failed.
      */
+    public void testMvccTransactionalCacheInitialization() throws Exception {
+        checkCacheInitialization(MVCC_TX_CACHE_NAME);
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
     public void testAtomicNearCacheInitialization() throws Exception {
         checkCacheInitialization(NEAR_ATOMIC_CACHE_NAME);
     }
@@ -161,6 +183,15 @@
     }
 
     /**
+     * @throws Exception If failed.
+     */
+    public void testMvccTransactionalNearCacheInitialization() throws Exception {
+        fail("https://issues.apache.org/jira/browse/IGNITE-7187");
+
+        checkCacheInitialization(NEAR_MVCC_TX_CACHE_NAME);
+    }
+
+    /**
      * @param cacheName Cache name.
      * @throws Exception If failed.
      */
@@ -198,12 +229,15 @@
                 IgniteCache<Integer, String> cache;
 
                 // Start cache with near enabled.
-                if (NEAR_ATOMIC_CACHE_NAME.equals(cacheName) || NEAR_TX_CACHE_NAME.equals(cacheName)) {
+                if (NEAR_ATOMIC_CACHE_NAME.equals(cacheName) || NEAR_TX_CACHE_NAME.equals(cacheName) ||
+                    NEAR_MVCC_TX_CACHE_NAME.equals(cacheName)) {
                     CacheConfiguration<Integer, String> ccfg = new CacheConfiguration<Integer, String>(cacheName)
                         .setNearConfiguration(new NearCacheConfiguration<Integer, String>());
 
                     if (NEAR_TX_CACHE_NAME.equals(cacheName))
                         ccfg.setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL);
+                    else if (NEAR_MVCC_TX_CACHE_NAME.equals(cacheName))
+                        ccfg.setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL_SNAPSHOT);
 
                     cache = client.getOrCreateCache(ccfg);
                 }
@@ -300,13 +334,14 @@
 
         /** {@inheritDoc} */
         @Override public void registerCache(String cacheName, String schemaName,
-            GridCacheContext<?, ?> cctx) throws IgniteCheckedException {
-            if (FAILED_CACHES.contains(cctx.name()) && cctx.kernalContext().clientNode())
-                throw new IgniteCheckedException("Test query exception " + cctx.name() + " " + new Random().nextInt());
+            GridCacheContextInfo<?, ?> cacheInfo) throws IgniteCheckedException {
+            if (FAILED_CACHES.contains(cacheInfo.name()) && cacheInfo.gridCacheContext().kernalContext().clientNode())
+                throw new IgniteCheckedException("Test query exception " + cacheInfo.name() + " " + new Random().nextInt());
         }
 
         /** {@inheritDoc} */
-        @Override public void unregisterCache(GridCacheContext cctx, boolean rmvIdx) throws IgniteCheckedException {
+        @Override public void unregisterCache(GridCacheContextInfo cacheInfo,
+            boolean rmvIdx) throws IgniteCheckedException {
             // No-op
         }
 
@@ -318,8 +353,7 @@
             return null;
         }
 
-        /** {@inheritDoc} */
-        @Override public boolean registerType(GridCacheContext cctx,
+        @Override public boolean registerType(GridCacheContextInfo cacheInfo,
             GridQueryTypeDescriptor desc, boolean isSql) throws IgniteCheckedException {
             return false;
         }
@@ -336,13 +370,8 @@
         }
 
         /** {@inheritDoc} */
-        @Override public void rebuildIndexesFromHash(String cacheName) throws IgniteCheckedException {
-            // No-op
-        }
-
-        /** {@inheritDoc} */
-        @Override public void markForRebuildFromHash(String cacheName) {
-            // No-op
+        @Override public IgniteInternalFuture<?> rebuildIndexesFromHash(GridCacheContext cctx) {
+            return null;
         }
 
         /** {@inheritDoc} */
@@ -389,5 +418,18 @@
         @Override public GridQueryRowCacheCleaner rowCacheCleaner(int cacheGroupId) {
             return null;
         }
+
+        /** {@inheritDoc} */
+        @Override public GridCacheContextInfo registeredCacheInfo(String cacheName) {
+            return null;
+        }
+
+        /** {@inheritDoc} */
+        @Override public boolean initCacheContext(GridCacheContext ctx) throws IgniteCheckedException {
+            if (FAILED_CACHES.contains(ctx.name()) && ctx.kernalContext().clientNode())
+                throw new IgniteCheckedException("Test query exception " + ctx.name() + " " + new Random().nextInt());
+
+            return true;
+        }
     }
 }
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 fa7d0a8..9ee38c0 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
@@ -35,6 +35,8 @@
 import org.apache.ignite.cluster.ClusterNode;
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.IgniteInternalFuture;
 import org.apache.ignite.internal.IgniteKernal;
 import org.apache.ignite.internal.IgniteNodeAttributes;
@@ -96,6 +98,11 @@
         super.afterTest();
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * @throws Exception If failed.
      */
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteClusterActivateDeactivateTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteClusterActivateDeactivateTest.java
index ed6eb86..cc65ada 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteClusterActivateDeactivateTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteClusterActivateDeactivateTest.java
@@ -1201,13 +1201,13 @@
 
         client = false;
 
-        IgniteInternalFuture startFut1 = GridTestUtils.runAsync((Callable)() -> {
+        IgniteInternalFuture<?> startFut1 = GridTestUtils.runAsync(() -> {
             startGrid(4);
 
             return null;
         }, "start-node1");
 
-        IgniteInternalFuture startFut2 = GridTestUtils.runAsync((Callable)() -> {
+        IgniteInternalFuture<?> startFut2 = GridTestUtils.runAsync(() -> {
             startGrid(5);
 
             return null;
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteDynamicCacheFilterTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteDynamicCacheFilterTest.java
index 53c1cb2..4d74172 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteDynamicCacheFilterTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteDynamicCacheFilterTest.java
@@ -21,6 +21,7 @@
 import java.util.Map;
 import org.apache.ignite.Ignite;
 import org.apache.ignite.IgniteCache;
+import org.apache.ignite.cache.CacheAtomicityMode;
 import org.apache.ignite.cluster.ClusterNode;
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
@@ -60,6 +61,7 @@
         ccfg.setRebalanceMode(SYNC);
 
         ccfg.setNodeFilter(new TestNodeFilter("A"));
+        ccfg.setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL);
 
         if (attrVal != null) {
             Map<String, Object> attrs = new HashMap<>();
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteDynamicCacheStartCoordinatorFailoverTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteDynamicCacheStartCoordinatorFailoverTest.java
index 0b7158d..ce29c31 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteDynamicCacheStartCoordinatorFailoverTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteDynamicCacheStartCoordinatorFailoverTest.java
@@ -27,11 +27,14 @@
 import org.apache.ignite.IgniteCache;

 import org.apache.ignite.IgniteDataStreamer;

 import org.apache.ignite.IgniteException;

+import org.apache.ignite.cache.CacheAtomicityMode;

 import org.apache.ignite.cache.affinity.AffinityFunctionContext;

 import org.apache.ignite.cache.affinity.rendezvous.RendezvousAffinityFunction;

 import org.apache.ignite.cluster.ClusterNode;

 import org.apache.ignite.configuration.CacheConfiguration;

 import org.apache.ignite.configuration.IgniteConfiguration;

+import org.apache.ignite.failure.FailureHandler;

+import org.apache.ignite.failure.NoOpFailureHandler;

 import org.apache.ignite.internal.GridJobExecuteResponse;

 import org.apache.ignite.internal.managers.communication.GridIoMessage;

 import org.apache.ignite.internal.processors.cache.distributed.dht.preloader.GridDhtPartitionsSingleMessage;

@@ -96,6 +99,11 @@
         return cfg;

     }

 

+    /** {@inheritDoc} */

+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {

+        return new NoOpFailureHandler();

+    }

+

     /**

      * Tests coordinator failover during cache start failure.

      *

@@ -118,6 +126,8 @@
 

         cfg.setName("test-coordinator-failover");

 

+        cfg.setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL);

+

         cfg.setAffinity(new BrokenAffinityFunction(false, getTestIgniteInstanceName(2)));

 

         GridTestUtils.runAsync(new Callable<Object>() {

diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteDynamicCacheStartFailWithPersistenceTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteDynamicCacheStartFailWithPersistenceTest.java
index 8643b66..4826119 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteDynamicCacheStartFailWithPersistenceTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteDynamicCacheStartFailWithPersistenceTest.java
@@ -24,6 +24,7 @@
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.configuration.WALMode;
 import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
+import org.apache.ignite.testframework.MvccFeatureChecker;
 
 /**
  * Tests the recovery after a dynamic cache start failure, with enabled persistence.
@@ -57,6 +58,9 @@
 
     /** {@inheritDoc} */
     @Override protected void beforeTestsStarted() throws Exception {
+        if (MvccFeatureChecker.forcedMvcc())
+            fail("https://issues.apache.org/jira/browse/IGNITE-10421");
+
         cleanPersistenceDir();
 
         startGrids(gridCount());
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteDynamicCacheStartNoExchangeTimeoutTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteDynamicCacheStartNoExchangeTimeoutTest.java
index c3e3e88..a00fd24 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteDynamicCacheStartNoExchangeTimeoutTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteDynamicCacheStartNoExchangeTimeoutTest.java
@@ -45,6 +45,7 @@
 
 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.CacheWriteSynchronizationMode.FULL_SYNC;
 
 /**
@@ -400,7 +401,7 @@
         {
             CacheConfiguration ccfg = new CacheConfiguration(DEFAULT_CACHE_NAME);
 
-            ccfg.setName("cache-4");
+            ccfg.setName("cache-6");
             ccfg.setAtomicityMode(TRANSACTIONAL);
             ccfg.setBackups(1);
             ccfg.setWriteSynchronizationMode(FULL_SYNC);
@@ -408,6 +409,39 @@
             res.add(ccfg);
         }
 
+        {
+            CacheConfiguration ccfg = new CacheConfiguration(DEFAULT_CACHE_NAME);
+
+            ccfg.setName("cache-7");
+            ccfg.setAtomicityMode(TRANSACTIONAL_SNAPSHOT);
+            ccfg.setBackups(0);
+            ccfg.setWriteSynchronizationMode(FULL_SYNC);
+
+            res.add(ccfg);
+        }
+
+        {
+            CacheConfiguration ccfg = new CacheConfiguration(DEFAULT_CACHE_NAME);
+
+            ccfg.setName("cache-8");
+            ccfg.setAtomicityMode(TRANSACTIONAL_SNAPSHOT);
+            ccfg.setBackups(1);
+            ccfg.setWriteSynchronizationMode(FULL_SYNC);
+
+            res.add(ccfg);
+        }
+
+        {
+            CacheConfiguration ccfg = new CacheConfiguration(DEFAULT_CACHE_NAME);
+
+            ccfg.setName("cache-9");
+            ccfg.setAtomicityMode(TRANSACTIONAL_SNAPSHOT);
+            ccfg.setBackups(1);
+            ccfg.setWriteSynchronizationMode(FULL_SYNC);
+
+            res.add(ccfg);
+        }
+
         return res;
     }
 
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteDynamicCacheStartSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteDynamicCacheStartSelfTest.java
index 53de23f..b5b83ad 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteDynamicCacheStartSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteDynamicCacheStartSelfTest.java
@@ -281,6 +281,13 @@
     /**
      * @throws Exception If failed.
      */
+    public void testStartStopCacheSimpleTransactionalMvcc() throws Exception {
+        checkStartStopCacheSimple(CacheAtomicityMode.TRANSACTIONAL_SNAPSHOT);
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
     public void testStartStopCacheSimpleAtomic() throws Exception {
         checkStartStopCacheSimple(CacheAtomicityMode.ATOMIC);
     }
@@ -295,6 +302,13 @@
     /**
      * @throws Exception If failed.
      */
+    public void testStartStopCachesSimpleTransactionalMvcc() throws Exception {
+        checkStartStopCachesSimple(CacheAtomicityMode.TRANSACTIONAL_SNAPSHOT);
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
     public void testStartStopCachesSimpleAtomic() throws Exception {
         checkStartStopCachesSimple(CacheAtomicityMode.ATOMIC);
     }
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteDynamicCacheWithConfigStartSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteDynamicCacheWithConfigStartSelfTest.java
index ec6b82d..d366306 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteDynamicCacheWithConfigStartSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteDynamicCacheWithConfigStartSelfTest.java
@@ -17,6 +17,7 @@
 
 package org.apache.ignite.internal.processors.cache;
 
+import org.apache.ignite.cache.CacheAtomicityMode;
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.internal.IgniteEx;
@@ -63,6 +64,7 @@
         CacheConfiguration<Object, Object> ccfg = new CacheConfiguration<>(CACHE_NAME);
 
         ccfg.setIndexedTypes(String.class, String.class);
+        ccfg.setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL);
 
         return ccfg;
     }
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteDynamicClientCacheStartSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteDynamicClientCacheStartSelfTest.java
index 0cb0856..69bf233 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteDynamicClientCacheStartSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteDynamicClientCacheStartSelfTest.java
@@ -44,7 +44,10 @@
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
 import org.jetbrains.annotations.Nullable;
 
-import static org.apache.ignite.cache.CacheAtomicityMode.*;
+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.CacheAtomicityMode.values;
 import static org.apache.ignite.cache.CacheMode.REPLICATED;
 import static org.apache.ignite.cache.CacheWriteSynchronizationMode.FULL_SYNC;
 import static org.apache.ignite.internal.IgniteNodeAttributes.ATTR_IGNITE_INSTANCE_NAME;
@@ -394,8 +397,9 @@
 
         cfgs.addAll(cacheConfigurations(null, ATOMIC));
         cfgs.addAll(cacheConfigurations(null, TRANSACTIONAL));
+        cfgs.addAll(cacheConfigurations(null, TRANSACTIONAL_SNAPSHOT));
 
-        assertEquals(6, cfgs.size());
+        assertEquals(9, cfgs.size());
 
         Collection<IgniteCache> caches = client.getOrCreateCaches(cfgs);
 
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteGetNonPlainKeyReadThroughSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteGetNonPlainKeyReadThroughSelfTest.java
new file mode 100644
index 0000000..21b09fc
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteGetNonPlainKeyReadThroughSelfTest.java
@@ -0,0 +1,155 @@
+/*
+ * 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.cache;
+
+import java.io.Serializable;
+import javax.cache.Cache;
+import javax.cache.configuration.Factory;
+import javax.cache.integration.CacheLoaderException;
+import javax.cache.integration.CacheWriterException;
+import org.apache.ignite.Ignite;
+import org.apache.ignite.cache.CacheMode;
+import org.apache.ignite.cache.store.CacheStore;
+import org.apache.ignite.cache.store.CacheStoreAdapter;
+import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.internal.IgniteKernal;
+import org.apache.ignite.internal.binary.BinaryUtils;
+import org.apache.ignite.lang.IgniteBiTuple;
+import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
+import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder;
+import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+
+/**
+ * Tests read through for non-{@link BinaryUtils#BINARY_CLS} keys.
+ */
+public class IgniteGetNonPlainKeyReadThroughSelfTest extends GridCommonAbstractTest {
+    /** */
+    private static final TcpDiscoveryIpFinder ipFinder = new TcpDiscoveryVmIpFinder(true);
+
+    private StoreFactory storeFactory;
+
+    /** {@inheritDoc} */
+    @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception {
+        IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName);
+
+        ((TcpDiscoverySpi)cfg.getDiscoverySpi()).setIpFinder(ipFinder);
+
+        CacheConfiguration ccfg = new CacheConfiguration(DEFAULT_CACHE_NAME);
+
+        ccfg.setCacheMode(CacheMode.PARTITIONED);
+
+        ccfg.setReadThrough(true);
+
+        ccfg.setCacheStoreFactory(storeFactory);
+
+        cfg.setCacheConfiguration(ccfg);
+
+        return cfg;
+    }
+
+    private static class StoreFactory implements Factory<CacheStore<Object, Object>> {
+        private boolean nullVal;
+
+        public StoreFactory(boolean nullVal) {
+            this.nullVal = nullVal;
+        }
+
+        /** {@inheritDoc} */
+        @Override public CacheStore<Object, Object> create() {
+            if (nullVal)
+                return new IgniteGetNonPlainKeyReadThroughSelfTest.Store(true);
+            else
+                return new IgniteGetNonPlainKeyReadThroughSelfTest.Store(false);
+        }
+    }
+
+    /**
+     *
+     */
+    private static class Store extends CacheStoreAdapter<Object, Object> implements Serializable {
+        private boolean nullVal;
+
+        public Store(boolean nullVal) {
+            this.nullVal = nullVal;
+        }
+
+        /** {@inheritDoc} */
+        @Override public Object load(Object key) throws CacheLoaderException {
+            if (nullVal)
+                return null;
+            else
+                return key;
+        }
+
+        /** {@inheritDoc} */
+        @Override public void write(Cache.Entry e)
+            throws CacheWriterException {
+            // No-op.
+        }
+
+        /** {@inheritDoc} */
+        @Override public void delete(Object key) throws CacheWriterException {
+            // No-op.
+        }
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testGetNullRead() throws Exception {
+        storeFactory = new StoreFactory(true);
+
+        testGet(true);
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testGetValueRead() throws Exception {
+        storeFactory = new StoreFactory(false);
+
+        testGet(false);
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    private void testGet(boolean nullRead) throws Exception {
+        try {
+            final Ignite ignite = startGrid();
+
+            final GridCacheAdapter cache = ((IgniteKernal)grid()).internalCache(DEFAULT_CACHE_NAME);
+
+            IgniteBiTuple<String, String> key = new IgniteBiTuple<>();
+
+            if (nullRead) {
+                assertEquals(null, cache.get("key"));
+                assertEquals(null, cache.get(key));
+            }
+            else {
+                assertEquals("key", cache.get("key"));
+                assertEquals(key, cache.get(key));
+            }
+        }
+        finally {
+            stopAllGrids();
+        }
+    }
+}
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteStartCacheInTransactionSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteStartCacheInTransactionSelfTest.java
index b037a7b..f4d3b25 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteStartCacheInTransactionSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteStartCacheInTransactionSelfTest.java
@@ -30,6 +30,7 @@
 import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder;
 import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
 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;
 
@@ -250,6 +251,8 @@
         if (atomicityMode() != TRANSACTIONAL)
             return;
 
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.ENTRY_LOCK);
+
         final Ignite ignite = grid(0);
 
         final String key = "key";
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteTopologyValidatorAbstractCacheTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteTopologyValidatorAbstractCacheTest.java
index bb61632..2902695 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteTopologyValidatorAbstractCacheTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteTopologyValidatorAbstractCacheTest.java
@@ -29,6 +29,8 @@
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.configuration.TopologyValidator;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.util.typedef.G;
 import org.apache.ignite.transactions.Transaction;
 
@@ -89,6 +91,11 @@
         return cfg;
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * @param nodes Nodes.
      * @return Number of server nodes.
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 ac294b0..8cb03c6 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
@@ -32,6 +32,8 @@
 import org.apache.ignite.cluster.ClusterNode;
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.IgniteKernal;
 import org.apache.ignite.internal.processors.cache.distributed.near.GridNearCacheAdapter;
 import org.apache.ignite.internal.transactions.IgniteTxHeuristicCheckedException;
@@ -128,6 +130,11 @@
         lastKey = 0;
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * @throws Exception If failed.
      */
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/regressions/logistic/binomial/package-info.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/MvccCacheGroupMetricsMBeanTest.java
similarity index 69%
copy from modules/ml/src/main/java/org/apache/ignite/ml/regressions/logistic/binomial/package-info.java
copy to modules/core/src/test/java/org/apache/ignite/internal/processors/cache/MvccCacheGroupMetricsMBeanTest.java
index d32b1ee..2642eb5 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/regressions/logistic/binomial/package-info.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/MvccCacheGroupMetricsMBeanTest.java
@@ -14,9 +14,16 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package org.apache.ignite.internal.processors.cache;
+
+import org.apache.ignite.cache.CacheAtomicityMode;
 
 /**
- * <!-- Package description. -->
- * Contains binomial logistic regression.
+ *
  */
-package org.apache.ignite.ml.regressions.logistic.binomial;
\ No newline at end of file
+public class MvccCacheGroupMetricsMBeanTest extends CacheGroupMetricsMBeanTest {
+    /** {@inheritDoc} */
+    @Override protected CacheAtomicityMode atomicityMode() {
+        return CacheAtomicityMode.TRANSACTIONAL_SNAPSHOT;
+    }
+}
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/PartitionedAtomicCacheGetsDistributionTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/PartitionedAtomicCacheGetsDistributionTest.java
index 2241a95..963ccc8 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/PartitionedAtomicCacheGetsDistributionTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/PartitionedAtomicCacheGetsDistributionTest.java
@@ -17,33 +17,23 @@
 
 package org.apache.ignite.internal.processors.cache;
 
+import org.apache.ignite.cache.CacheAtomicityMode;
 import org.apache.ignite.cache.CacheMode;
-import org.apache.ignite.configuration.CacheConfiguration;
 
+import static org.apache.ignite.cache.CacheAtomicityMode.ATOMIC;
 import static org.apache.ignite.cache.CacheMode.PARTITIONED;
 
 /**
  * Tests of partitioned atomic cache's 'get' requests distribution.
  */
-public class PartitionedAtomicCacheGetsDistributionTest extends ReplicatedAtomicCacheGetsDistributionTest {
+public class PartitionedAtomicCacheGetsDistributionTest extends CacheGetsDistributionAbstractTest {
+    /** {@inheritDoc} */
+    @Override protected CacheAtomicityMode atomicityMode() {
+        return ATOMIC;
+    }
+
     /** {@inheritDoc} */
     @Override protected CacheMode cacheMode() {
         return PARTITIONED;
     }
-
-    /** {@inheritDoc} */
-    @Override protected <K, V> CacheConfiguration<K, V> cacheConfiguration() {
-        CacheConfiguration<K, V> cacheCfg = super.cacheConfiguration();
-
-        cacheCfg.setBackups(backupsCount());
-
-        return cacheCfg;
-    }
-
-    /**
-     * @return Backups count.
-     */
-    protected int backupsCount() {
-        return gridCount() - 1;
-    }
 }
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheGetEntryOptimisticSerializableSeltTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/PartitionedMvccTxPessimisticCacheGetsDistributionTest.java
similarity index 68%
copy from modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheGetEntryOptimisticSerializableSeltTest.java
copy to modules/core/src/test/java/org/apache/ignite/internal/processors/cache/PartitionedMvccTxPessimisticCacheGetsDistributionTest.java
index 6ded4a9..de9d9a6 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheGetEntryOptimisticSerializableSeltTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/PartitionedMvccTxPessimisticCacheGetsDistributionTest.java
@@ -17,20 +17,16 @@
 
 package org.apache.ignite.internal.processors.cache;
 
-import org.apache.ignite.transactions.TransactionConcurrency;
 import org.apache.ignite.transactions.TransactionIsolation;
 
-/**
- * Test getEntry and getEntries methods.
- */
-public class CacheGetEntryOptimisticSerializableSeltTest extends CacheGetEntryAbstractTest {
-    /** {@inheritDoc} */
-    @Override protected TransactionConcurrency concurrency() {
-        return TransactionConcurrency.OPTIMISTIC;
-    }
+import static org.apache.ignite.transactions.TransactionIsolation.REPEATABLE_READ;
 
+/**
+ * Tests of pessimistic transactional partitioned cache's 'get' requests distribution.
+ */
+public class PartitionedMvccTxPessimisticCacheGetsDistributionTest extends PartitionedTransactionalPessimisticCacheGetsDistributionTest {
     /** {@inheritDoc} */
-    @Override protected TransactionIsolation isolation() {
-        return TransactionIsolation.SERIALIZABLE;
+    @Override protected TransactionIsolation transactionIsolation() {
+        return REPEATABLE_READ;
     }
 }
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/PartitionedTransactionalOptimisticCacheGetsDistributionTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/PartitionedTransactionalOptimisticCacheGetsDistributionTest.java
index 4c88229..e518e32 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/PartitionedTransactionalOptimisticCacheGetsDistributionTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/PartitionedTransactionalOptimisticCacheGetsDistributionTest.java
@@ -18,29 +18,36 @@
 package org.apache.ignite.internal.processors.cache;
 
 import org.apache.ignite.cache.CacheAtomicityMode;
+import org.apache.ignite.cache.CacheMode;
 import org.apache.ignite.transactions.TransactionConcurrency;
 import org.apache.ignite.transactions.TransactionIsolation;
 
 import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL;
+import static org.apache.ignite.cache.CacheMode.PARTITIONED;
 import static org.apache.ignite.transactions.TransactionConcurrency.OPTIMISTIC;
 import static org.apache.ignite.transactions.TransactionIsolation.READ_COMMITTED;
 
 /**
  * Tests of optimistic transactional partitioned cache's 'get' requests distribution.
  */
-public class PartitionedTransactionalOptimisticCacheGetsDistributionTest extends PartitionedAtomicCacheGetsDistributionTest {
+public class PartitionedTransactionalOptimisticCacheGetsDistributionTest extends CacheGetsDistributionAbstractTest {
+    /** {@inheritDoc} */
+    @Override protected CacheMode cacheMode() {
+        return PARTITIONED;
+    }
+
     /** {@inheritDoc} */
     @Override protected CacheAtomicityMode atomicityMode() {
         return TRANSACTIONAL;
     }
 
     /** {@inheritDoc} */
-    @Override protected TransactionIsolation transactionIsolation() {
-        return READ_COMMITTED;
+    @Override protected TransactionConcurrency transactionConcurrency() {
+        return OPTIMISTIC;
     }
 
     /** {@inheritDoc} */
-    @Override protected TransactionConcurrency transactionConcurrency() {
-        return OPTIMISTIC;
+    @Override protected TransactionIsolation transactionIsolation() {
+        return READ_COMMITTED;
     }
 }
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/PartitionedTransactionalPessimisticCacheGetsDistributionTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/PartitionedTransactionalPessimisticCacheGetsDistributionTest.java
index 78ea7a6..ce1f7b6 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/PartitionedTransactionalPessimisticCacheGetsDistributionTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/PartitionedTransactionalPessimisticCacheGetsDistributionTest.java
@@ -17,17 +17,37 @@
 
 package org.apache.ignite.internal.processors.cache;
 
+import org.apache.ignite.cache.CacheAtomicityMode;
+import org.apache.ignite.cache.CacheMode;
 import org.apache.ignite.transactions.TransactionConcurrency;
+import org.apache.ignite.transactions.TransactionIsolation;
 
+import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL;
+import static org.apache.ignite.cache.CacheMode.PARTITIONED;
 import static org.apache.ignite.transactions.TransactionConcurrency.PESSIMISTIC;
+import static org.apache.ignite.transactions.TransactionIsolation.READ_COMMITTED;
 
 /**
  * Tests of pessimistic transactional partitioned cache's 'get' requests distribution.
  */
-public class PartitionedTransactionalPessimisticCacheGetsDistributionTest
-    extends PartitionedTransactionalOptimisticCacheGetsDistributionTest {
+public class PartitionedTransactionalPessimisticCacheGetsDistributionTest extends CacheGetsDistributionAbstractTest {
+    /** {@inheritDoc} */
+    @Override protected CacheMode cacheMode() {
+        return PARTITIONED;
+    }
+
+    /** {@inheritDoc} */
+    @Override protected CacheAtomicityMode atomicityMode() {
+        return TRANSACTIONAL;
+    }
+
     /** {@inheritDoc} */
     @Override protected TransactionConcurrency transactionConcurrency() {
         return PESSIMISTIC;
     }
+
+    /** {@inheritDoc} */
+    @Override protected TransactionIsolation transactionIsolation() {
+        return READ_COMMITTED;
+    }
 }
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/PartitionsExchangeCoordinatorFailoverTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/PartitionsExchangeCoordinatorFailoverTest.java
index 1c847f9..9980753 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/PartitionsExchangeCoordinatorFailoverTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/PartitionsExchangeCoordinatorFailoverTest.java
@@ -24,6 +24,8 @@
 import org.apache.ignite.cluster.ClusterNode;
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.IgniteEx;
 import org.apache.ignite.internal.IgniteInternalFuture;
 import org.apache.ignite.internal.TestRecordingCommunicationSpi;
@@ -72,6 +74,11 @@
         return 60 * 1000L;
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * Tests that new coordinator is able to finish old exchanges in case of in-complete coordinator initialization.
      */
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/ReplicatedAtomicCacheGetsDistributionTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/ReplicatedAtomicCacheGetsDistributionTest.java
index 1aaea76..ef90408e4a2 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/ReplicatedAtomicCacheGetsDistributionTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/ReplicatedAtomicCacheGetsDistributionTest.java
@@ -17,350 +17,23 @@
 
 package org.apache.ignite.internal.processors.cache;
 
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeSet;
-import java.util.UUID;
-import org.apache.ignite.Ignite;
-import org.apache.ignite.IgniteCache;
 import org.apache.ignite.cache.CacheAtomicityMode;
 import org.apache.ignite.cache.CacheMode;
-import org.apache.ignite.cluster.ClusterNode;
-import org.apache.ignite.configuration.CacheConfiguration;
-import org.apache.ignite.configuration.IgniteConfiguration;
-import org.apache.ignite.configuration.TransactionConfiguration;
-import org.apache.ignite.internal.IgniteEx;
-import org.apache.ignite.internal.util.lang.GridAbsPredicate;
-import org.apache.ignite.internal.util.typedef.G;
-import org.apache.ignite.spi.discovery.tcp.internal.TcpDiscoveryNode;
-import org.apache.ignite.testframework.GridTestUtils;
-import org.apache.ignite.transactions.Transaction;
-import org.apache.ignite.transactions.TransactionConcurrency;
-import org.apache.ignite.transactions.TransactionIsolation;
 
 import static org.apache.ignite.cache.CacheAtomicityMode.ATOMIC;
 import static org.apache.ignite.cache.CacheMode.REPLICATED;
-import static org.apache.ignite.cache.CacheWriteSynchronizationMode.FULL_SYNC;
-import static org.apache.ignite.internal.IgniteNodeAttributes.ATTR_MACS;
-import static org.apache.ignite.transactions.TransactionConcurrency.PESSIMISTIC;
-import static org.apache.ignite.transactions.TransactionIsolation.REPEATABLE_READ;
 
 /**
  * Tests of replicated cache's 'get' requests distribution.
  */
-public class ReplicatedAtomicCacheGetsDistributionTest extends GridCacheAbstractSelfTest {
-    /** Cache name. */
-    private static final String CACHE_NAME = "getsDistributionTest";
-
-    /** Client nodes instance's name. */
-    private static final String CLIENT_NAME = "client";
-
-    /** Value prefix. */
-    private static final String VAL_PREFIX = "val";
-
-    /** */
-    private static final int PRIMARY_KEYS_NUMBER = 1_000;
-
-    /** {@inheritDoc} */
-    @Override protected void beforeTestsStarted() throws Exception {
-        super.beforeTestsStarted();
-
-        IgniteConfiguration clientCfg = getConfiguration(CLIENT_NAME);
-
-        clientCfg.setClientMode(true);
-
-        startGrid(clientCfg);
-    }
-
-    /** {@inheritDoc} */
-    @Override protected void beforeTest() throws Exception {
-        super.beforeTest();
-
-        IgniteCache cache = ignite(0).cache(CACHE_NAME);
-
-        if (cache != null)
-            cache.destroy();
-
-        // Setting different MAC addresses for all nodes
-        Map<UUID, String> macs = getClusterMacs();
-
-        int idx = 0;
-
-        for (Map.Entry<UUID, String> entry : macs.entrySet())
-            entry.setValue("x2-xx-xx-xx-xx-x" + idx++);
-
-        replaceMacAddresses(G.allGrids(), macs);
-    }
-
-    /** {@inheritDoc} */
-    @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception {
-        IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName);
-
-        cfg.setTransactionConfiguration(transactionConfiguration());
-
-        return cfg;
-    }
-
+public class ReplicatedAtomicCacheGetsDistributionTest extends CacheGetsDistributionAbstractTest {
     /** {@inheritDoc} */
     @Override protected CacheAtomicityMode atomicityMode() {
         return ATOMIC;
     }
 
     /** {@inheritDoc} */
-    @Override protected int gridCount() {
-        return 4;
-    }
-
-    /**
-     * Test 'get' operations requests generator distribution.
-     *
-     * @throws Exception In case of an error.
-     * @see #runTestBalancingDistribution(boolean)
-     */
-    public void testGetRequestsGeneratorDistribution() throws Exception {
-        runTestBalancingDistribution(false);
-    }
-
-    /**
-     * Test 'getAll' operations requests generator distribution.
-     *
-     * @throws Exception In case of an error.
-     * @see #runTestBalancingDistribution(boolean)
-     */
-    public void testGetAllRequestsGeneratorDistribution() throws Exception {
-        runTestBalancingDistribution(true);
-    }
-
-    /**
-     * @param batchMode Whenever 'get' or 'getAll' operations are used in the test.
-     * @throws Exception In case of an error.
-     */
-    protected void runTestBalancingDistribution(boolean batchMode) throws Exception {
-        IgniteCache<Integer, String> cache = grid(0).createCache(cacheConfiguration());
-
-        List<Integer> keys = primaryKeys(cache, PRIMARY_KEYS_NUMBER);
-
-        for (Integer key : keys)
-            cache.put(key, VAL_PREFIX + key);
-
-        IgniteCache<Integer, String> clientCache = grid(CLIENT_NAME).getOrCreateCache(CACHE_NAME)
-            .withAllowAtomicOpsInTx();
-
-        assertTrue(GridTestUtils.waitForCondition(
-            new GridAbsPredicate() {
-                int batchSize = 10;
-                int idx = 0;
-
-                @Override public boolean apply() {
-                    if (idx >= PRIMARY_KEYS_NUMBER)
-                        idx = 0;
-
-                    try (Transaction tx = grid(CLIENT_NAME).transactions().txStart()) {
-                        if (batchMode) {
-                            Set<Integer> keys0 = new TreeSet<>();
-
-                            for (int i = idx; i < idx + batchSize && i < PRIMARY_KEYS_NUMBER; i++)
-                                keys0.add(keys.get(i));
-
-                            idx += batchSize;
-
-                            Map<Integer, String> results = clientCache.getAll(keys0);
-
-                            for (Map.Entry<Integer, String> entry : results.entrySet())
-                                assertEquals(VAL_PREFIX + entry.getKey(), entry.getValue());
-                        }
-                        else {
-                            for (int i = idx; i < idx + gridCount() && i < PRIMARY_KEYS_NUMBER; i++) {
-                                Integer key = keys.get(i);
-
-                                assertEquals(VAL_PREFIX + key, clientCache.get(key));
-                            }
-
-                            idx += gridCount();
-                        }
-
-                        tx.commit();
-                    }
-
-                    for (int i = 0; i < gridCount(); i++) {
-                        IgniteEx ignite = grid(i);
-
-                        long getsCnt = ignite.cache(CACHE_NAME).localMetrics().getCacheGets();
-
-                        if (getsCnt == 0)
-                            return false;
-                    }
-
-                    return true;
-                }
-            },
-            getTestTimeout())
-        );
-    }
-
-    /**
-     * Tests that the 'get' operation requests are routed to node with same MAC address as at requester.
-     *
-     * @throws Exception In case of an error.
-     * @see #runTestSameHostDistribution(UUID, boolean)
-     */
-    public void testGetRequestsDistribution() throws Exception {
-        UUID destId = grid(0).localNode().id();
-
-        runTestSameHostDistribution(destId, false);
-    }
-
-    /**
-     * Tests that the 'getAll' operation requests are routed to node with same MAC address as at requester.
-     *
-     * @throws Exception In case of an error.
-     * @see #runTestSameHostDistribution(UUID, boolean)
-     */
-    public void testGetAllRequestsDistribution() throws Exception {
-        UUID destId = grid(gridCount() - 1).localNode().id();
-
-        runTestSameHostDistribution(destId, true);
-    }
-
-    /**
-     * Tests that the 'get' and 'getAll' requests are routed to node with same MAC address as at requester.
-     *
-     * @param destId Destination Ignite instance id for requests distribution.
-     * @param batchMode Test mode.
-     * @throws Exception In case of an error.
-     */
-    protected void runTestSameHostDistribution(final UUID destId, final boolean batchMode) throws Exception {
-        Map<UUID, String> macs = getClusterMacs();
-
-        String clientMac = macs.get(grid(CLIENT_NAME).localNode().id());
-
-        macs.put(destId, clientMac);
-
-        replaceMacAddresses(G.allGrids(), macs);
-
-        IgniteCache<Integer, String> cache = grid(0).createCache(cacheConfiguration());
-
-        List<Integer> keys = primaryKeys(cache, PRIMARY_KEYS_NUMBER);
-
-        for (Integer key : keys)
-            cache.put(key, VAL_PREFIX + key);
-
-        IgniteCache<Integer, String> clientCache = grid(CLIENT_NAME).getOrCreateCache(CACHE_NAME)
-            .withAllowAtomicOpsInTx();
-
-        try (Transaction tx = grid(CLIENT_NAME).transactions().txStart()) {
-            if (batchMode) {
-                Map<Integer, String> results = clientCache.getAll(new TreeSet<>(keys));
-
-                for (Map.Entry<Integer, String> entry : results.entrySet())
-                    assertEquals(VAL_PREFIX + entry.getKey(), entry.getValue());
-            }
-            else {
-                for (Integer key : keys)
-                    assertEquals(VAL_PREFIX + key, clientCache.get(key));
-            }
-
-            tx.commit();
-        }
-
-        for (int i = 0; i < gridCount(); i++) {
-            IgniteEx ignite = grid(i);
-
-            long getsCnt = ignite.cache(CACHE_NAME).localMetrics().getCacheGets();
-
-            if (destId.equals(ignite.localNode().id()))
-                assertEquals(PRIMARY_KEYS_NUMBER, getsCnt);
-            else
-                assertEquals(0L, getsCnt);
-        }
-    }
-
-    /**
-     * @return Transaction configuration.
-     */
-    protected TransactionConfiguration transactionConfiguration() {
-        TransactionConfiguration txCfg = new TransactionConfiguration();
-
-        txCfg.setDefaultTxIsolation(transactionIsolation());
-        txCfg.setDefaultTxConcurrency(transactionConcurrency());
-
-        return txCfg;
-    }
-
-    /**
-     * @return Cache transaction isolation.
-     */
-    protected TransactionIsolation transactionIsolation() {
-        return REPEATABLE_READ;
-    }
-
-    /**
-     * @return Cache transaction concurrency.
-     */
-    protected TransactionConcurrency transactionConcurrency() {
-        return PESSIMISTIC;
-    }
-
-    /**
-     * @return Caching mode.
-     */
     @Override protected CacheMode cacheMode() {
         return REPLICATED;
     }
-
-    /**
-     * @return Cache configuration.
-     */
-    protected <K, V> CacheConfiguration<K, V> cacheConfiguration() {
-        CacheConfiguration<K, V> cfg = new CacheConfiguration<K, V>(CACHE_NAME);
-
-        cfg.setCacheMode(cacheMode());
-        cfg.setAtomicityMode(atomicityMode());
-        cfg.setWriteSynchronizationMode(FULL_SYNC);
-        cfg.setReadFromBackup(true);
-        cfg.setStatisticsEnabled(true);
-
-        return cfg;
-    }
-
-    /**
-     * @param instances Started Ignite instances.
-     * @param macs Mapping MAC addresses to UUID.
-     */
-    private void replaceMacAddresses(List<Ignite> instances, Map<UUID, String> macs) {
-        for (Ignite ignite : instances) {
-            for (ClusterNode node : ignite.cluster().nodes()) {
-                String mac = macs.get(node.id());
-
-                assertNotNull(mac);
-
-                Map<String, Object> attrs = new HashMap<>(node.attributes());
-
-                attrs.put(ATTR_MACS, mac);
-
-                ((TcpDiscoveryNode)node).setAttributes(attrs);
-            }
-        }
-    }
-
-    /**
-     * @return Cluster nodes MAC addresses.
-     */
-    private Map<UUID, String> getClusterMacs() {
-        Map<UUID, String> macs = new HashMap<>();
-
-        for (Ignite ignite : G.allGrids()) {
-            ClusterNode node = ignite.cluster().localNode();
-
-            String mac = node.attribute(ATTR_MACS);
-
-            assert mac != null;
-
-            macs.put(node.id(), mac);
-        }
-
-        return macs;
-    }
 }
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheGetEntryOptimisticSerializableSeltTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/ReplicatedMvccTxPessimisticCacheGetsDistributionTest.java
similarity index 68%
copy from modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheGetEntryOptimisticSerializableSeltTest.java
copy to modules/core/src/test/java/org/apache/ignite/internal/processors/cache/ReplicatedMvccTxPessimisticCacheGetsDistributionTest.java
index 6ded4a9..6e2d67c 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheGetEntryOptimisticSerializableSeltTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/ReplicatedMvccTxPessimisticCacheGetsDistributionTest.java
@@ -17,20 +17,16 @@
 
 package org.apache.ignite.internal.processors.cache;
 
-import org.apache.ignite.transactions.TransactionConcurrency;
 import org.apache.ignite.transactions.TransactionIsolation;
 
-/**
- * Test getEntry and getEntries methods.
- */
-public class CacheGetEntryOptimisticSerializableSeltTest extends CacheGetEntryAbstractTest {
-    /** {@inheritDoc} */
-    @Override protected TransactionConcurrency concurrency() {
-        return TransactionConcurrency.OPTIMISTIC;
-    }
+import static org.apache.ignite.transactions.TransactionIsolation.REPEATABLE_READ;
 
+/**
+ * Tests of pessimistic transactional replicated cache's 'get' requests distribution.
+ */
+public class ReplicatedMvccTxPessimisticCacheGetsDistributionTest extends ReplicatedTransactionalPessimisticCacheGetsDistributionTest {
     /** {@inheritDoc} */
-    @Override protected TransactionIsolation isolation() {
-        return TransactionIsolation.SERIALIZABLE;
+    @Override protected TransactionIsolation transactionIsolation() {
+        return REPEATABLE_READ;
     }
 }
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/ReplicatedTransactionalOptimisticCacheGetsDistributionTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/ReplicatedTransactionalOptimisticCacheGetsDistributionTest.java
index 3bc6809..4744f0a 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/ReplicatedTransactionalOptimisticCacheGetsDistributionTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/ReplicatedTransactionalOptimisticCacheGetsDistributionTest.java
@@ -18,17 +18,24 @@
 package org.apache.ignite.internal.processors.cache;
 
 import org.apache.ignite.cache.CacheAtomicityMode;
+import org.apache.ignite.cache.CacheMode;
 import org.apache.ignite.transactions.TransactionConcurrency;
 import org.apache.ignite.transactions.TransactionIsolation;
 
 import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL;
+import static org.apache.ignite.cache.CacheMode.REPLICATED;
 import static org.apache.ignite.transactions.TransactionConcurrency.OPTIMISTIC;
 import static org.apache.ignite.transactions.TransactionIsolation.READ_COMMITTED;
 
 /**
  * Tests of optimistic transactional replicated cache's 'get' requests distribution.
  */
-public class ReplicatedTransactionalOptimisticCacheGetsDistributionTest extends ReplicatedAtomicCacheGetsDistributionTest {
+public class ReplicatedTransactionalOptimisticCacheGetsDistributionTest extends CacheGetsDistributionAbstractTest {
+    /** {@inheritDoc} */
+    @Override protected CacheMode cacheMode() {
+        return REPLICATED;
+    }
+
     /** {@inheritDoc} */
     @Override protected CacheAtomicityMode atomicityMode() {
         return TRANSACTIONAL;
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/ReplicatedTransactionalPessimisticCacheGetsDistributionTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/ReplicatedTransactionalPessimisticCacheGetsDistributionTest.java
index 7bace3c..2648851 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/ReplicatedTransactionalPessimisticCacheGetsDistributionTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/ReplicatedTransactionalPessimisticCacheGetsDistributionTest.java
@@ -17,17 +17,37 @@
 
 package org.apache.ignite.internal.processors.cache;
 
+import org.apache.ignite.cache.CacheAtomicityMode;
+import org.apache.ignite.cache.CacheMode;
 import org.apache.ignite.transactions.TransactionConcurrency;
+import org.apache.ignite.transactions.TransactionIsolation;
 
+import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL;
+import static org.apache.ignite.cache.CacheMode.REPLICATED;
 import static org.apache.ignite.transactions.TransactionConcurrency.PESSIMISTIC;
+import static org.apache.ignite.transactions.TransactionIsolation.READ_COMMITTED;
 
 /**
  * Tests of pessimistic transactional replicated cache's 'get' requests distribution.
  */
-public class ReplicatedTransactionalPessimisticCacheGetsDistributionTest
-    extends ReplicatedTransactionalOptimisticCacheGetsDistributionTest {
+public class ReplicatedTransactionalPessimisticCacheGetsDistributionTest extends CacheGetsDistributionAbstractTest {
+    /** {@inheritDoc} */
+    @Override protected CacheMode cacheMode() {
+        return REPLICATED;
+    }
+
+    /** {@inheritDoc} */
+    @Override protected CacheAtomicityMode atomicityMode() {
+        return TRANSACTIONAL;
+    }
+
     /** {@inheritDoc} */
     @Override protected TransactionConcurrency transactionConcurrency() {
         return PESSIMISTIC;
     }
+
+    /** {@inheritDoc} */
+    @Override protected TransactionIsolation transactionIsolation() {
+        return READ_COMMITTED;
+    }
 }
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/SetTxTimeoutOnPartitionMapExchangeTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/SetTxTimeoutOnPartitionMapExchangeTest.java
index 490b640..856a89b 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/SetTxTimeoutOnPartitionMapExchangeTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/SetTxTimeoutOnPartitionMapExchangeTest.java
@@ -32,6 +32,8 @@
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.configuration.TransactionConfiguration;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.IgniteEx;
 import org.apache.ignite.internal.IgniteInternalFuture;
 import org.apache.ignite.internal.IgniteInterruptedCheckedException;
@@ -80,6 +82,11 @@
         return cfg;
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      *
      */
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/WalModeChangeAbstractSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/WalModeChangeAbstractSelfTest.java
index 8c8ce53..467d6ff 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/WalModeChangeAbstractSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/WalModeChangeAbstractSelfTest.java
@@ -27,6 +27,7 @@
 import org.apache.ignite.internal.IgniteEx;
 import org.apache.ignite.internal.util.lang.IgniteInClosureX;
 import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.testframework.MvccFeatureChecker;
 
 import static org.apache.ignite.cache.CacheAtomicityMode.ATOMIC;
 import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL;
@@ -187,6 +188,8 @@
             // Doesn't make sense for JDBC.
             return;
 
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.LOCAL_CACHE);
+
         forAllNodes(new IgniteInClosureX<Ignite>() {
             @Override public void applyx(Ignite ignite) throws IgniteCheckedException {
                 createCache(ignite, cacheConfig(LOCAL).setDataRegionName(REGION_VOLATILE));
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/WalModeChangeAdvancedSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/WalModeChangeAdvancedSelfTest.java
index d95b715..f1e6e92 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/WalModeChangeAdvancedSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/WalModeChangeAdvancedSelfTest.java
@@ -26,10 +26,13 @@
 import org.apache.ignite.Ignite;
 import org.apache.ignite.IgniteCache;
 import org.apache.ignite.IgniteException;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.IgniteClientReconnectAbstractTest;
 import org.apache.ignite.internal.IgniteInternalFuture;
 import org.apache.ignite.testframework.GridTestUtils;
 import org.apache.ignite.testframework.GridTestUtils.SF;
+import org.apache.ignite.testframework.MvccFeatureChecker;
 
 import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL;
 import static org.apache.ignite.cache.CacheMode.PARTITIONED;
@@ -52,6 +55,11 @@
     }
 
     /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
+    /** {@inheritDoc} */
     @Override protected void afterTest() throws Exception {
         super.afterTest();
 
@@ -134,6 +142,9 @@
      * @throws Exception If failed.
      */
     public void testJoin() throws Exception {
+        if (MvccFeatureChecker.forcedMvcc())
+            fail("https://issues.apache.org/jira/browse/IGNITE-10421");
+
         checkJoin(false);
     }
 
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/datastructures/GridCacheAbstractDataStructuresFailoverSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/datastructures/GridCacheAbstractDataStructuresFailoverSelfTest.java
index 6e3a7bb..5b44510 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/datastructures/GridCacheAbstractDataStructuresFailoverSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/datastructures/GridCacheAbstractDataStructuresFailoverSelfTest.java
@@ -51,6 +51,8 @@
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.CollectionConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.IgniteEx;
 import org.apache.ignite.internal.IgniteInternalFuture;
 import org.apache.ignite.internal.NodeStoppingException;
@@ -158,6 +160,11 @@
         return cfg;
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * Starts client node.
      *
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/datastructures/GridCacheSetAbstractSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/datastructures/GridCacheSetAbstractSelfTest.java
index 4e888aa..bb85008 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/datastructures/GridCacheSetAbstractSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/datastructures/GridCacheSetAbstractSelfTest.java
@@ -1081,7 +1081,7 @@
      *
      * @throws Exception If failed.
      */
-    public void _testMultipleStructuresInDifferentGroups() throws Exception {
+    public void testMultipleStructuresInDifferentGroups() throws Exception {
         Ignite ignite = grid(0);
 
         CollectionConfiguration cfg1 = collectionConfiguration();
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CacheAffinityEarlyTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CacheAffinityEarlyTest.java
index 46669ac..2f04870 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CacheAffinityEarlyTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CacheAffinityEarlyTest.java
@@ -156,7 +156,7 @@
         CacheConfiguration ccfg = defaultCacheConfiguration();
 
         ccfg.setCacheMode(CacheMode.PARTITIONED);
-        ccfg.setAtomicityMode(CacheAtomicityMode.ATOMIC);
+        ccfg.setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL);
         ccfg.setBackups(1);
         ccfg.setNearConfiguration(null);
 
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CacheAsyncOperationsFailoverAbstractTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CacheAsyncOperationsFailoverAbstractTest.java
index 211320f..5e77816 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CacheAsyncOperationsFailoverAbstractTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CacheAsyncOperationsFailoverAbstractTest.java
@@ -31,6 +31,8 @@
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.configuration.NearCacheConfiguration;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.IgniteInternalFuture;
 import org.apache.ignite.internal.processors.cache.GridCacheAbstractSelfTest;
 import org.apache.ignite.internal.util.typedef.internal.S;
@@ -93,6 +95,11 @@
         return null;
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * @throws Exception If failed.
      */
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CacheAsyncOperationsTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CacheAsyncOperationsTest.java
index 0b6d7b1..0416d17 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CacheAsyncOperationsTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CacheAsyncOperationsTest.java
@@ -37,6 +37,7 @@
 
 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.CacheWriteSynchronizationMode.FULL_SYNC;
 
@@ -79,6 +80,13 @@
     /**
      * @throws Exception If failed.
      */
+    public void testAsyncOperationsMvccTx() throws Exception {
+        asyncOperations(TRANSACTIONAL_SNAPSHOT);
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
     public void testAsyncOperationsAtomic() throws Exception {
         asyncOperations(ATOMIC);
     }
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CacheBaselineTopologyTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CacheBaselineTopologyTest.java
index 053ed82..f4cc24a 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CacheBaselineTopologyTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CacheBaselineTopologyTest.java
@@ -43,6 +43,8 @@
 import org.apache.ignite.configuration.DataStorageConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.configuration.WALMode;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.IgniteEx;
 import org.apache.ignite.internal.IgniteInternalFuture;
 import org.apache.ignite.internal.IgniteInterruptedCheckedException;
@@ -146,6 +148,11 @@
         return cfg;
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * Verifies that rebalance on cache with Node Filter happens when BaselineTopology changes.
      *
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CacheDataLossOnPartitionMoveTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CacheDataLossOnPartitionMoveTest.java
index 9ff0725..acbfa8c 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CacheDataLossOnPartitionMoveTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CacheDataLossOnPartitionMoveTest.java
@@ -36,13 +36,14 @@
 import org.apache.ignite.configuration.WALMode;
 import org.apache.ignite.internal.TestRecordingCommunicationSpi;
 import org.apache.ignite.internal.processors.cache.GridCacheUtils;
-import org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridDhtLocalPartition;
 import org.apache.ignite.internal.processors.cache.distributed.dht.preloader.GridDhtPartitionDemandMessage;
+import org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridDhtLocalPartition;
 import org.apache.ignite.internal.util.typedef.G;
 import org.apache.ignite.internal.util.typedef.internal.CU;
 import org.apache.ignite.internal.util.typedef.internal.U;
 import org.apache.ignite.lang.IgniteBiPredicate;
 import org.apache.ignite.testframework.GridTestNode;
+import org.apache.ignite.testframework.MvccFeatureChecker;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
 import org.jetbrains.annotations.Nullable;
 
@@ -119,6 +120,9 @@
      * @throws Exception if failed.
      */
     public void testDataLossOnPartitionMove() throws Exception {
+        if (MvccFeatureChecker.forcedMvcc())
+            fail("https://issues.apache.org/jira/browse/IGNITE-10421");
+
         try {
             Ignite ignite = startGridsMultiThreaded(GRIDS_CNT / 2, false);
 
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CacheExchangeMergeTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CacheExchangeMergeTest.java
index 2dad0b5..f91116d 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CacheExchangeMergeTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CacheExchangeMergeTest.java
@@ -43,6 +43,8 @@
 import org.apache.ignite.events.DiscoveryEvent;
 import org.apache.ignite.events.Event;
 import org.apache.ignite.events.EventType;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.IgniteEx;
 import org.apache.ignite.internal.IgniteInternalFuture;
 import org.apache.ignite.internal.IgniteKernal;
@@ -79,6 +81,7 @@
 import static org.apache.ignite.IgniteSystemProperties.IGNITE_EXCHANGE_HISTORY_SIZE;
 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;
@@ -149,7 +152,12 @@
                 cacheConfiguration("c7", TRANSACTIONAL, PARTITIONED, 1),
                 cacheConfiguration("c8", TRANSACTIONAL, PARTITIONED, 2),
                 cacheConfiguration("c9", TRANSACTIONAL, PARTITIONED, 10),
-                cacheConfiguration("c10", TRANSACTIONAL, REPLICATED, 0)
+                cacheConfiguration("c10", TRANSACTIONAL, REPLICATED, 0),
+                cacheConfiguration("c11", TRANSACTIONAL_SNAPSHOT, PARTITIONED, 0),
+                cacheConfiguration("c12", TRANSACTIONAL_SNAPSHOT, PARTITIONED, 1),
+                cacheConfiguration("c13", TRANSACTIONAL_SNAPSHOT, PARTITIONED, 2),
+                cacheConfiguration("c14", TRANSACTIONAL_SNAPSHOT, PARTITIONED, 10),
+                cacheConfiguration("c15", TRANSACTIONAL_SNAPSHOT, REPLICATED, 0)
             );
         }
 
@@ -176,6 +184,11 @@
         super.afterTest();
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * @param name Cache name.
      * @param atomicityMode Cache atomicity mode.
@@ -825,7 +838,6 @@
         mergeServersAndClientsFail(true);
     }
 
-
     /**
      * @param waitRebalance Wait for rebalance end before start tested topology change.
      * @throws Exception If failed.
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CacheGetInsideLockChangingTopologyTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CacheGetInsideLockChangingTopologyTest.java
index 80aa9ee..8a00f28 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CacheGetInsideLockChangingTopologyTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CacheGetInsideLockChangingTopologyTest.java
@@ -33,6 +33,8 @@
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.configuration.NearCacheConfiguration;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.IgniteInternalFuture;
 import org.apache.ignite.internal.processors.cache.GridCacheAlwaysEvictionPolicy;
 import org.apache.ignite.internal.util.typedef.internal.U;
@@ -152,6 +154,11 @@
         System.clearProperty(IgniteSystemProperties.IGNITE_ENABLE_FORCIBLE_NODE_KILL);
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * @throws Exception If failed.
      */
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CacheGroupsPreloadTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CacheGroupsPreloadTest.java
index 8859638..af223f4 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CacheGroupsPreloadTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CacheGroupsPreloadTest.java
@@ -106,6 +106,17 @@
     /**
      * @throws Exception If failed.
      */
+    public void testCachePreloadMvcc2() throws Exception {
+        fail("https://issues.apache.org/jira/browse/IGNITE-7187");
+
+        atomicityMode = CacheAtomicityMode.TRANSACTIONAL_SNAPSHOT;
+
+        cachePreloadTest();
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
     public void testCachePreload3() throws Exception {
         cacheMode = CacheMode.REPLICATED;
 
@@ -125,6 +136,16 @@
     /**
      * @throws Exception If failed.
      */
+    public void testCachePreloadMvcc4() throws Exception {
+        cacheMode = CacheMode.REPLICATED;
+        atomicityMode = CacheAtomicityMode.TRANSACTIONAL_SNAPSHOT;
+
+        cachePreloadTest();
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
     public void testCachePreload5() throws Exception {
         sameGrp = false;
 
@@ -144,6 +165,18 @@
     /**
      * @throws Exception If failed.
      */
+    public void testCachePreloadMvcc6() throws Exception {
+        fail("https://issues.apache.org/jira/browse/IGNITE-7187");
+
+        sameGrp = false;
+        atomicityMode = CacheAtomicityMode.TRANSACTIONAL_SNAPSHOT;
+
+        cachePreloadTest();
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
     public void testCachePreload7() throws Exception {
         sameGrp = false;
         cacheMode = CacheMode.REPLICATED;
@@ -165,6 +198,17 @@
     /**
      * @throws Exception If failed.
      */
+    public void testCachePreloadMvcc8() throws Exception {
+        sameGrp = false;
+        cacheMode = CacheMode.REPLICATED;
+        atomicityMode = CacheAtomicityMode.TRANSACTIONAL_SNAPSHOT;
+
+        cachePreloadTest();
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
     private void cachePreloadTest() throws Exception {
         IgniteCache<Object, Object> cache = startGrid(0).cache(CACHE1);
 
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 0107894..2766aba 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
@@ -92,6 +92,7 @@
 import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder;
 import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
 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;
@@ -2047,6 +2048,9 @@
      * @throws Exception If failed.
      */
     public void testNoForceKeysRequests() throws Exception {
+        if (MvccFeatureChecker.forcedMvcc())
+            fail("https://issues.apache.org/jira/browse/IGNITE-10391");
+
         cacheC = new IgniteClosure<String, CacheConfiguration[]>() {
             @Override public CacheConfiguration[] apply(String s) {
                 return null;
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CacheLoadingConcurrentGridStartSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CacheLoadingConcurrentGridStartSelfTest.java
index 10d04bd..9a8511a 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CacheLoadingConcurrentGridStartSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CacheLoadingConcurrentGridStartSelfTest.java
@@ -37,6 +37,8 @@
 import org.apache.ignite.cluster.ClusterNode;
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.IgniteEx;
 import org.apache.ignite.internal.IgniteInternalFuture;
 import org.apache.ignite.internal.processors.datastreamer.DataStreamerImpl;
@@ -141,6 +143,11 @@
         stopAllGrids();
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * @throws Exception if failed
      */
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CachePageWriteLockUnlockTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CachePageWriteLockUnlockTest.java
index 41c5882..5b24761 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CachePageWriteLockUnlockTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CachePageWriteLockUnlockTest.java
@@ -21,6 +21,7 @@
 import javax.cache.Cache;
 import org.apache.ignite.Ignite;
 import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.cache.CacheAtomicityMode;
 import org.apache.ignite.cache.affinity.rendezvous.RendezvousAffinityFunction;
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.DataRegionConfiguration;
@@ -51,8 +52,9 @@
     @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception {
         IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName);
 
-        cfg.setCacheConfiguration(new CacheConfiguration(DEFAULT_CACHE_NAME).
-            setAffinity(new RendezvousAffinityFunction(false, 32)));
+        cfg.setCacheConfiguration(new CacheConfiguration(DEFAULT_CACHE_NAME)
+            .setAffinity(new RendezvousAffinityFunction(false, 32))
+            .setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL));
 
         cfg.setActiveOnStart(false);
 
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CachePutAllFailoverAbstractTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CachePutAllFailoverAbstractTest.java
index 57a150f..ce60c8a 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CachePutAllFailoverAbstractTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CachePutAllFailoverAbstractTest.java
@@ -30,6 +30,8 @@
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.configuration.NearCacheConfiguration;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.IgniteInternalFuture;
 import org.apache.ignite.internal.processors.cache.GridCacheAbstractSelfTest;
 import org.apache.ignite.internal.util.typedef.internal.S;
@@ -92,6 +94,11 @@
         return null;
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * @throws Exception If failed.
      */
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CacheStartOnJoinTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CacheStartOnJoinTest.java
index d59f470..54889e4 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CacheStartOnJoinTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CacheStartOnJoinTest.java
@@ -46,6 +46,7 @@
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
 
 import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL;
+import static org.apache.ignite.testframework.MvccFeatureChecker.assertMvccWriteConflict;
 
 /**
  *
@@ -184,7 +185,18 @@
                     if (createCache) {
                         for (int c = 0; c < 5; c++) {
                             for (IgniteCache cache : node.getOrCreateCaches(cacheConfigurations())) {
-                                cache.put(c, c);
+                                boolean updated = false;
+
+                                while (!updated) {
+                                    try {
+                                        cache.put(c, c);
+
+                                        updated = true;
+                                    }
+                                    catch (Exception e) {
+                                        assertMvccWriteConflict(e);
+                                    }
+                                }
 
                                 assertEquals(c, cache.get(c));
                             }
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CacheTryLockMultithreadedTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CacheTryLockMultithreadedTest.java
index 82d9c12..bccc703 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CacheTryLockMultithreadedTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CacheTryLockMultithreadedTest.java
@@ -27,6 +27,7 @@
 import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder;
 import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
 import org.apache.ignite.testframework.GridTestUtils;
+import org.apache.ignite.testframework.MvccFeatureChecker;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
 
 import static java.util.concurrent.TimeUnit.MILLISECONDS;
@@ -68,6 +69,8 @@
 
     /** {@inheritDoc} */
     @Override protected void beforeTestsStarted() throws Exception {
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.ENTRY_LOCK);
+
         super.beforeTestsStarted();
 
         startGridsMultiThreaded(SRVS);
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/GridCacheAbstractDistributedByteArrayValuesSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/GridCacheAbstractDistributedByteArrayValuesSelfTest.java
index c2716b5..c4aed34 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/GridCacheAbstractDistributedByteArrayValuesSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/GridCacheAbstractDistributedByteArrayValuesSelfTest.java
@@ -22,6 +22,7 @@
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.internal.processors.cache.GridCacheAbstractByteArrayValuesSelfTest;
+import org.apache.ignite.testframework.MvccFeatureChecker;
 import org.apache.ignite.transactions.Transaction;
 import org.apache.ignite.transactions.TransactionConcurrency;
 import org.jetbrains.annotations.Nullable;
@@ -169,6 +170,9 @@
      */
     private void testTransactionMixed0(IgniteCache<Integer, Object>[] caches, TransactionConcurrency concurrency,
         Integer key1, byte[] val1, @Nullable Integer key2, @Nullable Object val2) throws Exception {
+        if (MvccFeatureChecker.forcedMvcc() && !MvccFeatureChecker.isSupported(concurrency, REPEATABLE_READ))
+            return;
+
         for (IgniteCache<Integer, Object> cache : caches) {
             info("Checking cache: " + cache.getName());
 
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/GridCacheAbstractNodeRestartSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/GridCacheAbstractNodeRestartSelfTest.java
index 2116ecb..3fd0170 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/GridCacheAbstractNodeRestartSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/GridCacheAbstractNodeRestartSelfTest.java
@@ -40,6 +40,8 @@
 import org.apache.ignite.cache.eviction.lru.LruEvictionPolicy;
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.spi.communication.tcp.TcpCommunicationSpi;
 import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
 import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder;
@@ -188,6 +190,11 @@
         idx = -1;
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * @return Cache atomicity mode.
      */
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/GridCacheAbstractPartitionedByteArrayValuesSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/GridCacheAbstractPartitionedByteArrayValuesSelfTest.java
index 4af2571..0ee6262 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/GridCacheAbstractPartitionedByteArrayValuesSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/GridCacheAbstractPartitionedByteArrayValuesSelfTest.java
@@ -21,6 +21,7 @@
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.configuration.NearCacheConfiguration;
 import org.apache.ignite.configuration.TransactionConfiguration;
+import org.apache.ignite.testframework.MvccFeatureChecker;
 
 import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL;
 import static org.apache.ignite.cache.CacheMode.PARTITIONED;
@@ -31,6 +32,15 @@
  */
 public abstract class GridCacheAbstractPartitionedByteArrayValuesSelfTest extends
     GridCacheAbstractDistributedByteArrayValuesSelfTest {
+
+    /** {@inheritDoc} */
+    @Override protected void beforeTestsStarted() throws Exception {
+        if (nearConfiguration() != null)
+            MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.NEAR_CACHE);
+
+        super.beforeTestsStarted();
+    }
+
     /** {@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/distributed/GridCacheClientModesAbstractSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/GridCacheClientModesAbstractSelfTest.java
index 33766f3..9316c2d 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/GridCacheClientModesAbstractSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/GridCacheClientModesAbstractSelfTest.java
@@ -30,6 +30,7 @@
 import org.apache.ignite.internal.util.typedef.F;
 import org.apache.ignite.internal.util.typedef.G;
 import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
+import org.apache.ignite.testframework.MvccFeatureChecker;
 
 import static org.apache.ignite.cache.CacheMode.PARTITIONED;
 import static org.apache.ignite.cache.CacheMode.REPLICATED;
@@ -51,6 +52,9 @@
 
     /** {@inheritDoc} */
     @Override protected void beforeTestsStarted() throws Exception {
+        if (nearEnabled())
+            MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.NEAR_CACHE);
+
         gridCnt = new AtomicInteger();
 
         super.beforeTestsStarted();
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/GridCacheEventAbstractTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/GridCacheEventAbstractTest.java
index daa1557..9183476 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/GridCacheEventAbstractTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/GridCacheEventAbstractTest.java
@@ -40,6 +40,7 @@
 import org.apache.ignite.internal.util.typedef.internal.U;
 import org.apache.ignite.lang.IgniteBiTuple;
 import org.apache.ignite.lang.IgnitePredicate;
+import org.apache.ignite.testframework.MvccFeatureChecker;
 import org.apache.ignite.transactions.Transaction;
 
 import static org.apache.ignite.events.EventType.EVTS_CACHE;
@@ -77,6 +78,8 @@
 
     /** {@inheritDoc} */
     @Override protected void beforeTestsStarted() throws Exception {
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.CACHE_EVENTS);
+
         super.beforeTestsStarted();
 
         gridCnt = gridCount();
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/GridCacheMixedModeSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/GridCacheMixedModeSelfTest.java
index 3d6c088..bd309fa 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/GridCacheMixedModeSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/GridCacheMixedModeSelfTest.java
@@ -27,6 +27,8 @@
 
 /**
  * Tests cache puts in mixed mode.
+ *
+ * TODO IGNITE-10345: Remove test in ignite 3.0.
  */
 public class GridCacheMixedModeSelfTest extends GridCommonAbstractTest {
     /** {@inheritDoc} */
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/GridCacheMultiNodeAbstractTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/GridCacheMultiNodeAbstractTest.java
index 912aece..0d1aff9 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/GridCacheMultiNodeAbstractTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/GridCacheMultiNodeAbstractTest.java
@@ -184,6 +184,8 @@
      * @throws Exception If check fails.
      */
     private void checkPuts(int cnt, Ignite... ignites) throws Exception {
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.ENTRY_LOCK);
+
         CountDownLatch latch = new CountDownLatch(ignites.length * cnt);
 
         CacheEventListener lsnr = new CacheEventListener(latch, EVT_CACHE_OBJECT_PUT);
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/GridCachePartitionEvictionDuringReadThroughSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/GridCachePartitionEvictionDuringReadThroughSelfTest.java
index 01316f6..5a9e86a 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/GridCachePartitionEvictionDuringReadThroughSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/GridCachePartitionEvictionDuringReadThroughSelfTest.java
@@ -84,8 +84,6 @@
      * @throws Exception if failed.
      */
     public void testPartitionRent() throws Exception {
-        fail("https://issues.apache.org/jira/browse/IGNITE-5759");
-
         startGrid(DATA_READ_GRID_IDX);
 
         final AtomicBoolean done = new AtomicBoolean();
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/GridCachePartitionNotLoadedEventSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/GridCachePartitionNotLoadedEventSelfTest.java
index f5695ca..4091b73 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/GridCachePartitionNotLoadedEventSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/GridCachePartitionNotLoadedEventSelfTest.java
@@ -107,6 +107,8 @@
      * @throws Exception If failed.
      */
     public void testPrimaryAndBackupDead() throws Exception {
+        fail("https://issues.apache.org/jira/browse/IGNITE-5968");
+
         backupCnt = 1;
 
         startGridsMultiThreaded(4);
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/GridCachePreloadEventsAbstractSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/GridCachePreloadEventsAbstractSelfTest.java
index 59af680..0148804 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/GridCachePreloadEventsAbstractSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/GridCachePreloadEventsAbstractSelfTest.java
@@ -32,6 +32,7 @@
 import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder;
 import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
 import org.apache.ignite.spi.eventstorage.memory.MemoryEventStorageSpi;
+import org.apache.ignite.testframework.MvccFeatureChecker;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
 
 import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL;
@@ -47,6 +48,13 @@
     private TcpDiscoveryIpFinder ipFinder = new TcpDiscoveryVmIpFinder(true);
 
     /** {@inheritDoc} */
+    @Override protected void beforeTestsStarted() throws Exception {
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.CACHE_EVENTS);
+
+        super.beforeTestsStarted();
+    }
+
+    /** {@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/distributed/IgniteBinaryMetadataUpdateChangingTopologySelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteBinaryMetadataUpdateChangingTopologySelfTest.java
index edfeb96..c544330 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteBinaryMetadataUpdateChangingTopologySelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteBinaryMetadataUpdateChangingTopologySelfTest.java
@@ -34,6 +34,8 @@
 import org.apache.ignite.cluster.ClusterNode;
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.IgniteInternalFuture;
 import org.apache.ignite.internal.IgniteNodeAttributes;
 import org.apache.ignite.internal.managers.communication.GridIoMessage;
@@ -89,6 +91,11 @@
         startGrids(4);
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * @throws Exception If failed.
      */
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteCache150ClientsTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteCache150ClientsTest.java
index b7ae844..535fb7e 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteCache150ClientsTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteCache150ClientsTest.java
@@ -25,9 +25,12 @@
 import java.util.concurrent.atomic.AtomicInteger;
 import org.apache.ignite.Ignite;
 import org.apache.ignite.IgniteCache;
+import org.apache.ignite.cache.CacheAtomicityMode;
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.ClientConnectorConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.IgniteInternalFuture;
 import org.apache.ignite.internal.util.typedef.G;
 import org.apache.ignite.spi.communication.tcp.TcpCommunicationSpi;
@@ -37,8 +40,6 @@
 import org.apache.ignite.testframework.GridTestUtils;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
 
-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.PRIMARY_SYNC;
 
@@ -52,6 +53,9 @@
     /** */
     private static final int CACHES = 10;
 
+    /** */
+    private static final int CLIENTS = 150;
+
     /** {@inheritDoc} */
     @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception {
         IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName);
@@ -80,7 +84,7 @@
             CacheConfiguration ccfg = new CacheConfiguration(DEFAULT_CACHE_NAME);
 
             ccfg.setCacheMode(PARTITIONED);
-            ccfg.setAtomicityMode(i % 2 == 0 ? ATOMIC : TRANSACTIONAL);
+            ccfg.setAtomicityMode(CacheAtomicityMode.values()[i % 3]);
             ccfg.setWriteSynchronizationMode(PRIMARY_SYNC);
             ccfg.setBackups(1);
 
@@ -106,6 +110,12 @@
         stopAllGrids();
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        // Test can be too slow because of a lot of clients.
+        return new NoOpFailureHandler();
+    }
+
     /**
      * @throws Exception If failed.
      */
@@ -114,8 +124,6 @@
 
         assertFalse(srv.configuration().isClientMode());
 
-        final int CLIENTS = 150;
-
         final AtomicInteger idx = new AtomicInteger(1);
 
         final CountDownLatch latch = new CountDownLatch(CLIENTS);
@@ -164,7 +172,7 @@
             }
         }, CLIENTS, "start-client");
 
-        fut.get();
+        fut.get(getTestTimeout());
 
         log.info("Started all clients.");
 
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteCacheClientMultiNodeUpdateTopologyLockTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteCacheClientMultiNodeUpdateTopologyLockTest.java
index 7711bbb..b2bf2a1 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteCacheClientMultiNodeUpdateTopologyLockTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteCacheClientMultiNodeUpdateTopologyLockTest.java
@@ -25,6 +25,8 @@
 import org.apache.ignite.cluster.ClusterNode;
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.IgniteInternalFuture;
 import org.apache.ignite.internal.TestRecordingCommunicationSpi;
 import org.apache.ignite.internal.processors.cache.distributed.dht.preloader.GridDhtPartitionsSingleMessage;
@@ -75,6 +77,11 @@
         return cfg;
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * @throws Exception If failed.
      */
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteCacheClientNodeChangingTopologyTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteCacheClientNodeChangingTopologyTest.java
index dd6e36e..37edfbf 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteCacheClientNodeChangingTopologyTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteCacheClientNodeChangingTopologyTest.java
@@ -52,6 +52,8 @@
 import org.apache.ignite.configuration.NearCacheConfiguration;
 import org.apache.ignite.events.DiscoveryEvent;
 import org.apache.ignite.events.EventType;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.IgniteEx;
 import org.apache.ignite.internal.IgniteInternalFuture;
 import org.apache.ignite.internal.IgniteKernal;
@@ -154,6 +156,11 @@
         stopAllGrids();
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * @throws Exception If failed.
      */
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteCacheClientReconnectTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteCacheClientReconnectTest.java
index a0796a3..e7b5ed2 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteCacheClientReconnectTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteCacheClientReconnectTest.java
@@ -31,6 +31,8 @@
 import org.apache.ignite.cluster.ClusterNode;
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.IgniteEx;
 import org.apache.ignite.internal.IgniteInternalFuture;
 import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion;
@@ -118,6 +120,11 @@
         stopAllGrids();
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * If setting IGNITE_EXCHANGE_HISTORY_SIZE is set to small value
      * it is possible that bunch of clients simultaneous start (amount > IGNITE_EXCHANGE_HISTORY_SIZE)
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteCacheCreatePutMultiNodeSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteCacheCreatePutMultiNodeSelfTest.java
index 23fc941..0b021a8 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteCacheCreatePutMultiNodeSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteCacheCreatePutMultiNodeSelfTest.java
@@ -34,6 +34,7 @@
 import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder;
 import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
 import org.apache.ignite.testframework.GridTestUtils;
+import org.apache.ignite.testframework.MvccFeatureChecker;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
 
 /**
@@ -94,8 +95,18 @@
 
                                 IgniteCache<Integer, Integer> cache = getCache(ignite, cacheName);
 
-                                for (int i = 0; i < 100; i++)
-                                    cache.getAndPut(i, i);
+                                for (int i = 0; i < 100; i++) {
+                                    while (true) {
+                                        try {
+                                            cache.getAndPut(i, i);
+
+                                            break;
+                                        }
+                                        catch (Exception e) {
+                                            MvccFeatureChecker.assertMvccWriteConflict(e);
+                                        }
+                                    }
+                                }
 
                                 barrier.await();
 
@@ -139,7 +150,7 @@
         CacheConfiguration<Integer, Integer> ccfg = new CacheConfiguration<>(cacheName);
 
         ccfg.setCacheMode(CacheMode.PARTITIONED);
-        ccfg.setAtomicityMode(CacheAtomicityMode.ATOMIC);
+        ccfg.setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL);
         ccfg.setBackups(1);
         ccfg.setNearConfiguration(null);
 
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteCacheCreatePutTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteCacheCreatePutTest.java
index 646084c..5d6e895 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteCacheCreatePutTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteCacheCreatePutTest.java
@@ -37,9 +37,11 @@
 
 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.testframework.MvccFeatureChecker.assertMvccWriteConflict;
 
 /**
  *
@@ -149,6 +151,7 @@
 
         ignite0.createCache(cacheConfiguration("atomic-cache", ATOMIC));
         ignite0.createCache(cacheConfiguration("tx-cache", TRANSACTIONAL));
+        ignite0.createCache(cacheConfiguration("mvcc-tx-cache", TRANSACTIONAL_SNAPSHOT));
 
         final long stopTime = System.currentTimeMillis() + 60_000;
 
@@ -162,6 +165,7 @@
 
                 IgniteCache cache1 = node.cache("atomic-cache");
                 IgniteCache cache2 = node.cache("tx-cache");
+                IgniteCache cache3 = node.cache("mvcc-tx-cache");
 
                 ThreadLocalRandom rnd = ThreadLocalRandom.current();
 
@@ -174,6 +178,13 @@
 
                     cache2.put(key, key);
 
+                    try {
+                        cache3.put(key, key);
+                    }
+                    catch (Exception e) {
+                        assertMvccWriteConflict(e); // Do not retry.
+                    }
+
                     if (iter++ % 1000 == 0)
                         log.info("Update iteration: " + iter);
                 }
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteCacheFailedUpdateResponseTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteCacheFailedUpdateResponseTest.java
index ebcff7c..7414b88 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteCacheFailedUpdateResponseTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteCacheFailedUpdateResponseTest.java
@@ -37,12 +37,16 @@
 import org.apache.ignite.cache.CachePartialUpdateException;
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.IgniteEx;
+import org.apache.ignite.internal.processors.cache.IgniteCacheProxy;
 import org.apache.ignite.internal.util.typedef.F;
 import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
 
 import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL;
+import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL_SNAPSHOT;
 import static org.apache.ignite.testframework.GridTestUtils.assertThrows;
 import static org.apache.ignite.transactions.TransactionConcurrency.OPTIMISTIC;
 import static org.apache.ignite.transactions.TransactionConcurrency.PESSIMISTIC;
@@ -51,7 +55,7 @@
 import static org.apache.ignite.transactions.TransactionIsolation.SERIALIZABLE;
 
 /**
- * Checks that no future hangs on non-srializable exceptions and values.
+ * Checks that no future hangs on non-serializable exceptions and values.
  */
 public class IgniteCacheFailedUpdateResponseTest extends GridCommonAbstractTest {
     /** Atomic cache. */
@@ -60,25 +64,34 @@
     /** Tx cache. */
     private static final String TX_CACHE = "tx";
 
+    /** Mvcc tx cache. */
+    private static final String MVCC_TX_CACHE = "mvcc-tx";
+
     /** Atomic cache. */
     private IgniteCache<Object, Object> atomicCache;
 
     /** Tx cache. */
     private IgniteCache<Object, Object> txCache;
 
+    /** Mvcc tx cache. */
+    private IgniteCache<Object, Object> mvccTxCache;
+
     /** {@inheritDoc} */
     @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception {
         IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName);
 
         CacheConfiguration atomicCfg = new CacheConfiguration(ATOMIC_CACHE);
         CacheConfiguration txCfg = new CacheConfiguration(TX_CACHE);
+        CacheConfiguration mvccTxCfg = new CacheConfiguration(MVCC_TX_CACHE);
 
         atomicCfg.setBackups(1);
         txCfg.setBackups(1);
+        mvccTxCfg.setBackups(1);
 
         txCfg.setAtomicityMode(TRANSACTIONAL);
+        mvccTxCfg.setAtomicityMode(TRANSACTIONAL_SNAPSHOT);
 
-        cfg.setCacheConfiguration(atomicCfg, txCfg);
+        cfg.setCacheConfiguration(atomicCfg, txCfg, mvccTxCfg);
 
         cfg.setClientMode(igniteInstanceName.contains("client"));
 
@@ -98,6 +111,12 @@
     @Override protected void beforeTest() throws Exception {
         atomicCache = grid("client").cache(ATOMIC_CACHE);
         txCache = grid("client").cache(TX_CACHE);
+        mvccTxCache = grid("client").cache(MVCC_TX_CACHE);
+    }
+
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
     }
 
     /**
@@ -135,10 +154,31 @@
     }
 
     /**
+     * @throws Exception If failed.
+     */
+    public void testInvokeMvccTx() throws Exception {
+        testInvoke(mvccTxCache);
+        testInvokeAll(mvccTxCache);
+
+        IgniteEx client = grid("client");
+
+        Callable<Object> clos = new Callable<Object>() {
+            @Override public Object call() throws Exception {
+                testInvoke(mvccTxCache);
+                testInvokeAll(mvccTxCache);
+
+                return null;
+            }
+        };
+
+        doInTransaction(client, PESSIMISTIC, REPEATABLE_READ, clos);
+    }
+
+    /**
      * @param cache Cache.
      */
     private void testInvoke(final IgniteCache<Object, Object> cache) throws Exception {
-        Class<? extends Exception> exp = grid("client").transactions().tx() == null
+        Class<? extends Exception> exp = grid("client").transactions().tx() == null || ((IgniteCacheProxy)cache).context().mvccEnabled()
             ? EntryProcessorException.class
             : NonSerializableException.class;
 
@@ -174,7 +214,7 @@
         assertNotNull(epRes);
 
         // In transactions EP will be invoked locally.
-        Class<? extends Exception> exp = grid("client").transactions().tx() == null
+        Class<? extends Exception> exp = grid("client").transactions().tx() == null || ((IgniteCacheProxy)cache).context().mvccEnabled()
             ? EntryProcessorException.class
             : NonSerializableException.class;
 
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteCacheGetRestartTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteCacheGetRestartTest.java
index ba22048..43f016f 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteCacheGetRestartTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteCacheGetRestartTest.java
@@ -31,6 +31,8 @@
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.configuration.NearCacheConfiguration;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.IgniteInternalFuture;
 import org.apache.ignite.internal.processors.cache.IgniteCacheProxy;
 import org.apache.ignite.internal.util.typedef.internal.U;
@@ -116,6 +118,11 @@
         return TEST_TIME + 3 * 60_000;
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * @throws Exception If failed.
      */
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteCachePrimarySyncTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteCachePrimarySyncTest.java
index e9e22ee..2482a8e 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteCachePrimarySyncTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteCachePrimarySyncTest.java
@@ -27,6 +27,7 @@
 import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
 import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder;
 import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
+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;
@@ -35,6 +36,7 @@
 
 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.CacheWriteSynchronizationMode.PRIMARY_SYNC;
 import static org.apache.ignite.transactions.TransactionConcurrency.OPTIMISTIC;
 import static org.apache.ignite.transactions.TransactionConcurrency.PESSIMISTIC;
@@ -53,6 +55,15 @@
     private static final int SRVS = 4;
 
     /** */
+    private static final String ATOMIC_CACHE = "atomicCache";
+
+    /** */
+    private static final String TX_CACHE = "txCache";
+
+    /** */
+    private static final String MVCC_CACHE = "mvccCache";
+
+    /** */
     private boolean clientMode;
 
     /** {@inheritDoc} */
@@ -61,19 +72,22 @@
 
         ((TcpDiscoverySpi)cfg.getDiscoverySpi()).setIpFinder(ipFinder);
 
-        CacheConfiguration<Object, Object> ccfg1 = new CacheConfiguration<>(DEFAULT_CACHE_NAME);
-        ccfg1.setName("cache1");
-        ccfg1.setAtomicityMode(ATOMIC);
-        ccfg1.setBackups(2);
-        ccfg1.setWriteSynchronizationMode(PRIMARY_SYNC);
+        CacheConfiguration<Object, Object> ccfg1 = new CacheConfiguration<>(ATOMIC_CACHE)
+            .setAtomicityMode(ATOMIC)
+            .setBackups(2)
+            .setWriteSynchronizationMode(PRIMARY_SYNC);
 
-        CacheConfiguration<Object, Object> ccfg2 = new CacheConfiguration<>(DEFAULT_CACHE_NAME);
-        ccfg2.setName("cache2");
-        ccfg2.setAtomicityMode(TRANSACTIONAL);
-        ccfg2.setBackups(2);
-        ccfg2.setWriteSynchronizationMode(PRIMARY_SYNC);
+        CacheConfiguration<Object, Object> ccfg2 = new CacheConfiguration<>(TX_CACHE)
+            .setAtomicityMode(TRANSACTIONAL)
+            .setBackups(2)
+            .setWriteSynchronizationMode(PRIMARY_SYNC);
 
-        cfg.setCacheConfiguration(ccfg1, ccfg2);
+        CacheConfiguration<Object, Object> ccfg3 = new CacheConfiguration<>(MVCC_CACHE)
+            .setAtomicityMode(TRANSACTIONAL_SNAPSHOT)
+            .setBackups(2)
+            .setWriteSynchronizationMode(PRIMARY_SYNC);
+
+        cfg.setCacheConfiguration(ccfg1, ccfg2, ccfg3);
 
         cfg.setClientMode(clientMode);
 
@@ -97,17 +111,24 @@
      * @throws Exception If failed.
      */
     public void testPutGet() throws Exception {
+        if (MvccFeatureChecker.forcedMvcc())
+            fail("https://issues.apache.org/jira/browse/IGNITE-10520");
+
         Ignite ignite = ignite(SRVS);
 
-        checkPutGet(ignite.cache("cache1"), null, null, null);
+        checkPutGet(ignite.cache(ATOMIC_CACHE), null, null, null);
 
-        checkPutGet(ignite.cache("cache2"), null, null, null);
+        checkPutGet(ignite.cache(TX_CACHE), null, null, null);
 
-        checkPutGet(ignite.cache("cache2"), ignite.transactions(), OPTIMISTIC, REPEATABLE_READ);
+        checkPutGet(ignite.cache(MVCC_CACHE), null, null, null);
 
-        checkPutGet(ignite.cache("cache2"), ignite.transactions(), OPTIMISTIC, SERIALIZABLE);
+        checkPutGet(ignite.cache(TX_CACHE), ignite.transactions(), OPTIMISTIC, REPEATABLE_READ);
 
-        checkPutGet(ignite.cache("cache2"), ignite.transactions(), PESSIMISTIC, READ_COMMITTED);
+        checkPutGet(ignite.cache(TX_CACHE), ignite.transactions(), OPTIMISTIC, SERIALIZABLE);
+
+        checkPutGet(ignite.cache(TX_CACHE), ignite.transactions(), PESSIMISTIC, READ_COMMITTED);
+
+        checkPutGet(ignite.cache(MVCC_CACHE), ignite.transactions(), PESSIMISTIC, REPEATABLE_READ);
     }
 
     /**
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteCacheReadFromBackupTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteCacheReadFromBackupTest.java
index 2bb5fbb..652aba0 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteCacheReadFromBackupTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteCacheReadFromBackupTest.java
@@ -50,6 +50,7 @@
 
 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;
 
@@ -87,7 +88,23 @@
      * @throws Exception If failed.
      */
     public void testGetFromBackupStoreReadThroughEnabled() throws Exception {
-        for (CacheConfiguration<Object, Object> ccfg : cacheConfigurations()) {
+        checkGetFromBackupStoreReadThroughEnabled(cacheConfigurations());
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testMvccGetFromBackupStoreReadThroughEnabled() throws Exception {
+        fail("https://issues.apache.org/jira/browse/IGNITE-10274");
+
+        checkGetFromBackupStoreReadThroughEnabled(mvccCacheConfigurations());
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    private void checkGetFromBackupStoreReadThroughEnabled(List<CacheConfiguration<Object, Object>> cacheCfgs) throws Exception {
+        for (CacheConfiguration<Object, Object> ccfg : cacheCfgs) {
             ccfg.setCacheStoreFactory(new TestStoreFactory());
             ccfg.setReadThrough(true);
 
@@ -131,7 +148,23 @@
      * @throws Exception If failed.
      */
     public void testGetFromBackupStoreReadThroughDisabled() throws Exception {
-        for (CacheConfiguration<Object, Object> ccfg : cacheConfigurations()) {
+        checkGetFromBackupStoreReadThroughDisabled(cacheConfigurations());
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testMvccGetFromBackupStoreReadThroughDisabled() throws Exception {
+        fail("https://issues.apache.org/jira/browse/IGNITE-10274");
+
+        checkGetFromBackupStoreReadThroughDisabled(mvccCacheConfigurations());
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    private void checkGetFromBackupStoreReadThroughDisabled(List<CacheConfiguration<Object, Object>> cacheCfgs) throws Exception {
+        for (CacheConfiguration<Object, Object> ccfg : cacheCfgs) {
             ccfg.setCacheStoreFactory(new TestStoreFactory());
             ccfg.setReadThrough(false);
 
@@ -159,7 +192,23 @@
      * @throws Exception If failed.
      */
     public void testGetFromPrimaryPreloadInProgress() throws Exception {
-        for (final CacheConfiguration<Object, Object> ccfg : cacheConfigurations()) {
+        checkGetFromPrimaryPreloadInProgress(cacheConfigurations());
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testMvccGetFromPrimaryPreloadInProgress() throws Exception {
+        fail("https://issues.apache.org/jira/browse/IGNITE-10274");
+
+        checkGetFromPrimaryPreloadInProgress(mvccCacheConfigurations());
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    private void checkGetFromPrimaryPreloadInProgress(List<CacheConfiguration<Object, Object>> cacheCfgs) throws Exception {
+        for (final CacheConfiguration<Object, Object> ccfg : cacheCfgs) {
             boolean near = (ccfg.getNearConfiguration() != null);
 
             log.info("Test cache [mode=" + ccfg.getCacheMode() +
@@ -245,7 +294,24 @@
      * @throws Exception If failed.
      */
     public void testNoPrimaryReadPreloadFinished() throws Exception {
-        for (CacheConfiguration<Object, Object> ccfg : cacheConfigurations()) {
+        checkNoPrimaryReadPreloadFinished(cacheConfigurations());
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testMvccNoPrimaryReadPreloadFinished() throws Exception {
+        fail("https://issues.apache.org/jira/browse/IGNITE-10274");
+
+        checkNoPrimaryReadPreloadFinished(mvccCacheConfigurations());
+
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    private void checkNoPrimaryReadPreloadFinished(List<CacheConfiguration<Object, Object>> cacheCfgs) throws Exception {
+        for (CacheConfiguration<Object, Object> ccfg : cacheCfgs) {
             boolean near = (ccfg.getNearConfiguration() != null);
 
             log.info("Test cache [mode=" + ccfg.getCacheMode() +
@@ -370,6 +436,21 @@
     }
 
     /**
+     * @return Cache configurations to test.
+     */
+    private List<CacheConfiguration<Object, Object>> mvccCacheConfigurations() {
+        List<CacheConfiguration<Object, Object>> ccfgs = new ArrayList<>();
+
+        ccfgs.add(cacheConfiguration(REPLICATED, TRANSACTIONAL_SNAPSHOT, 0, false));
+
+        ccfgs.add(cacheConfiguration(PARTITIONED, TRANSACTIONAL_SNAPSHOT, 1, false));
+        ccfgs.add(cacheConfiguration(PARTITIONED, TRANSACTIONAL_SNAPSHOT, 1, true));
+        ccfgs.add(cacheConfiguration(PARTITIONED, TRANSACTIONAL_SNAPSHOT, 2, false));
+
+        return ccfgs;
+    }
+
+    /**
      * @param cacheMode Cache mode.
      * @param atomicityMode Cache atomicity mode.
      * @param backups Number of backups.
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteCacheSingleGetMessageTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteCacheSingleGetMessageTest.java
index 974bcf2..df6100b 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteCacheSingleGetMessageTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteCacheSingleGetMessageTest.java
@@ -37,6 +37,7 @@
 
 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;
@@ -88,11 +89,25 @@
      * @throws Exception If failed.
      */
     public void testSingleGetMessage() throws Exception {
+        checkSingleGetMessage(cacheConfigurations());
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testMvccSingleGetMessage() throws Exception {
+        fail("https://issues.apache.org/jira/browse/IGNITE-7371");
+
+        checkSingleGetMessage(mvccCacheConfigurations());
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void checkSingleGetMessage(List<CacheConfiguration<Integer, Integer>> ccfgs) throws Exception {
         assertFalse(ignite(0).configuration().isClientMode());
         assertTrue(ignite(SRVS).configuration().isClientMode());
 
-        List<CacheConfiguration<Integer, Integer>> ccfgs = cacheConfigurations();
-
         for (int i = 0; i < ccfgs.size(); i++) {
             CacheConfiguration<Integer, Integer> ccfg = ccfgs.get(i);
 
@@ -282,6 +297,19 @@
     }
 
     /**
+     * @return Mvcc cache configurations to test.
+     */
+    private List<CacheConfiguration<Integer, Integer>> mvccCacheConfigurations() {
+        List<CacheConfiguration<Integer, Integer>> ccfgs = new ArrayList<>();
+
+        ccfgs.add(cacheConfiguration(PARTITIONED, TRANSACTIONAL_SNAPSHOT, FULL_SYNC, 0));
+        ccfgs.add(cacheConfiguration(PARTITIONED, TRANSACTIONAL_SNAPSHOT, FULL_SYNC, 1));
+        ccfgs.add(cacheConfiguration(REPLICATED, TRANSACTIONAL_SNAPSHOT, FULL_SYNC, 0));
+
+        return ccfgs;
+    }
+
+    /**
      * @param cacheMode Cache mode.
      * @param atomicityMode Cache atomicity mode.
      * @param syncMode Write synchronization mode.
@@ -297,7 +325,6 @@
 
         ccfg.setCacheMode(cacheMode);
         ccfg.setAtomicityMode(atomicityMode);
-        ccfg.setAtomicityMode(TRANSACTIONAL);
         ccfg.setWriteSynchronizationMode(syncMode);
 
         if (cacheMode == PARTITIONED)
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteCacheSizeFailoverTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteCacheSizeFailoverTest.java
index cd85950..7a8b6ba 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteCacheSizeFailoverTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteCacheSizeFailoverTest.java
@@ -24,6 +24,8 @@
 import org.apache.ignite.IgniteCache;
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.IgniteInternalFuture;
 import org.apache.ignite.spi.communication.tcp.TcpCommunicationSpi;
 import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
@@ -70,6 +72,11 @@
         stopAllGrids();
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * @throws Exception If failed.
      */
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteCacheThreadLocalTxTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteCacheThreadLocalTxTest.java
index c8eac20..cab6c72 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteCacheThreadLocalTxTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteCacheThreadLocalTxTest.java
@@ -29,6 +29,7 @@
 import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
 import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder;
 import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
+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;
@@ -106,6 +107,9 @@
 
         for (TransactionConcurrency concurrency : TransactionConcurrency.values()) {
             for (TransactionIsolation isolation : TransactionIsolation.values()) {
+                if (MvccFeatureChecker.forcedMvcc() && !MvccFeatureChecker.isSupported(concurrency, isolation))
+                    continue;
+
                 for (boolean read : reads) {
                     for (boolean write : writes) {
                         for (int i = 0; i < endOps; i++)
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgnitePessimisticTxSuspendResumeTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgnitePessimisticTxSuspendResumeTest.java
index 57a1470..dba769d 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgnitePessimisticTxSuspendResumeTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgnitePessimisticTxSuspendResumeTest.java
@@ -24,6 +24,7 @@
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
 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;
@@ -70,6 +71,10 @@
             IgniteTransactions txs = g.transactions();
 
             for (TransactionIsolation isolation : TransactionIsolation.values()) {
+                if (MvccFeatureChecker.forcedMvcc() &&
+                    !MvccFeatureChecker.isSupported(TransactionConcurrency.PESSIMISTIC, isolation))
+                    continue;
+
                 final Transaction tx = txs.txStart(TransactionConcurrency.PESSIMISTIC, isolation);
 
                 cache.put(1, "1");
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteTxCachePrimarySyncTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteTxCachePrimarySyncTest.java
index bdf0b12..ceed9b8 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteTxCachePrimarySyncTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteTxCachePrimarySyncTest.java
@@ -58,6 +58,8 @@
 import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder;
 import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
 import org.apache.ignite.testframework.GridTestUtils;
+import org.apache.ignite.testframework.MvccFeatureChecker;
+import org.apache.ignite.testframework.MvccFeatureChecker.Feature;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
 import org.apache.ignite.transactions.Transaction;
 import org.apache.ignite.transactions.TransactionConcurrency;
@@ -134,6 +136,9 @@
      * @throws Exception If failed.
      */
     public void testSingleKeyCommitFromPrimary() throws Exception {
+        if (MvccFeatureChecker.forcedMvcc())
+            fail("https://issues.apache.org/jira/browse/IGNITE-10518");
+
         singleKeyCommitFromPrimary(cacheConfiguration(DEFAULT_CACHE_NAME, PRIMARY_SYNC, 1, true, false));
 
         singleKeyCommitFromPrimary(cacheConfiguration(DEFAULT_CACHE_NAME, PRIMARY_SYNC, 2, false, false));
@@ -148,6 +153,16 @@
      * @throws Exception If failed.
      */
     private void singleKeyCommitFromPrimary(CacheConfiguration<Object, Object> ccfg) throws Exception {
+        if (MvccFeatureChecker.forcedMvcc()) {
+            if (ccfg.getCacheStoreFactory() != null &&
+                !MvccFeatureChecker.isSupported(Feature.CACHE_STORE))
+                return;
+
+            if (ccfg.getNearConfiguration() != null &&
+                !MvccFeatureChecker.isSupported(Feature.NEAR_CACHE))
+                return;
+        }
+
         Ignite ignite = ignite(0);
 
         IgniteCache<Object, Object> cache = ignite.createCache(ccfg);
@@ -164,6 +179,9 @@
 
                 for (final TransactionConcurrency concurrency : TransactionConcurrency.values()) {
                     for (final TransactionIsolation isolation : TransactionIsolation.values()) {
+                        if (MvccFeatureChecker.forcedMvcc() && !MvccFeatureChecker.isSupported(concurrency, isolation))
+                            continue;
+
                         singleKeyCommitFromPrimary(node, ccfg, new IgniteBiInClosure<Integer, IgniteCache<Object, Object>>() {
                             @Override public void apply(Integer key, IgniteCache<Object, Object> cache) {
                                 Ignite ignite = cache.unwrap(Ignite.class);
@@ -266,12 +284,19 @@
      * @throws Exception If failed.
      */
     private void singleKeyPrimaryNodeLeft(CacheConfiguration<Object, Object> ccfg) throws Exception {
+        if (MvccFeatureChecker.forcedMvcc()) {
+            if (ccfg.getCacheStoreFactory() != null &&
+                !MvccFeatureChecker.isSupported(Feature.CACHE_STORE))
+                return;
+        }
+
         Ignite ignite = ignite(0);
 
         IgniteCache<Object, Object> cache = ignite.createCache(ccfg);
 
         try {
-            ignite(NODES - 1).createNearCache(ccfg.getName(), new NearCacheConfiguration<>());
+            if (!MvccFeatureChecker.forcedMvcc() || MvccFeatureChecker.isSupported(Feature.NEAR_CACHE))
+                ignite(NODES - 1).createNearCache(ccfg.getName(), new NearCacheConfiguration<>());
 
             for (int i = 0; i < NODES; i++) {
                 Ignite node = ignite(i);
@@ -284,6 +309,9 @@
 
                 for (final TransactionConcurrency concurrency : TransactionConcurrency.values()) {
                     for (final TransactionIsolation isolation : TransactionIsolation.values()) {
+                        if (MvccFeatureChecker.forcedMvcc() && !MvccFeatureChecker.isSupported(concurrency, isolation))
+                            continue;
+
                         singleKeyPrimaryNodeLeft(node, ccfg, new IgniteBiInClosure<Integer, IgniteCache<Object, Object>>() {
                             @Override public void apply(Integer key, IgniteCache<Object, Object> cache) {
                                 Ignite ignite = cache.unwrap(Ignite.class);
@@ -372,6 +400,9 @@
      * @throws Exception If failed.
      */
     public void testSingleKeyCommit() throws Exception {
+        if (MvccFeatureChecker.forcedMvcc())
+            fail("https://issues.apache.org/jira/browse/IGNITE-10518");
+
         singleKeyCommit(cacheConfiguration(DEFAULT_CACHE_NAME, PRIMARY_SYNC, 1, true, false));
 
         singleKeyCommit(cacheConfiguration(DEFAULT_CACHE_NAME, PRIMARY_SYNC, 2, false, false));
@@ -386,12 +417,23 @@
      * @throws Exception If failed.
      */
     private void singleKeyCommit(CacheConfiguration<Object, Object> ccfg) throws Exception {
+        if (MvccFeatureChecker.forcedMvcc()) {
+            if (ccfg.getCacheStoreFactory() != null &&
+                !MvccFeatureChecker.isSupported(Feature.CACHE_STORE))
+                return;
+
+            if (ccfg.getNearConfiguration() != null &&
+                !MvccFeatureChecker.isSupported(Feature.NEAR_CACHE))
+                return;
+        }
+
         Ignite ignite = ignite(0);
 
         IgniteCache<Object, Object> cache = ignite.createCache(ccfg);
 
         try {
-            ignite(NODES - 1).createNearCache(ccfg.getName(), new NearCacheConfiguration<>());
+            if (!MvccFeatureChecker.forcedMvcc() || MvccFeatureChecker.isSupported(Feature.NEAR_CACHE))
+                ignite(NODES - 1).createNearCache(ccfg.getName(), new NearCacheConfiguration<>());
 
             for (int i = 1; i < NODES; i++) {
                 Ignite node = ignite(i);
@@ -406,6 +448,9 @@
 
                 for (final TransactionConcurrency concurrency : TransactionConcurrency.values()) {
                     for (final TransactionIsolation isolation : TransactionIsolation.values()) {
+                        if (MvccFeatureChecker.forcedMvcc() && !MvccFeatureChecker.isSupported(concurrency, isolation))
+                            continue;
+
                         singleKeyCommit(node, ccfg, new IgniteBiInClosure<Integer, IgniteCache<Object, Object>>() {
                             @Override public void apply(Integer key, IgniteCache<Object, Object> cache) {
                                 Ignite ignite = cache.unwrap(Ignite.class);
@@ -528,12 +573,23 @@
      * @throws Exception If failed.
      */
     private void checkWaitPrimaryResponse(CacheConfiguration<Object, Object> ccfg) throws Exception {
+        if (MvccFeatureChecker.forcedMvcc()) {
+            if (ccfg.getCacheStoreFactory() != null &&
+                !MvccFeatureChecker.isSupported(Feature.CACHE_STORE))
+                return;
+
+            if (ccfg.getNearConfiguration() != null &&
+                !MvccFeatureChecker.isSupported(Feature.NEAR_CACHE))
+                return;
+        }
+
         Ignite ignite = ignite(0);
 
         IgniteCache<Object, Object> cache = ignite.createCache(ccfg);
 
         try {
-            ignite(NODES - 1).createNearCache(ccfg.getName(), new NearCacheConfiguration<>());
+            if (!MvccFeatureChecker.forcedMvcc() || MvccFeatureChecker.isSupported(Feature.NEAR_CACHE))
+                ignite(NODES - 1).createNearCache(ccfg.getName(), new NearCacheConfiguration<>());
 
             for (int i = 1; i < NODES; i++) {
                 Ignite node = ignite(i);
@@ -561,6 +617,9 @@
 
                 for (final TransactionConcurrency concurrency : TransactionConcurrency.values()) {
                     for (final TransactionIsolation isolation : TransactionIsolation.values()) {
+                        if (MvccFeatureChecker.forcedMvcc() && !MvccFeatureChecker.isSupported(concurrency, isolation))
+                            continue;
+
                         checkWaitPrimaryResponse(node, ccfg, new IgniteBiInClosure<Integer, IgniteCache<Object, Object>>() {
                             @Override public void apply(Integer key, IgniteCache<Object, Object> cache) {
                                 Ignite ignite = cache.unwrap(Ignite.class);
@@ -652,6 +711,9 @@
      * @throws Exception If failed.
      */
     public void testOnePhaseMessages() throws Exception {
+        if (MvccFeatureChecker.forcedMvcc())
+            return; // Not supported. Commit flow differs for Mvcc mode.
+
         checkOnePhaseMessages(cacheConfiguration(DEFAULT_CACHE_NAME, PRIMARY_SYNC, 1, false, false));
     }
 
@@ -678,6 +740,9 @@
 
                 for (final TransactionConcurrency concurrency : TransactionConcurrency.values()) {
                     for (final TransactionIsolation isolation : TransactionIsolation.values()) {
+                        if (MvccFeatureChecker.forcedMvcc() && !MvccFeatureChecker.isSupported(concurrency, isolation))
+                            continue;
+
                         checkOnePhaseMessages(node, ccfg, new IgniteBiInClosure<Integer, IgniteCache<Object, Object>>() {
                             @Override public void apply(Integer key, IgniteCache<Object, Object> cache) {
                                 Ignite ignite = cache.unwrap(Ignite.class);
@@ -760,12 +825,13 @@
         List<IgniteCache<Object, Object>> caches = new ArrayList<>();
 
         try {
-            caches.add(createCache(ignite, cacheConfiguration("fullSync1", FULL_SYNC, 1, false, false), true));
-            caches.add(createCache(ignite, cacheConfiguration("fullSync2", FULL_SYNC, 1, false, false), true));
-            caches.add(createCache(ignite, cacheConfiguration("fullAsync1", FULL_ASYNC, 1, false, false), true));
-            caches.add(createCache(ignite, cacheConfiguration("fullAsync2", FULL_ASYNC, 1, false, false), true));
-            caches.add(createCache(ignite, cacheConfiguration("primarySync1", PRIMARY_SYNC, 1, false, false), true));
-            caches.add(createCache(ignite, cacheConfiguration("primarySync2", PRIMARY_SYNC, 1, false, false), true));
+
+            caches.add(createCache(ignite, cacheConfiguration("fullSync1", FULL_SYNC, 1, false, false)));
+            caches.add(createCache(ignite, cacheConfiguration("fullSync2", FULL_SYNC, 1, false, false)));
+            caches.add(createCache(ignite, cacheConfiguration("fullAsync1", FULL_ASYNC, 1, false, false)));
+            caches.add(createCache(ignite, cacheConfiguration("fullAsync2", FULL_ASYNC, 1, false, false)));
+            caches.add(createCache(ignite, cacheConfiguration("primarySync1", PRIMARY_SYNC, 1, false, false)));
+            caches.add(createCache(ignite, cacheConfiguration("primarySync2", PRIMARY_SYNC, 1, false, false)));
 
             for (int i = 0; i < NODES; i++) {
                 checkTxSyncMode(ignite(i), true);
@@ -805,7 +871,8 @@
      * @param key Cache key.
      * @throws Exception If failed.
      */
-    private void waitKeyUpdated(Ignite ignite, int expNodes, final String cacheName, final Object key) throws Exception {
+    private void waitKeyUpdated(Ignite ignite, int expNodes, final String cacheName,
+        final Object key) throws Exception {
         Affinity<Object> aff = ignite.affinity(cacheName);
 
         final Collection<ClusterNode> nodes = aff.mapKeyToPrimaryAndBackups(key);
@@ -834,14 +901,12 @@
     /**
      * @param ignite Node.
      * @param ccfg Cache configuration.
-     * @param nearCache If {@code true} creates near cache on one of client nodes.
      * @return Created cache.
      */
-    private <K, V> IgniteCache<K, V> createCache(Ignite ignite, CacheConfiguration<K, V> ccfg,
-        boolean nearCache) {
+    private <K, V> IgniteCache<K, V> createCache(Ignite ignite, CacheConfiguration<K, V> ccfg) {
         IgniteCache<K, V> cache = ignite.createCache(ccfg);
 
-        if (nearCache)
+        if (!MvccFeatureChecker.forcedMvcc() || MvccFeatureChecker.isSupported(Feature.NEAR_CACHE))
             ignite(NODES - 1).createNearCache(ccfg.getName(), new NearCacheConfiguration<>());
 
         return cache;
@@ -866,6 +931,9 @@
 
             for (TransactionConcurrency concurrency : TransactionConcurrency.values()) {
                 for (TransactionIsolation isolation : TransactionIsolation.values()) {
+                    if (MvccFeatureChecker.forcedMvcc() && !MvccFeatureChecker.isSupported(concurrency, isolation))
+                        continue;
+
                     try (Transaction tx = txs.txStart(concurrency, isolation)) {
                         fullSync1.put(key++, 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 bed8a41..86d20db 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,13 +32,14 @@
 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;
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.configuration.NearCacheConfiguration;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.IgniteInternalFuture;
 import org.apache.ignite.internal.util.lang.GridAbsPredicate;
 import org.apache.ignite.internal.util.typedef.internal.U;
@@ -49,6 +50,7 @@
 import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder;
 import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
 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.TransactionOptimisticException;
@@ -105,24 +107,31 @@
 
     /** {@inheritDoc} */
     @Override protected void beforeTestsStarted() throws Exception {
+        if (MvccFeatureChecker.forcedMvcc())
+            fail("https://issues.apache.org/jira/browse/IGNITE-9470");
+
         super.beforeTestsStarted();
 
-        System.setProperty(IgniteSystemProperties.IGNITE_ENABLE_FORCIBLE_NODE_KILL,"true");
-
-        startGrids(SRVS);
+        startGridsMultiThreaded(SRVS);
 
         clientMode = true;
 
-        for (int i = 0; i < CLIENTS; i++) {
-            Ignite client = startGrid(SRVS + i);
+        startGridsMultiThreaded(SRVS, CLIENTS);
 
-            assertTrue(client.configuration().isClientMode());
-        }
+        for (int i = 0; i < CLIENTS; i++)
+            assertTrue(grid(SRVS + i).configuration().isClientMode());
     }
 
     /** {@inheritDoc} */
     @Override protected void afterTestsStopped() throws Exception {
-        System.clearProperty(IgniteSystemProperties.IGNITE_ENABLE_FORCIBLE_NODE_KILL);
+        stopAllGrids();
+
+        super.afterTestsStopped();
+    }
+
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
     }
 
     /**
@@ -195,6 +204,14 @@
         boolean store,
         boolean nearCache,
         boolean restart) throws Exception {
+        if (MvccFeatureChecker.forcedMvcc()) {
+            if (store && !MvccFeatureChecker.isSupported(MvccFeatureChecker.Feature.CACHE_STORE))
+                return;
+
+            if (nearCache && !MvccFeatureChecker.isSupported(MvccFeatureChecker.Feature.NEAR_CACHE))
+                return;
+        }
+
         final Ignite ignite = ignite(0);
 
         createCache(ignite, cacheConfiguration(DEFAULT_CACHE_NAME, syncMode, backups, store), nearCache);
@@ -271,36 +288,38 @@
                 }
             });
 
-            commitMultithreaded(new IgniteBiInClosure<Ignite, IgniteCache<Integer, Integer>>() {
-                @Override public void apply(Ignite ignite, IgniteCache<Integer, Integer> cache) {
-                    ThreadLocalRandom rnd = ThreadLocalRandom.current();
+            if (!MvccFeatureChecker.forcedMvcc()) {
+                commitMultithreaded(new IgniteBiInClosure<Ignite, IgniteCache<Integer, Integer>>() {
+                    @Override public void apply(Ignite ignite, IgniteCache<Integer, Integer> cache) {
+                        ThreadLocalRandom rnd = ThreadLocalRandom.current();
 
-                    Map<Integer, Integer> map = new LinkedHashMap<>();
+                        Map<Integer, Integer> map = new LinkedHashMap<>();
 
-                    for (int i = 0; i < 10; i++) {
-                        Integer key = rnd.nextInt(MULTITHREADED_TEST_KEYS);
+                        for (int i = 0; i < 10; i++) {
+                            Integer key = rnd.nextInt(MULTITHREADED_TEST_KEYS);
 
-                        map.put(key, rnd.nextInt());
-                    }
-
-                    while (true) {
-                        try (Transaction tx = ignite.transactions().txStart(OPTIMISTIC, SERIALIZABLE)) {
-                            for (Map.Entry<Integer, Integer> e : map.entrySet())
-                                cache.put(e.getKey(), e.getValue());
-
-                            tx.commit();
-
-                            break;
+                            map.put(key, rnd.nextInt());
                         }
-                        catch (TransactionOptimisticException ignored) {
-                           // Retry.
-                        }
-                        catch (CacheException | IgniteException ignored) {
-                            break;
+
+                        while (true) {
+                            try (Transaction tx = ignite.transactions().txStart(OPTIMISTIC, SERIALIZABLE)) {
+                                for (Map.Entry<Integer, Integer> e : map.entrySet())
+                                    cache.put(e.getKey(), e.getValue());
+
+                                tx.commit();
+
+                                break;
+                            }
+                            catch (TransactionOptimisticException ignored) {
+                                // Retry.
+                            }
+                            catch (CacheException | IgniteException ignored) {
+                                break;
+                            }
                         }
                     }
-                }
-            });
+                });
+            }
         }
         finally {
             stop.set(true);
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 a5b2cb7..cd5cbe6 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
@@ -36,9 +36,11 @@
 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.TransactionConcurrency;
+import org.apache.ignite.transactions.TransactionIsolation;
 
 import static org.apache.ignite.IgniteSystemProperties.IGNITE_CACHE_REMOVED_ENTRIES_TTL;
-import static org.apache.ignite.transactions.TransactionConcurrency.OPTIMISTIC;
+import static org.apache.ignite.transactions.TransactionIsolation.REPEATABLE_READ;
 import static org.apache.ignite.transactions.TransactionIsolation.SERIALIZABLE;
 
 /**
@@ -67,25 +69,22 @@
         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 {
+        stopAllGrids();
+
         System.setProperty(IGNITE_CACHE_REMOVED_ENTRIES_TTL, Long.toString(oldIgniteCacheRmvEntriesTtl));
 
         super.afterTestsStopped();
     }
 
     /** {@inheritDoc} */
-    @Override protected void beforeTest() throws Exception {
-        super.beforeTest();
-
-        stopAllGrids();
-    }
-
-    /** {@inheritDoc} */
     @Override protected void afterTest() throws Exception {
-        stopAllGrids();
+        grid(0).destroyCache(DEFAULT_CACHE_NAME);
 
         super.afterTest();
     }
@@ -102,7 +101,7 @@
     /**
      * @return Cache configuration.
      */
-    private CacheConfiguration<Integer, String> getCacheCfg() {
+    private CacheConfiguration<Integer, String> cacheConfiguration() {
         CacheConfiguration<Integer, String> ccfg = new CacheConfiguration<>();
 
         ccfg.setName(DEFAULT_CACHE_NAME);
@@ -115,16 +114,39 @@
     }
 
     /**
+     * @throws Exception If failed.
+     */
+    public void testOptimisticTxLeavesObjectsInLocalPartition() throws Exception {
+        checkTxLeavesObjectsInLocalPartition(cacheConfiguration(), TransactionConcurrency.OPTIMISTIC, SERIALIZABLE);
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testPessimisticTxLeavesObjectsInLocalPartition() throws Exception {
+        checkTxLeavesObjectsInLocalPartition(cacheConfiguration(), TransactionConcurrency.PESSIMISTIC, SERIALIZABLE);
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testMvccTxLeavesObjectsInLocalPartition() throws Exception {
+        checkTxLeavesObjectsInLocalPartition(cacheConfiguration().setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL_SNAPSHOT),
+            TransactionConcurrency.PESSIMISTIC, REPEATABLE_READ);
+    }
+
+    /**
      * Too many deletes in single transaction may overflow {@link GridDhtLocalPartition#rmvQueue} and entries will be
      * deleted synchronously in {@link GridDhtLocalPartition#onDeferredDelete(int, KeyCacheObject, GridCacheVersion)}.
      * This should not corrupt internal map state in {@link GridDhtLocalPartition}.
      *
      * @throws Exception If failed.
      */
-    public void testTxLeavesObjectsInLocalPartition() throws Exception {
-        IgniteEx igniteEx = startGrid(getConfiguration());
+    public void checkTxLeavesObjectsInLocalPartition(CacheConfiguration<Integer, String> ccfg,
+        TransactionConcurrency optimistic, TransactionIsolation isolation) throws Exception {
+        IgniteEx igniteEx = grid(0);
 
-        igniteEx.getOrCreateCache(getCacheCfg());
+        igniteEx.getOrCreateCache(ccfg);
 
         try (IgniteDataStreamer<Integer, String> dataStreamer = igniteEx.dataStreamer(DEFAULT_CACHE_NAME)) {
             for (int i = 0; i < CACHE_ENTRIES_COUNT; i++)
@@ -141,8 +163,8 @@
 
         assertEquals(CACHE_ENTRIES_COUNT, client.getOrCreateCache(DEFAULT_CACHE_NAME).size());
 
-        try (Transaction tx = client.transactions().txStart(OPTIMISTIC, SERIALIZABLE)) {
-            IgniteCache<Integer, String> cache = client.getOrCreateCache(getCacheCfg());
+        try (Transaction tx = client.transactions().txStart(optimistic, isolation)) {
+            IgniteCache<Integer, String> cache = client.getOrCreateCache(cacheConfiguration());
 
             for (int v = 0; v < CACHE_ENTRIES_COUNT; v++) {
                 cache.get(v);
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteTxPreloadAbstractTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteTxPreloadAbstractTest.java
index c94457f..65e9f37 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteTxPreloadAbstractTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteTxPreloadAbstractTest.java
@@ -32,6 +32,7 @@
 import org.apache.ignite.internal.IgniteInternalFuture;
 import org.apache.ignite.internal.processors.cache.GridCacheAbstractSelfTest;
 import org.apache.ignite.testframework.GridTestUtils;
+import org.apache.ignite.testframework.MvccFeatureChecker;
 import org.apache.ignite.transactions.Transaction;
 import org.apache.ignite.transactions.TransactionConcurrency;
 import org.apache.ignite.transactions.TransactionIsolation;
@@ -78,6 +79,9 @@
      * @throws Exception If failed.
      */
     public void testRemoteTxPreloading() throws Exception {
+        if (MvccFeatureChecker.forcedMvcc())
+            fail("https://issues.apache.org/jira/browse/IGNITE-10391");
+
         IgniteCache<String, Integer> cache = jcache(0);
 
         for (int i = 0; i < 10_000; i++)
@@ -147,13 +151,17 @@
      * @throws Exception If failed.
      */
     public void testLocalTxPreloadingOptimistic() throws Exception {
-        testLocalTxPreloading(OPTIMISTIC);
+        if (!MvccFeatureChecker.forcedMvcc()) // Do not check optimistic tx for mvcc.
+            testLocalTxPreloading(OPTIMISTIC);
     }
 
     /**
      * @throws Exception If failed.
      */
     public void testLocalTxPreloadingPessimistic() throws Exception {
+        if (MvccFeatureChecker.forcedMvcc())
+            fail("https://issues.apache.org/jira/browse/IGNITE-10391");
+
         testLocalTxPreloading(PESSIMISTIC);
     }
 
@@ -186,7 +194,7 @@
 
             IgniteTransactions txs = ignite(i).transactions();
 
-            try (Transaction tx = txs.txStart(txConcurrency, TransactionIsolation.READ_COMMITTED)) {
+            try (Transaction tx = txs.txStart(txConcurrency, TransactionIsolation.REPEATABLE_READ)) {
                 cache.invoke(TX_KEY, new EntryProcessor<String, Integer, Void>() {
                     @Override public Void process(MutableEntry<String, Integer> e, Object... args) {
                         Integer val = e.getValue();
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteTxRemoveTimeoutObjectsTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteTxRemoveTimeoutObjectsTest.java
index 5713621..bcc72e5 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteTxRemoveTimeoutObjectsTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteTxRemoveTimeoutObjectsTest.java
@@ -32,6 +32,7 @@
 import org.apache.ignite.internal.util.typedef.X;
 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.transactions.Transaction;
 import org.apache.ignite.transactions.TransactionTimeoutException;
 
@@ -55,6 +56,17 @@
         return 60_000;
     }
 
+    /** {@inheritDoc} */
+    @Override public void setUp() throws Exception {
+        if (MvccFeatureChecker.forcedMvcc())
+            fail("https://issues.apache.org/jira/browse/IGNITE-7388");
+
+        if (nearEnabled())
+            MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.NEAR_CACHE);
+
+        super.setUp();
+    }
+
     /**
      * @throws Exception If failed.
      */
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/CacheGetReadFromBackupFailoverTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/CacheGetReadFromBackupFailoverTest.java
new file mode 100644
index 0000000..71cb4ed
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/CacheGetReadFromBackupFailoverTest.java
@@ -0,0 +1,257 @@
+/*
+ * 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.cache.distributed.dht;
+
+import java.util.Collections;
+import java.util.UUID;
+import java.util.concurrent.ThreadLocalRandom;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.stream.Collectors;
+import javax.cache.CacheException;
+import org.apache.ignite.Ignite;
+import org.apache.ignite.IgniteDataStreamer;
+import org.apache.ignite.IgniteIllegalStateException;
+import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.failure.AbstractFailureHandler;
+import org.apache.ignite.failure.FailureContext;
+import org.apache.ignite.internal.IgniteEx;
+import org.apache.ignite.internal.IgniteFutureTimeoutCheckedException;
+import org.apache.ignite.internal.IgniteInternalFuture;
+import org.apache.ignite.internal.IgniteNodeAttributes;
+import org.apache.ignite.internal.NodeStoppingException;
+import org.apache.ignite.internal.processors.cache.GridCacheFuture;
+import org.apache.ignite.internal.processors.cache.GridCacheMvccManager;
+import org.apache.ignite.internal.util.typedef.G;
+import org.apache.ignite.internal.util.typedef.X;
+import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
+import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder;
+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.Assert;
+
+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;
+
+/**
+ * Test for getting values on unstable topology with read from backup enabled.
+ */
+public class CacheGetReadFromBackupFailoverTest extends GridCommonAbstractTest {
+    /** */
+    private static final TcpDiscoveryIpFinder IP_FINDER = new TcpDiscoveryVmIpFinder(true);
+    /** Tx cache name. */
+    private static final String TX_CACHE = "txCache";
+    /** Atomic cache name. */
+    private static final String ATOMIC_CACHE = "atomicCache";
+    /** Keys count. */
+    private static final int KEYS_CNT = 50000;
+    /** Stop load flag. */
+    private static final AtomicBoolean stop = new AtomicBoolean();
+    /** Error. */
+    private static final AtomicReference<Throwable> err = new AtomicReference<>();
+
+    /**
+     * @return Grid count.
+     */
+    public int gridCount() {
+        return 3;
+    }
+
+    /** {@inheritDoc} */
+    @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception {
+        IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName);
+
+        cfg.setFailureHandler(new AbstractFailureHandler() {
+            @Override protected boolean handle(Ignite ignite, FailureContext failureCtx) {
+                err.compareAndSet(null, failureCtx.error());
+                stop.set(true);
+                return false;
+            }
+        });
+
+        cfg.setConsistentId(igniteInstanceName);
+
+        cfg.setDiscoverySpi(new TcpDiscoverySpi().setIpFinder(IP_FINDER));
+
+        CacheConfiguration<Long, Long> txCcfg = new CacheConfiguration<Long, Long>(TX_CACHE)
+            .setAtomicityMode(TRANSACTIONAL)
+            .setCacheMode(PARTITIONED)
+            .setBackups(1)
+            .setWriteSynchronizationMode(FULL_SYNC)
+            .setReadFromBackup(true);
+
+        CacheConfiguration<Long, Long> atomicCcfg = new CacheConfiguration<Long, Long>(ATOMIC_CACHE)
+            .setAtomicityMode(ATOMIC)
+            .setCacheMode(PARTITIONED)
+            .setBackups(1)
+            .setWriteSynchronizationMode(FULL_SYNC)
+            .setReadFromBackup(true);
+
+        cfg.setCacheConfiguration(txCcfg, atomicCcfg);
+
+        // Enforce different mac adresses to emulate distributed environment by default.
+        cfg.setUserAttributes(Collections.singletonMap(
+            IgniteNodeAttributes.ATTR_MACS_OVERRIDE, UUID.randomUUID().toString()));
+
+        return cfg;
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void beforeTest() throws Exception {
+        super.beforeTest();
+
+        stop.set(false);
+
+        err.set(null);
+
+        startGrids(gridCount());
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void afterTest() throws Exception {
+        super.afterTest();
+
+        stopAllGrids();
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testFailover() throws Exception {
+        Ignite ignite = ignite(0);
+
+        ignite.cluster().active(true);
+
+        ThreadLocalRandom rnd = ThreadLocalRandom.current();
+
+        try (IgniteDataStreamer<Object, Object> stmr = ignite.dataStreamer(TX_CACHE)) {
+            for (int i = 0; i < KEYS_CNT; i++)
+                stmr.addData(i, rnd.nextLong());
+        }
+
+        try (IgniteDataStreamer<Object, Object> stmr = ignite.dataStreamer(ATOMIC_CACHE)) {
+            for (int i = 0; i < KEYS_CNT; i++)
+                stmr.addData(i, rnd.nextLong());
+        }
+
+        AtomicInteger idx = new AtomicInteger(-1);
+
+        AtomicInteger successGet = new AtomicInteger();
+
+        IgniteInternalFuture fut = GridTestUtils.runAsync(() -> {
+            ThreadLocalRandom rnd0 = ThreadLocalRandom.current();
+
+            while (!stop.get()) {
+                Ignite ig = null;
+
+                while (ig == null) {
+                    int n = rnd0.nextInt(gridCount());
+
+                    if (idx.get() != n) {
+                        try {
+                            ig = ignite(n);
+                        }
+                        catch (IgniteIllegalStateException e) {
+                            // No-op.
+                        }
+                    }
+                }
+
+                try {
+                    if (rnd.nextBoolean()) {
+                        ig.cache(TX_CACHE).get(rnd0.nextLong(KEYS_CNT));
+                        ig.cache(ATOMIC_CACHE).get(rnd0.nextLong(KEYS_CNT));
+                    }
+                    else {
+                        ig.cache(TX_CACHE).getAll(rnd.longs(16, 0, KEYS_CNT).boxed().collect(Collectors.toSet()));
+                        ig.cache(ATOMIC_CACHE).getAll(rnd.longs(16, 0, KEYS_CNT).boxed().collect(Collectors.toSet()));
+                    }
+
+                    successGet.incrementAndGet();
+                }
+                catch (CacheException e) {
+                    if (!X.hasCause(e, NodeStoppingException.class))
+                        throw e;
+                }
+
+            }
+        }, "load-thread");
+
+        long startTime = System.currentTimeMillis();
+
+        while (System.currentTimeMillis() - startTime < 30 * 1000L) {
+            int idx0 = idx.get();
+
+            if (idx0 >= 0)
+                startGrid(idx0);
+
+            U.sleep(500);
+
+            int next = rnd.nextInt(gridCount());
+
+            idx.set(next);
+
+            stopGrid(next);
+
+            U.sleep(500);
+        }
+
+        stop.set(true);
+
+        while (true){
+            try {
+                fut.get(10_000);
+
+                break;
+            }
+            catch (IgniteFutureTimeoutCheckedException e) {
+                for (Ignite i : G.allGrids()) {
+                    IgniteEx ex = (IgniteEx)i;
+
+                    log.info(">>>> " + ex.context().localNodeId());
+
+                    GridCacheMvccManager mvcc = ex.context().cache().context().mvcc();
+
+                    for (GridCacheFuture<?> fut0 : mvcc.activeFutures()) {
+                        log.info("activeFut - " + fut0);
+                    }
+
+                    for (GridCacheFuture<?> fut0 : mvcc.atomicFutures()) {
+                        log.info("atomicFut - " + fut0);
+                    }
+                }
+            }
+        }
+
+        Assert.assertTrue(String.valueOf(successGet.get()), successGet.get() > 50);
+
+        Throwable e = err.get();
+
+        if (e != null) {
+            log.error("Test failed", e);
+
+            fail("Test failed");
+        }
+    }
+}
\ No newline at end of file
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridCacheAbstractPartitionedOnlyByteArrayValuesSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridCacheAbstractPartitionedOnlyByteArrayValuesSelfTest.java
index 86738f5..18459c9 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridCacheAbstractPartitionedOnlyByteArrayValuesSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridCacheAbstractPartitionedOnlyByteArrayValuesSelfTest.java
@@ -34,9 +34,6 @@
     /** Offheap cache name. */
     protected static final String CACHE_ATOMIC = "cache_atomic";
 
-    /** Offheap cache name. */
-    protected static final String CACHE_ATOMIC_OFFHEAP = "cache_atomic_offheap";
-
     /** Atomic caches. */
     private static IgniteCache<Integer, Object>[] cachesAtomic;
 
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridCacheAbstractTransformWriteThroughSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridCacheAbstractTransformWriteThroughSelfTest.java
index 34c96fd..1c1f3a5 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridCacheAbstractTransformWriteThroughSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridCacheAbstractTransformWriteThroughSelfTest.java
@@ -31,6 +31,7 @@
 import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
 import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder;
 import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
+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;
@@ -132,6 +133,8 @@
 
     /** {@inheritDoc} */
     @Override protected void beforeTestsStarted() throws Exception {
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.CACHE_STORE);
+
         super.beforeTestsStarted();
 
         for (int i = 0; i < GRID_CNT; i++)
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridCachePartitionedTopologyChangeSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridCachePartitionedTopologyChangeSelfTest.java
index 2051616..3ea2916 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridCachePartitionedTopologyChangeSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridCachePartitionedTopologyChangeSelfTest.java
@@ -36,6 +36,8 @@
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.events.Event;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.IgniteInternalFuture;
 import org.apache.ignite.internal.IgniteKernal;
 import org.apache.ignite.internal.processors.cache.GridCacheContext;
@@ -77,6 +79,11 @@
     }
 
     /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
+    /** {@inheritDoc} */
     @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception {
         IgniteConfiguration c = super.getConfiguration(igniteInstanceName);
 
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/IgniteAtomicLongChangingTopologySelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/IgniteAtomicLongChangingTopologySelfTest.java
index 2c6d187..696e5cf 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/IgniteAtomicLongChangingTopologySelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/IgniteAtomicLongChangingTopologySelfTest.java
@@ -37,6 +37,8 @@
 import org.apache.ignite.configuration.AtomicConfiguration;
 import org.apache.ignite.configuration.CollectionConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.IgniteInternalFuture;
 import org.apache.ignite.internal.util.typedef.internal.U;
 import org.apache.ignite.lang.IgniteInClosure;
@@ -105,6 +107,11 @@
         queue.clear();
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * @throws Exception If failed.
      */
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/IgniteCacheCrossCacheTxFailoverTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/IgniteCacheCrossCacheTxFailoverTest.java
index 40f9dc4..f5115c1 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/IgniteCacheCrossCacheTxFailoverTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/IgniteCacheCrossCacheTxFailoverTest.java
@@ -33,6 +33,8 @@
 import org.apache.ignite.cache.affinity.rendezvous.RendezvousAffinityFunction;
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.IgniteFutureTimeoutCheckedException;
 import org.apache.ignite.internal.IgniteInternalFuture;
 import org.apache.ignite.internal.IgniteKernal;
@@ -132,6 +134,11 @@
         return TEST_TIME + 60_000;
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * @throws Exception If failed.
      */
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/IgniteCacheLockFailoverSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/IgniteCacheLockFailoverSelfTest.java
index f813ef8..2ab36f2 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/IgniteCacheLockFailoverSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/IgniteCacheLockFailoverSelfTest.java
@@ -22,6 +22,8 @@
 import org.apache.ignite.IgniteCache;
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.IgniteInternalFuture;
 import org.apache.ignite.internal.IgniteKernal;
 import org.apache.ignite.internal.processors.cache.GridCacheAbstractSelfTest;
@@ -31,6 +33,7 @@
 import org.apache.ignite.lang.IgniteFutureTimeoutException;
 import org.apache.ignite.spi.communication.tcp.TcpCommunicationSpi;
 import org.apache.ignite.testframework.GridTestUtils;
+import org.apache.ignite.testframework.MvccFeatureChecker;
 
 /**
  *
@@ -38,6 +41,13 @@
 @SuppressWarnings("unchecked")
 public class IgniteCacheLockFailoverSelfTest extends GridCacheAbstractSelfTest {
     /** {@inheritDoc} */
+    @Override public void setUp() throws Exception {
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.ENTRY_LOCK);
+
+        super.setUp();
+    }
+
+    /** {@inheritDoc} */
     @Override protected int gridCount() {
         return 2;
     }
@@ -82,6 +92,11 @@
         return 2 * 60_000;
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * @throws Exception If failed.
      */
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/IgniteCacheMultiTxLockSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/IgniteCacheMultiTxLockSelfTest.java
index bc3b13d..d7454fd 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/IgniteCacheMultiTxLockSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/IgniteCacheMultiTxLockSelfTest.java
@@ -22,6 +22,7 @@
 import java.util.TreeMap;
 import java.util.concurrent.ThreadLocalRandom;
 import java.util.concurrent.TimeUnit;
+import org.apache.ignite.IgniteCheckedException;
 import org.apache.ignite.cache.eviction.lru.LruEvictionPolicy;
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
@@ -33,6 +34,7 @@
 import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
 import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder;
 import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
+import org.apache.ignite.testframework.MvccFeatureChecker;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
 
 import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL;
@@ -55,6 +57,16 @@
     /** */
     private boolean client;
 
+    /** Unexpected lock error. */
+    private volatile Throwable err;
+
+    /** {@inheritDoc} */
+    @Override public void setUp() throws Exception {
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.ENTRY_LOCK);
+
+        super.setUp();
+    }
+
     /** {@inheritDoc} */
     @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception {
         IgniteConfiguration c = super.getConfiguration(igniteInstanceName);
@@ -120,6 +132,8 @@
     public void checkExplicitLock(int keys, boolean testClient) throws Exception {
         Collection<Thread> threads = new ArrayList<>();
 
+        err = null;
+
         try {
             // Start grid 1.
             IgniteEx grid1 = startGrid(1);
@@ -171,6 +185,8 @@
 
                 assertEquals("txMap is not empty:" + i, 0, tm.idMapSize());
             }
+
+            assertNull(err);
         }
         finally {
             stopAllGrids();
@@ -214,7 +230,7 @@
                             else
                                 cache.removeAll(vals.keySet());
                         }
-                        catch (Exception e) {
+                        catch (IgniteCheckedException e) {
                             U.error(log(), "Failed cache operation.", e);
                         }
                         finally {
@@ -223,8 +239,12 @@
 
                         U.sleep(100);
                     }
-                    catch (Exception e){
+                    catch (Throwable e){
                         U.error(log(), "Failed unlock.", e);
+
+                        err = e;
+
+                        return;
                     }
                 }
             }
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/IgniteCachePutRetryAbstractSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/IgniteCachePutRetryAbstractSelfTest.java
index fbb7c3a..85eb8d1 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/IgniteCachePutRetryAbstractSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/IgniteCachePutRetryAbstractSelfTest.java
@@ -44,6 +44,8 @@
 import org.apache.ignite.configuration.AtomicConfiguration;
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.IgniteInternalFuture;
 import org.apache.ignite.internal.IgniteKernal;
 import org.apache.ignite.internal.cluster.ClusterTopologyCheckedException;
@@ -161,6 +163,11 @@
         }
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * @return Cache atomicity mode.
      */
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/IgniteCacheTopologySplitAbstractTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/IgniteCacheTopologySplitAbstractTest.java
index 4422d1e..25859dc 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/IgniteCacheTopologySplitAbstractTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/IgniteCacheTopologySplitAbstractTest.java
@@ -27,6 +27,8 @@
 import org.apache.ignite.IgniteCheckedException;
 import org.apache.ignite.cluster.ClusterNode;
 import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.IgniteEx;
 import org.apache.ignite.internal.IgniteInternalFuture;
 import org.apache.ignite.internal.TestRecordingCommunicationSpi;
@@ -62,6 +64,11 @@
         return cfg;
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * @param seg Cluster segment.
      * @param topVer Topology version to wait for.
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/IgniteCacheTxRecoveryRollbackTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/IgniteCacheTxRecoveryRollbackTest.java
index 11c4c67..ee7e876 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/IgniteCacheTxRecoveryRollbackTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/IgniteCacheTxRecoveryRollbackTest.java
@@ -36,6 +36,8 @@
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.configuration.NearCacheConfiguration;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.IgniteInternalFuture;
 import org.apache.ignite.internal.IgniteKernal;
 import org.apache.ignite.internal.TestRecordingCommunicationSpi;
@@ -112,6 +114,11 @@
         }
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * @throws Exception If failed.
      */
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/IgniteCrossCacheMvccTxSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/IgniteCrossCacheMvccTxSelfTest.java
new file mode 100644
index 0000000..63a255e
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/IgniteCrossCacheMvccTxSelfTest.java
@@ -0,0 +1,39 @@
+/*
+ * 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.cache.distributed.dht;
+
+import org.apache.ignite.cache.CacheAtomicityMode;
+
+import static org.apache.ignite.transactions.TransactionConcurrency.PESSIMISTIC;
+import static org.apache.ignite.transactions.TransactionIsolation.REPEATABLE_READ;
+
+/**
+ *
+ */
+public class IgniteCrossCacheMvccTxSelfTest extends IgniteCrossCacheTxAbstractSelfTest {
+    /** {@inheritDoc} */
+    @Override public CacheAtomicityMode atomicityMode() {
+        return CacheAtomicityMode.TRANSACTIONAL_SNAPSHOT;
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testPessimisticRepeatableRead() throws Exception {
+        checkTxsSingleOp(PESSIMISTIC, REPEATABLE_READ);
+    }
+}
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/IgniteCrossCacheTxAbstractSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/IgniteCrossCacheTxAbstractSelfTest.java
new file mode 100644
index 0000000..5224daf
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/IgniteCrossCacheTxAbstractSelfTest.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.cache.distributed.dht;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.ThreadLocalRandom;
+import org.apache.ignite.IgniteCache;
+import org.apache.ignite.cache.CacheAtomicityMode;
+import org.apache.ignite.cluster.ClusterNode;
+import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.configuration.NearCacheConfiguration;
+import org.apache.ignite.internal.IgniteEx;
+import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
+import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder;
+import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
+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 static org.apache.ignite.cache.CacheWriteSynchronizationMode.FULL_SYNC;
+
+/**
+ * Tests specific combinations of cross-cache transactions.
+ */
+public abstract class IgniteCrossCacheTxAbstractSelfTest extends GridCommonAbstractTest {
+    /** */
+    private static final TcpDiscoveryIpFinder IP_FINDER = new TcpDiscoveryVmIpFinder(true);
+
+    /** */
+    private static final String FIRST_CACHE = "FirstCache";
+
+    /** */
+    private static final String SECOND_CACHE = "SecondCache";
+
+    /** */
+    private static final int TX_CNT = 500;
+
+    /** {@inheritDoc} */
+    @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception {
+        IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName);
+
+        ((TcpDiscoverySpi)cfg.getDiscoverySpi()).setIpFinder(IP_FINDER);
+
+        return cfg;
+    }
+
+    /**
+     * @return Node count for this test.
+     */
+    private int nodeCount() {
+        return 4;
+    }
+
+    /**
+     * @return {@code True} if near cache should be enabled.
+     */
+    protected boolean nearEnabled() {
+        return false;
+    }
+
+    /** {@inheritDoc} */
+    @SuppressWarnings("unchecked")
+    @Override protected void beforeTestsStarted() throws Exception {
+        startGridsMultiThreaded(nodeCount());
+
+        CacheConfiguration firstCfg = new CacheConfiguration(FIRST_CACHE);
+        firstCfg.setBackups(1);
+        firstCfg.setAtomicityMode(atomicityMode());
+        firstCfg.setWriteSynchronizationMode(FULL_SYNC);
+
+        grid(0).createCache(firstCfg);
+
+        CacheConfiguration secondCfg = new CacheConfiguration(SECOND_CACHE);
+        secondCfg.setBackups(1);
+        secondCfg.setAtomicityMode(atomicityMode());
+        secondCfg.setWriteSynchronizationMode(FULL_SYNC);
+
+        if (nearEnabled())
+            secondCfg.setNearConfiguration(new NearCacheConfiguration());
+
+        grid(0).createCache(secondCfg);
+    }
+
+    /**
+     * @return Atomicity mode.
+     */
+    public abstract CacheAtomicityMode atomicityMode();
+
+    /**
+     * @param concurrency Concurrency.
+     * @param isolation Isolation.
+     * @throws Exception If failed.
+     */
+    protected void checkTxsSingleOp(TransactionConcurrency concurrency, TransactionIsolation isolation) throws Exception {
+        Map<Integer, String> firstCheck = new HashMap<>();
+        Map<Integer, String> secondCheck = new HashMap<>();
+
+        for (int i = 0; i < TX_CNT; i++) {
+            int grid = ThreadLocalRandom.current().nextInt(nodeCount());
+
+            IgniteCache<Integer, String> first = grid(grid).cache(FIRST_CACHE);
+            IgniteCache<Integer, String> second = grid(grid).cache(SECOND_CACHE);
+
+            try (Transaction tx = grid(grid).transactions().txStart(concurrency, isolation)) {
+                try {
+                    int size = ThreadLocalRandom.current().nextInt(24) + 1;
+
+                    for (int k = 0; k < size; k++) {
+                        boolean rnd = ThreadLocalRandom.current().nextBoolean();
+
+                        IgniteCache<Integer, String> cache = rnd ? first : second;
+                        Map<Integer, String> check = rnd ? firstCheck : secondCheck;
+
+                        String val = rnd ? "first" + i : "second" + i;
+
+                        cache.put(k, val);
+                        check.put(k, val);
+                    }
+
+                    tx.commit();
+                }
+                catch (Throwable e) {
+                    e.printStackTrace();
+
+                    throw e;
+                }
+            }
+
+            if (i > 0 && i % 100 == 0)
+                info("Finished iteration: " + i);
+        }
+
+        for (int g = 0; g < nodeCount(); g++) {
+            IgniteEx grid = grid(g);
+
+            assertEquals(0, grid.context().cache().context().tm().idMapSize());
+
+            ClusterNode locNode = grid.localNode();
+
+            IgniteCache<Object, Object> firstCache = grid.cache(FIRST_CACHE);
+
+            for (Map.Entry<Integer, String> entry : firstCheck.entrySet()) {
+                boolean primary = grid.affinity(FIRST_CACHE).isPrimary(locNode, entry.getKey());
+
+                boolean backup = grid.affinity(FIRST_CACHE).isBackup(locNode, entry.getKey());
+
+                assertEquals("Invalid value found first cache [primary=" + primary + ", backup=" + backup +
+                        ", node=" + locNode.id() + ", key=" + entry.getKey() + ']',
+                    entry.getValue(), firstCache.get(entry.getKey()));
+            }
+
+            for (Map.Entry<Integer, String> entry : secondCheck.entrySet()) {
+                boolean primary = grid.affinity(SECOND_CACHE).isPrimary(locNode, entry.getKey());
+
+                boolean backup = grid.affinity(SECOND_CACHE).isBackup(locNode, entry.getKey());
+
+                assertEquals("Invalid value found second cache [primary=" + primary + ", backup=" + backup +
+                        ", node=" + locNode.id() + ", key=" + entry.getKey() + ']',
+                    entry.getValue(), grid.cache(SECOND_CACHE).get(entry.getKey()));
+            }
+        }
+    }
+}
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/IgniteCrossCacheTxSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/IgniteCrossCacheTxSelfTest.java
index 91c6685..3b0106c 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/IgniteCrossCacheTxSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/IgniteCrossCacheTxSelfTest.java
@@ -14,28 +14,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 package org.apache.ignite.internal.processors.cache.distributed.dht;
 
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.ThreadLocalRandom;
-import org.apache.ignite.IgniteCache;
-import org.apache.ignite.cluster.ClusterNode;
-import org.apache.ignite.configuration.CacheConfiguration;
-import org.apache.ignite.configuration.IgniteConfiguration;
-import org.apache.ignite.configuration.NearCacheConfiguration;
-import org.apache.ignite.internal.IgniteEx;
-import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
-import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder;
-import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
-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.cache.CacheAtomicityMode;
 
-import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL;
-import static org.apache.ignite.cache.CacheWriteSynchronizationMode.FULL_SYNC;
 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;
@@ -43,65 +25,12 @@
 import static org.apache.ignite.transactions.TransactionIsolation.SERIALIZABLE;
 
 /**
- * Tests specific combinations of cross-cache transactions.
+ *
  */
-public class IgniteCrossCacheTxSelfTest extends GridCommonAbstractTest {
-    /** */
-    private static final TcpDiscoveryIpFinder IP_FINDER = new TcpDiscoveryVmIpFinder(true);
-
-    /** */
-    private static final String FIRST_CACHE = "FirstCache";
-
-    /** */
-    private static final String SECOND_CACHE = "SecondCache";
-
-    /** */
-    private static final int TX_CNT = 500;
-
+public class IgniteCrossCacheTxSelfTest extends IgniteCrossCacheTxAbstractSelfTest {
     /** {@inheritDoc} */
-    @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception {
-        IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName);
-
-        ((TcpDiscoverySpi)cfg.getDiscoverySpi()).setIpFinder(IP_FINDER);
-
-        return cfg;
-    }
-
-    /**
-     * @return Node count for this test.
-     */
-    private int nodeCount() {
-        return 4;
-    }
-
-    /**
-     * @return {@code True} if near cache should be enabled.
-     */
-    protected boolean nearEnabled() {
-        return false;
-    }
-
-    /** {@inheritDoc} */
-    @SuppressWarnings("unchecked")
-    @Override protected void beforeTestsStarted() throws Exception {
-        startGridsMultiThreaded(nodeCount());
-
-        CacheConfiguration firstCfg = new CacheConfiguration(FIRST_CACHE);
-        firstCfg.setBackups(1);
-        firstCfg.setAtomicityMode(TRANSACTIONAL);
-        firstCfg.setWriteSynchronizationMode(FULL_SYNC);
-
-        grid(0).createCache(firstCfg);
-
-        CacheConfiguration secondCfg = new CacheConfiguration(SECOND_CACHE);
-        secondCfg.setBackups(1);
-        secondCfg.setAtomicityMode(TRANSACTIONAL);
-        secondCfg.setWriteSynchronizationMode(FULL_SYNC);
-
-        if (nearEnabled())
-            secondCfg.setNearConfiguration(new NearCacheConfiguration());
-
-        grid(0).createCache(secondCfg);
+    @Override public CacheAtomicityMode atomicityMode() {
+        return CacheAtomicityMode.TRANSACTIONAL;
     }
 
     /**
@@ -139,78 +68,4 @@
         checkTxsSingleOp(OPTIMISTIC, SERIALIZABLE);
     }
 
-    /**
-     * @param concurrency Concurrency.
-     * @param isolation Isolation.
-     * @throws Exception If failed.
-     */
-    private void checkTxsSingleOp(TransactionConcurrency concurrency, TransactionIsolation isolation) throws Exception {
-        Map<Integer, String> firstCheck = new HashMap<>();
-        Map<Integer, String> secondCheck = new HashMap<>();
-
-        for (int i = 0; i < TX_CNT; i++) {
-            int grid = ThreadLocalRandom.current().nextInt(nodeCount());
-
-            IgniteCache<Integer, String> first = grid(grid).cache(FIRST_CACHE);
-            IgniteCache<Integer, String> second = grid(grid).cache(SECOND_CACHE);
-
-            try (Transaction tx = grid(grid).transactions().txStart(concurrency, isolation)) {
-                try {
-                    int size = ThreadLocalRandom.current().nextInt(24) + 1;
-
-                    for (int k = 0; k < size; k++) {
-                        boolean rnd = ThreadLocalRandom.current().nextBoolean();
-
-                        IgniteCache<Integer, String> cache = rnd ? first : second;
-                        Map<Integer, String> check = rnd ? firstCheck : secondCheck;
-
-                        String val = rnd ? "first" + i : "second" + i;
-
-                        cache.put(k, val);
-                        check.put(k, val);
-                    }
-
-                    tx.commit();
-                }
-                catch (Throwable e) {
-                    e.printStackTrace();
-
-                    throw e;
-                }
-            }
-
-            if (i > 0 && i % 100 == 0)
-                info("Finished iteration: " + i);
-        }
-
-        for (int g = 0; g < nodeCount(); g++) {
-            IgniteEx grid = grid(g);
-
-            assertEquals(0, grid.context().cache().context().tm().idMapSize());
-
-            ClusterNode locNode = grid.localNode();
-
-            IgniteCache<Object, Object> firstCache = grid.cache(FIRST_CACHE);
-
-            for (Map.Entry<Integer, String> entry : firstCheck.entrySet()) {
-                boolean primary = grid.affinity(FIRST_CACHE).isPrimary(locNode, entry.getKey());
-
-                boolean backup = grid.affinity(FIRST_CACHE).isBackup(locNode, entry.getKey());
-
-                assertEquals("Invalid value found first cache [primary=" + primary + ", backup=" + backup +
-                        ", node=" + locNode.id() + ", key=" + entry.getKey() + ']',
-                    entry.getValue(), firstCache.get(entry.getKey()));
-            }
-
-            for (Map.Entry<Integer, String> entry : secondCheck.entrySet()) {
-                boolean primary = grid.affinity(SECOND_CACHE).isPrimary(locNode, entry.getKey());
-
-                boolean backup = grid.affinity(SECOND_CACHE).isBackup(locNode, entry.getKey());
-
-                assertEquals("Invalid value found second cache [primary=" + primary + ", backup=" + backup +
-                        ", node=" + locNode.id() + ", key=" + entry.getKey() + ']',
-                    entry.getValue(), grid.cache(SECOND_CACHE).get(entry.getKey()));
-            }
-        }
-    }
 }
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/NotMappedPartitionInTxTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/NotMappedPartitionInTxTest.java
index e09cf53..c3fa4f0 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/NotMappedPartitionInTxTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/NotMappedPartitionInTxTest.java
@@ -62,23 +62,33 @@
     /** Is client. */
     private boolean isClient;
 
+    /** Atomicity mode. */
+    private CacheAtomicityMode atomicityMode = CacheAtomicityMode.TRANSACTIONAL;
+
+    /** {@inheritDoc} */
+    @Override protected void afterTest() throws Exception {
+        super.afterTest();
+
+        atomicityMode = CacheAtomicityMode.TRANSACTIONAL;
+    }
+
     /** {@inheritDoc} */
     @Override protected IgniteConfiguration getConfiguration(String gridName) throws Exception {
         return super.getConfiguration(gridName)
             .setClientMode(isClient)
             .setCacheConfiguration(
                 new CacheConfiguration(CACHE)
-                    .setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL)
+                    .setAtomicityMode(atomicityMode)
                     .setCacheMode(CacheMode.REPLICATED)
                     .setAffinity(new TestAffinity()),
                 new CacheConfiguration(CACHE2)
-                    .setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL));
+                    .setAtomicityMode(atomicityMode));
     }
 
     /**
      *
      */
-    public void testOneServerOptimistic() throws Exception {
+    public void testOneServerTx() throws Exception {
         try {
             isClient = false;
             startGrid(0);
@@ -86,13 +96,11 @@
             isClient = true;
             final IgniteEx client = startGrid(1);
 
-            GridTestUtils.assertThrowsAnyCause(log, new Callable<Void>() {
-                @Override public Void call() throws Exception {
-                    testNotMapped(client, OPTIMISTIC, REPEATABLE_READ);
+            checkNotMapped(client, OPTIMISTIC, REPEATABLE_READ);
 
-                    return null;
-                }
-            }, ClusterTopologyServerNotFoundException.class, "Failed to map keys to nodes (partition is not mapped to any node)");
+            checkNotMapped(client, OPTIMISTIC, SERIALIZABLE);
+
+            checkNotMapped(client, PESSIMISTIC, READ_COMMITTED);
         }
         finally {
             stopAllGrids();
@@ -102,21 +110,19 @@
     /**
      *
      */
-    public void testOneServerOptimisticSerializable() throws Exception {
+    public void testOneServerMvcc() throws Exception {
+        fail("https://issues.apache.org/jira/browse/IGNITE-10377");
+
         try {
+            atomicityMode = CacheAtomicityMode.TRANSACTIONAL_SNAPSHOT;
+
             isClient = false;
             startGrid(0);
 
             isClient = true;
             final IgniteEx client = startGrid(1);
 
-            GridTestUtils.assertThrowsAnyCause(log, new Callable<Void>() {
-                @Override public Void call() throws Exception {
-                    testNotMapped(client, OPTIMISTIC, SERIALIZABLE);
-
-                    return null;
-                }
-            }, ClusterTopologyServerNotFoundException.class, "Failed to map keys to nodes (partition is not mapped to any node)");
+            checkNotMapped(client, PESSIMISTIC, REPEATABLE_READ);
         }
         finally {
             stopAllGrids();
@@ -126,45 +132,19 @@
     /**
      *
      */
-    public void testOneServerPessimistic() throws Exception {
+    public void testFourServersTx() throws Exception {
         try {
             isClient = false;
-            startGrid(0);
-
-            isClient = true;
-            final IgniteEx client = startGrid(1);
-
-            GridTestUtils.assertThrowsAnyCause(log, new Callable<Void>() {
-                @Override public Void call() throws Exception {
-                    testNotMapped(client, PESSIMISTIC, READ_COMMITTED);
-
-                    return null;
-                }
-            }, ClusterTopologyServerNotFoundException.class, "Failed to lock keys (all partition nodes left the grid)");
-        }
-        finally {
-            stopAllGrids();
-        }
-    }
-
-    /**
-     *
-     */
-    public void testFourServersOptimistic() throws Exception {
-        try {
-            isClient = false;
-            startGrids(4);
+            startGridsMultiThreaded(4);
 
             isClient = true;
             final IgniteEx client = startGrid(4);
 
-            GridTestUtils.assertThrowsAnyCause(log, new Callable<Void>() {
-                @Override public Void call() throws Exception {
-                    testNotMapped(client, OPTIMISTIC, REPEATABLE_READ);
+            checkNotMapped(client, OPTIMISTIC, REPEATABLE_READ);
 
-                    return null;
-                }
-            }, ClusterTopologyServerNotFoundException.class, "Failed to map keys to nodes (partition is not mapped to any node)");
+            checkNotMapped(client, OPTIMISTIC, SERIALIZABLE);
+
+            checkNotMapped(client, PESSIMISTIC, READ_COMMITTED);
         }
         finally {
             stopAllGrids();
@@ -174,45 +154,19 @@
     /**
      *
      */
-    public void testFourServersOptimisticSerializable() throws Exception {
+    public void testFourServersMvcc() throws Exception {
+        fail("https://issues.apache.org/jira/browse/IGNITE-10377");
+
         try {
+            atomicityMode = CacheAtomicityMode.TRANSACTIONAL_SNAPSHOT;
+
             isClient = false;
-            startGrids(4);
+            startGridsMultiThreaded(4);
 
             isClient = true;
             final IgniteEx client = startGrid(4);
 
-            GridTestUtils.assertThrowsAnyCause(log, new Callable<Void>() {
-                @Override public Void call() throws Exception {
-                    testNotMapped(client, OPTIMISTIC, SERIALIZABLE);
-
-                    return null;
-                }
-            }, ClusterTopologyServerNotFoundException.class, "Failed to map keys to nodes (partition is not mapped to any node)");
-        }
-        finally {
-            stopAllGrids();
-        }
-    }
-
-    /**
-     *
-     */
-    public void testFourServersPessimistic() throws Exception {
-        try {
-            isClient = false;
-            startGrids(4);
-
-            isClient = true;
-            final IgniteEx client = startGrid(4);
-
-            GridTestUtils.assertThrowsAnyCause(log, new Callable<Void>() {
-                @Override public Void call() throws Exception {
-                    testNotMapped(client, PESSIMISTIC, READ_COMMITTED);
-
-                    return null;
-                }
-            }, ClusterTopologyServerNotFoundException.class, "Failed to lock keys (all partition nodes left the grid)");
+            checkNotMapped(client, PESSIMISTIC, READ_COMMITTED);
         }
         finally {
             stopAllGrids();
@@ -222,24 +176,35 @@
     /**
      * @param client Ignite client.
      */
-    private void testNotMapped(IgniteEx client, TransactionConcurrency concurrency, TransactionIsolation isolation) {
-        IgniteCache cache2 = client.cache(CACHE2);
-        IgniteCache cache1 = client.cache(CACHE).withKeepBinary();
+    private void checkNotMapped(final IgniteEx client, final TransactionConcurrency concurrency,
+        final TransactionIsolation isolation) {
+        String msg = concurrency == PESSIMISTIC ? "Failed to lock keys (all partition nodes left the grid)" :
+           "Failed to map keys to nodes (partition is not mapped to any node";
 
-        try(Transaction tx = client.transactions().txStart(concurrency, isolation)) {
 
-            Map<String, Integer> param = new TreeMap<>();
-            param.put(TEST_KEY + 1, 1);
-            param.put(TEST_KEY + 1, 3);
-            param.put(TEST_KEY, 3);
+        GridTestUtils.assertThrowsAnyCause(log, new Callable<Void>() {
+            @Override public Void call() {
+                IgniteCache cache2 = client.cache(CACHE2);
+                IgniteCache cache1 = client.cache(CACHE).withKeepBinary();
 
-            cache1.put(TEST_KEY, 3);
+                try (Transaction tx = client.transactions().txStart(concurrency, isolation)) {
 
-            cache1.putAll(param);
-            cache2.putAll(param);
+                    Map<String, Integer> param = new TreeMap<>();
+                    param.put(TEST_KEY + 1, 1);
+                    param.put(TEST_KEY + 1, 3);
+                    param.put(TEST_KEY, 3);
 
-            tx.commit();
-        }
+                    cache1.put(TEST_KEY, 3);
+
+                    cache1.putAll(param);
+                    cache2.putAll(param);
+
+                    tx.commit();
+                }
+
+                return null;
+            }
+        }, ClusterTopologyServerNotFoundException.class, msg);
     }
 
     /** */
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridCacheAtomicInvalidPartitionHandlingSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridCacheAtomicInvalidPartitionHandlingSelfTest.java
index ba17da0..5c9f50c 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridCacheAtomicInvalidPartitionHandlingSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridCacheAtomicInvalidPartitionHandlingSelfTest.java
@@ -35,6 +35,8 @@
 import org.apache.ignite.cluster.ClusterNode;
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.IgniteInternalFuture;
 import org.apache.ignite.internal.IgniteKernal;
 import org.apache.ignite.internal.TestDelayingCommunicationSpi;
@@ -96,6 +98,11 @@
     }
 
     /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
+    /** {@inheritDoc} */
     protected CacheConfiguration cacheConfiguration() {
         CacheConfiguration ccfg = new CacheConfiguration(DEFAULT_CACHE_NAME);
 
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/near/GridCacheNearOnlyTopologySelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/near/GridCacheNearOnlyTopologySelfTest.java
index 2124bc8..5df4153 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/near/GridCacheNearOnlyTopologySelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/near/GridCacheNearOnlyTopologySelfTest.java
@@ -25,11 +25,14 @@
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.configuration.NearCacheConfiguration;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.cluster.ClusterTopologyCheckedException;
 import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
 import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder;
 import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
 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;
 
@@ -54,6 +57,13 @@
     private boolean cache = true;
 
     /** {@inheritDoc} */
+    @Override protected void beforeTestsStarted() throws Exception {
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.NEAR_CACHE);
+
+        super.beforeTestsStarted();
+    }
+
+    /** {@inheritDoc} */
     @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception {
         IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName);
 
@@ -81,6 +91,11 @@
         return cfg;
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /** @throws Exception If failed. */
     public void testStartupFirstOneNode() throws Exception {
         checkStartupNearNode(0, 2);
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/near/GridCacheNearTxPreloadSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/near/GridCacheNearTxPreloadSelfTest.java
index caf6cc7..96b932a 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/near/GridCacheNearTxPreloadSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/near/GridCacheNearTxPreloadSelfTest.java
@@ -21,6 +21,7 @@
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.NearCacheConfiguration;
 import org.apache.ignite.internal.processors.cache.distributed.IgniteTxPreloadAbstractTest;
+import org.apache.ignite.testframework.MvccFeatureChecker;
 
 import static org.apache.ignite.cache.CacheMode.PARTITIONED;
 
@@ -29,6 +30,13 @@
  */
 public class GridCacheNearTxPreloadSelfTest extends IgniteTxPreloadAbstractTest {
     /** {@inheritDoc} */
+    @Override public void setUp() throws Exception {
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.NEAR_CACHE);
+
+        super.setUp();
+    }
+
+    /** {@inheritDoc} */
     @Override protected CacheMode cacheMode() {
         return PARTITIONED;
     }
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/near/GridCachePutArrayValueSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/near/GridCachePutArrayValueSelfTest.java
index 14a0c0f..7ee83e8 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/near/GridCachePutArrayValueSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/near/GridCachePutArrayValueSelfTest.java
@@ -22,10 +22,12 @@
 import java.io.ObjectInput;
 import java.io.ObjectOutput;
 import org.apache.ignite.IgniteCache;
+import org.apache.ignite.IgniteCheckedException;
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.internal.processors.cache.GridCacheAbstractSelfTest;
 import org.apache.ignite.internal.processors.cache.GridCacheInternal;
 import org.apache.ignite.internal.util.typedef.internal.S;
+import org.apache.ignite.testframework.MvccFeatureChecker;
 
 import static org.apache.ignite.cache.CacheMode.PARTITIONED;
 
@@ -38,6 +40,13 @@
         return 4;
     }
 
+    @Override protected void initStoreStrategy() throws IgniteCheckedException {
+        if (!MvccFeatureChecker.isSupported(MvccFeatureChecker.Feature.CACHE_STORE))
+            return;
+
+        super.initStoreStrategy();
+    }
+
     /** {@inheritDoc} */
     @Override protected CacheConfiguration cacheConfiguration(String igniteInstanceName) throws Exception {
         CacheConfiguration cacheCfg = super.cacheConfiguration(igniteInstanceName);
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/near/IgniteCacheNearOnlyTxTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/near/IgniteCacheNearOnlyTxTest.java
index ca12a99..d86fa91 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/near/IgniteCacheNearOnlyTxTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/near/IgniteCacheNearOnlyTxTest.java
@@ -29,6 +29,7 @@
 import org.apache.ignite.internal.IgniteInternalFuture;
 import org.apache.ignite.internal.processors.cache.IgniteCacheAbstractTest;
 import org.apache.ignite.testframework.GridTestUtils;
+import org.apache.ignite.testframework.MvccFeatureChecker;
 import org.apache.ignite.transactions.Transaction;
 
 import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL;
@@ -41,6 +42,13 @@
  */
 public class IgniteCacheNearOnlyTxTest extends IgniteCacheAbstractTest {
     /** {@inheritDoc} */
+    @Override public void setUp() throws Exception {
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.NEAR_CACHE);
+
+        super.setUp();
+    }
+
+    /** {@inheritDoc} */
     @Override protected int gridCount() {
         return 2;
     }
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/near/IgniteCacheNearReadCommittedTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/near/IgniteCacheNearReadCommittedTest.java
index ad9bce0..76f0d17 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/near/IgniteCacheNearReadCommittedTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/near/IgniteCacheNearReadCommittedTest.java
@@ -22,6 +22,7 @@
 import org.apache.ignite.cache.CachePeekMode;
 import org.apache.ignite.configuration.NearCacheConfiguration;
 import org.apache.ignite.internal.processors.cache.GridCacheAbstractSelfTest;
+import org.apache.ignite.testframework.MvccFeatureChecker;
 import org.apache.ignite.transactions.Transaction;
 
 import static org.apache.ignite.cache.CacheMode.PARTITIONED;
@@ -34,6 +35,13 @@
 @SuppressWarnings("RedundantMethodOverride")
 public class IgniteCacheNearReadCommittedTest extends GridCacheAbstractSelfTest {
     /** {@inheritDoc} */
+    @Override public void setUp() throws Exception {
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.NEAR_CACHE);
+
+        super.setUp();
+    }
+
+    /** {@inheritDoc} */
     @Override protected int gridCount() {
         return 2;
     }
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/rebalancing/CacheManualRebalancingTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/rebalancing/CacheManualRebalancingTest.java
index 3a6ad48..eb090a8 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/rebalancing/CacheManualRebalancingTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/rebalancing/CacheManualRebalancingTest.java
@@ -24,7 +24,6 @@
 import org.apache.ignite.IgniteLogger;
 import org.apache.ignite.cache.CacheMode;
 import org.apache.ignite.cache.CachePeekMode;
-import org.apache.ignite.compute.ComputeTaskFuture;
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.internal.IgniteEx;
@@ -104,11 +103,9 @@
         int newNodeCacheSize;
 
         // Start manual rebalancing.
-        IgniteCompute compute = newNode.compute().withAsync();
+        IgniteCompute compute = newNode.compute();
 
-        compute.broadcast(new MyCallable());
-
-        final ComputeTaskFuture<Object> rebalanceTaskFuture = compute.future();
+        final IgniteFuture<?> rebalanceTaskFuture =  compute.broadcastAsync(new MyCallable());
 
         boolean rebalanceFinished = GridTestUtils.waitForCondition(new GridAbsPredicate() {
             @Override public boolean apply() {
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/regressions/logistic/binomial/package-info.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/rebalancing/GridCacheRebalancingPartitionCountersMvccTest.java
similarity index 66%
copy from modules/ml/src/main/java/org/apache/ignite/ml/regressions/logistic/binomial/package-info.java
copy to modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/rebalancing/GridCacheRebalancingPartitionCountersMvccTest.java
index d32b1ee..4166cfc 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/regressions/logistic/binomial/package-info.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/rebalancing/GridCacheRebalancingPartitionCountersMvccTest.java
@@ -14,9 +14,16 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package org.apache.ignite.internal.processors.cache.distributed.rebalancing;
+
+import org.apache.ignite.cache.CacheAtomicityMode;
 
 /**
- * <!-- Package description. -->
- * Contains binomial logistic regression.
+ *
  */
-package org.apache.ignite.ml.regressions.logistic.binomial;
\ No newline at end of file
+public class GridCacheRebalancingPartitionCountersMvccTest extends GridCacheRebalancingPartitionCountersTest {
+    /** {@inheritDoc} */
+    @Override protected CacheAtomicityMode atomicityMode() {
+        return CacheAtomicityMode.TRANSACTIONAL_SNAPSHOT;
+    }
+}
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/rebalancing/GridCacheRebalancingPartitionCountersTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/rebalancing/GridCacheRebalancingPartitionCountersTest.java
index 258e36e..6523eb9 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/rebalancing/GridCacheRebalancingPartitionCountersTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/rebalancing/GridCacheRebalancingPartitionCountersTest.java
@@ -24,6 +24,7 @@
 import java.util.HashMap;
 import java.util.List;
 import org.apache.ignite.IgniteCache;
+import org.apache.ignite.cache.CacheAtomicityMode;
 import org.apache.ignite.cache.affinity.rendezvous.RendezvousAffinityFunction;
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.DataRegionConfiguration;
@@ -61,6 +62,7 @@
                                 .setMaxSize(100L * 1024 * 1024))
                         .setWalMode(WALMode.LOG_ONLY))
                 .setCacheConfiguration(new CacheConfiguration(CACHE_NAME)
+                    .setAtomicityMode(atomicityMode())
                     .setBackups(2)
                     .setRebalanceBatchSize(4096) // Force to create several supply messages during rebalancing.
                     .setAffinity(
@@ -80,6 +82,13 @@
     }
 
     /**
+     * @return Cache atomicity mode.
+     */
+    protected CacheAtomicityMode atomicityMode() {
+        return CacheAtomicityMode.ATOMIC;
+    }
+
+    /**
      *
      */
     private boolean contains(int[] arr, int a) {
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 a95ad43..8008aa8 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
@@ -33,6 +33,8 @@
 import org.apache.ignite.cluster.ClusterNode;
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.IgniteEx;
 import org.apache.ignite.internal.IgniteKernal;
 import org.apache.ignite.internal.managers.communication.GridIoMessage;
@@ -251,6 +253,11 @@
         GridTestUtils.runGC(); // Clean heap before rebalancing.
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * @throws Exception If failed.
      */
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheGetEntryPessimisticReadCommittedSeltTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/rebalancing/GridCacheRebalancingWithAsyncClearingMvccTest.java
similarity index 61%
copy from modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheGetEntryPessimisticReadCommittedSeltTest.java
copy to modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/rebalancing/GridCacheRebalancingWithAsyncClearingMvccTest.java
index 975d271..a61d6d0 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheGetEntryPessimisticReadCommittedSeltTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/rebalancing/GridCacheRebalancingWithAsyncClearingMvccTest.java
@@ -14,23 +14,23 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package org.apache.ignite.internal.processors.cache.distributed.rebalancing;
 
-package org.apache.ignite.internal.processors.cache;
-
-import org.apache.ignite.transactions.TransactionConcurrency;
-import org.apache.ignite.transactions.TransactionIsolation;
+import org.apache.ignite.cache.CacheAtomicityMode;
 
 /**
- * Test getEntry and getEntries methods.
+ *
  */
-public class CacheGetEntryPessimisticReadCommittedSeltTest extends CacheGetEntryAbstractTest {
+public class GridCacheRebalancingWithAsyncClearingMvccTest extends GridCacheRebalancingWithAsyncClearingTest {
     /** {@inheritDoc} */
-    @Override protected TransactionConcurrency concurrency() {
-        return TransactionConcurrency.PESSIMISTIC;
+    @Override public void setUp() throws Exception {
+        fail("https://issues.apache.org/jira/browse/IGNITE-10421");
+
+        super.setUp();
     }
 
     /** {@inheritDoc} */
-    @Override protected TransactionIsolation isolation() {
-        return TransactionIsolation.READ_COMMITTED;
+    @Override protected CacheAtomicityMode atomicityMode() {
+        return CacheAtomicityMode.TRANSACTIONAL_SNAPSHOT;
     }
 }
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/rebalancing/GridCacheRebalancingWithAsyncClearingTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/rebalancing/GridCacheRebalancingWithAsyncClearingTest.java
index 328653d..2b69439 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/rebalancing/GridCacheRebalancingWithAsyncClearingTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/rebalancing/GridCacheRebalancingWithAsyncClearingTest.java
@@ -21,6 +21,7 @@
 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.CacheWriteSynchronizationMode;
 import org.apache.ignite.cache.PartitionLossPolicy;
 import org.apache.ignite.cache.affinity.rendezvous.RendezvousAffinityFunction;
@@ -65,6 +66,7 @@
         );
 
         cfg.setCacheConfiguration(new CacheConfiguration<>(CACHE_NAME)
+                .setAtomicityMode(atomicityMode())
                 .setBackups(2)
                 .setWriteSynchronizationMode(CacheWriteSynchronizationMode.FULL_SYNC)
                 .setIndexedTypes(Integer.class, Integer.class)
@@ -94,6 +96,13 @@
     }
 
     /**
+     * @return Atomicity mode.
+     */
+    protected CacheAtomicityMode atomicityMode() {
+        return CacheAtomicityMode.ATOMIC;
+    }
+
+    /**
      * Test that partition clearing doesn't block partitions map exchange.
      *
      * @throws Exception If failed.
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/rebalancing/IgniteRebalanceOnCachesStoppingOrDestroyingTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/rebalancing/IgniteRebalanceOnCachesStoppingOrDestroyingTest.java
new file mode 100644
index 0000000..97f8d45
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/rebalancing/IgniteRebalanceOnCachesStoppingOrDestroyingTest.java
@@ -0,0 +1,279 @@
+/*
+ * 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.cache.distributed.rebalancing;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.ThreadLocalRandom;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import org.apache.ignite.Ignite;
+import org.apache.ignite.IgniteCache;
+import org.apache.ignite.IgniteDataStreamer;
+import org.apache.ignite.IgniteException;
+import org.apache.ignite.cache.CacheMode;
+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.configuration.TransactionConfiguration;
+import org.apache.ignite.configuration.WALMode;
+import org.apache.ignite.failure.StopNodeFailureHandler;
+import org.apache.ignite.internal.IgniteEx;
+import org.apache.ignite.internal.IgniteInterruptedCheckedException;
+import org.apache.ignite.internal.managers.communication.GridIoMessage;
+import org.apache.ignite.internal.processors.cache.GridCacheGroupIdMessage;
+import org.apache.ignite.internal.processors.cache.distributed.dht.preloader.GridDhtPartitionSupplyMessage;
+import org.apache.ignite.internal.util.lang.IgniteThrowableConsumer;
+import org.apache.ignite.internal.util.typedef.F;
+import org.apache.ignite.internal.util.typedef.internal.CU;
+import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.lang.IgniteInClosure;
+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.spi.discovery.tcp.TcpDiscoverySpi;
+import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder;
+import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
+import org.apache.ignite.testframework.GridTestUtils;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+
+/**
+ *
+ */
+public class IgniteRebalanceOnCachesStoppingOrDestroyingTest extends GridCommonAbstractTest {
+    /** */
+    private static final String CACHE_1 = "cache_1";
+
+    /** */
+    private static final String CACHE_2 = "cache_2";
+
+    /** */
+    private static final String CACHE_3 = "cache_3";
+
+    /** */
+    private static final String CACHE_4 = "cache_4";
+
+    /** */
+    private static final String GROUP_1 = "group_1";
+
+    /** */
+    private static final String GROUP_2 = "group_2";
+
+    /** */
+    private static final int REBALANCE_BATCH_SIZE = 50 * 1024;
+
+    /** */
+    private static TcpDiscoveryIpFinder ipFinder = new TcpDiscoveryVmIpFinder(true);
+
+    /** {@inheritDoc} */
+    @Override protected void beforeTest() throws Exception {
+        super.beforeTest();
+
+        cleanPersistenceDir();
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void afterTest() throws Exception {
+        super.afterTest();
+
+        stopAllGrids();
+
+        cleanPersistenceDir();
+    }
+
+    /** {@inheritDoc} */
+    @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception {
+        IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName);
+
+        TcpDiscoverySpi spi = new TcpDiscoverySpi();
+
+        spi.setIpFinder(ipFinder);
+
+        cfg.setDiscoverySpi(spi);
+
+        cfg.setCommunicationSpi(new RebalanceBlockingSPI());
+
+        cfg.setFailureHandler(new StopNodeFailureHandler());
+
+        cfg.setRebalanceThreadPoolSize(4);
+
+        cfg.setTransactionConfiguration(new TransactionConfiguration()
+            .setDefaultTxTimeout(1000));
+
+        cfg.setDataStorageConfiguration(
+                new DataStorageConfiguration()
+                        .setWalMode(WALMode.LOG_ONLY)
+                        .setDefaultDataRegionConfiguration(
+                                new DataRegionConfiguration()
+                                        .setPersistenceEnabled(true)
+                                        .setMaxSize(100L * 1024 * 1024)));
+
+        return cfg;
+    }
+
+    /**
+     *
+     */
+    public void testStopCachesOnDeactivation() throws Exception {
+        performTest(ig -> {
+            ig.cluster().active(false);
+
+            // Add to escape possible long waiting in awaitPartitionMapExchange due to {@link CacheAffinityChangeMessage}.
+            ig.cluster().active(true);
+
+            return null;
+        });
+    }
+
+    /**
+     *
+     */
+    public void testDestroySpecificCachesInDifferentCacheGroups() throws Exception {
+        performTest(ig -> {
+            ig.destroyCaches(Arrays.asList(CACHE_1, CACHE_3));
+
+            return null;
+        });
+    }
+
+    /**
+     *
+     */
+    public void testDestroySpecificCacheAndCacheGroup() throws Exception {
+        performTest(ig -> {
+            ig.destroyCaches(Arrays.asList(CACHE_1, CACHE_3, CACHE_4));
+
+            return null;
+        });
+    }
+
+    /**
+     * @param testAction Action that trigger stop or destroy of caches.
+     */
+    private void performTest(IgniteThrowableConsumer<Ignite, Void> testAction) throws Exception {
+        IgniteEx ig0 = (IgniteEx)startGrids(2);
+
+        ig0.cluster().active(true);
+
+        stopGrid(1);
+
+        loadData(ig0);
+
+        startGrid(1);
+
+        runLoad(ig0);
+
+        testAction.accept(ig0);
+
+        U.sleep(1000);
+
+        awaitPartitionMapExchange(true, true, null, true);
+
+        assertNull(grid(1).context().failure().failureContext());
+    }
+
+    /**
+     * @param ig Ig.
+     */
+    private void loadData(Ignite ig) {
+        List<CacheConfiguration> configs = Stream.of(
+                F.t(CACHE_1, GROUP_1),
+                F.t(CACHE_2, GROUP_1),
+                F.t(CACHE_3, GROUP_2),
+                F.t(CACHE_4, GROUP_2)
+        ).map(names -> new CacheConfiguration<>(names.get1())
+                .setGroupName(names.get2())
+                .setRebalanceBatchSize(REBALANCE_BATCH_SIZE)
+                .setCacheMode(CacheMode.REPLICATED)
+        ).collect(Collectors.toList());
+
+        ig.getOrCreateCaches(configs);
+
+        configs.forEach(cfg -> {
+            try (IgniteDataStreamer<Object, Object> streamer = ig.dataStreamer(cfg.getName())) {
+                for (int i = 0; i < 3_000; i++)
+                    streamer.addData(i, new byte[1024]);
+
+                streamer.flush();
+            }
+        });
+    }
+
+    /**
+     * @param ig Ignite instance.
+     */
+    private void runLoad(Ignite ig) throws Exception{
+        GridTestUtils.runMultiThreaded(new Runnable() {
+            @Override public void run() {
+                String cacheName = F.rand(CACHE_1, CACHE_2, CACHE_3, CACHE_4);
+
+                IgniteCache cache = ig.cache(cacheName);
+
+                for (int i = 0; i < 3_000; i++) {
+                    int idx = ThreadLocalRandom.current().nextInt(3_000);
+
+                    cache.put(idx, new byte[1024]);
+                }
+            }
+        }, 4, "load-thread");
+    }
+
+    /**
+     *
+     */
+    private static class RebalanceBlockingSPI extends TcpCommunicationSpi {
+        /** */
+        public static final TcpDiscoveryIpFinder IP_FINDER = new TcpDiscoveryVmIpFinder(true);
+
+        /** {@inheritDoc} */
+        @Override public void sendMessage(ClusterNode node, Message msg) throws IgniteSpiException {
+            slowDownMessage(msg);
+
+            super.sendMessage(node, msg);
+
+        }
+
+        /** {@inheritDoc} */
+        @Override public void sendMessage(ClusterNode node, Message msg,
+                                          IgniteInClosure<IgniteException> ackC) throws IgniteSpiException {
+            slowDownMessage(msg);
+
+            super.sendMessage(node, msg, ackC);
+        }
+
+        /**
+         * @param msg Message.
+         */
+        private void slowDownMessage(Message msg) {
+            if (msg instanceof GridIoMessage && ((GridIoMessage)msg).message() instanceof GridDhtPartitionSupplyMessage) {
+                int grpId = ((GridCacheGroupIdMessage)((GridIoMessage)msg).message()).groupId();
+
+                if (grpId == CU.cacheId(GROUP_1) || grpId == CU.cacheId(GROUP_2)) {
+                    try {
+                        U.sleep(50);
+                    }
+                    catch (IgniteInterruptedCheckedException e) {
+                        e.printStackTrace();
+                    }
+                }
+            }
+        }
+    }
+}
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
new file mode 100644
index 0000000..2df5d45
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/replicated/GridCacheReplicatedMvccTxMultiThreadedSelfTest.java
@@ -0,0 +1,81 @@
+/*
+ * 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.cache.distributed.replicated;
+
+import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.internal.processors.cache.IgniteMvccTxMultiThreadedAbstractTest;
+
+import static org.apache.ignite.cache.CacheMode.REPLICATED;
+import static org.apache.ignite.cache.CacheWriteSynchronizationMode.FULL_SYNC;
+
+/**
+ * Tests for replicated transactions.
+ */
+public class GridCacheReplicatedMvccTxMultiThreadedSelfTest extends IgniteMvccTxMultiThreadedAbstractTest {
+    /** {@inheritDoc} */
+    @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception {
+        IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName);
+
+        CacheConfiguration ccfg = defaultCacheConfiguration();
+
+        ccfg.setCacheMode(REPLICATED);
+        ccfg.setEvictionPolicy(null);
+
+        ccfg.setWriteSynchronizationMode(FULL_SYNC);
+
+        cfg.setCacheConfiguration(ccfg);
+
+        return cfg;
+    }
+
+    /** {@inheritDoc} */
+    @Override protected int gridCount() {
+        return 3;
+    }
+
+    /** {@inheritDoc} */
+    @Override protected int keyCount() {
+        return 3;
+    }
+
+    /** {@inheritDoc} */
+    @Override protected int maxKeyValue() {
+        return 3;
+    }
+
+    /** {@inheritDoc} */
+    @Override protected int threadCount() {
+        return 5;
+    }
+
+    /** {@inheritDoc} */
+    @Override protected int iterations() {
+        return 1000;
+    }
+
+    /** {@inheritDoc} */
+    @Override protected boolean isTestDebug() {
+        return false;
+    }
+
+    /** {@inheritDoc} */
+    @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/GridCacheReplicatedMvccTxSingleThreadedSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/replicated/GridCacheReplicatedMvccTxSingleThreadedSelfTest.java
new file mode 100644
index 0000000..7e80634
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/replicated/GridCacheReplicatedMvccTxSingleThreadedSelfTest.java
@@ -0,0 +1,77 @@
+/*
+ * 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.cache.distributed.replicated;
+
+import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.internal.processors.cache.IgniteMvccTxSingleThreadedAbstractTest;
+
+import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL_SNAPSHOT;
+import static org.apache.ignite.cache.CacheMode.REPLICATED;
+import static org.apache.ignite.cache.CacheWriteSynchronizationMode.FULL_SYNC;
+
+/**
+ * Tests for replicated transactions.
+ */
+public class GridCacheReplicatedMvccTxSingleThreadedSelfTest extends IgniteMvccTxSingleThreadedAbstractTest {
+     /** {@inheritDoc} */
+    @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception {
+        IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName);
+
+        CacheConfiguration ccfg = defaultCacheConfiguration();
+
+        ccfg.setAtomicityMode(TRANSACTIONAL_SNAPSHOT);
+        ccfg.setCacheMode(REPLICATED);
+        ccfg.setEvictionPolicy(null);
+        ccfg.setWriteSynchronizationMode(FULL_SYNC);
+
+        cfg.setCacheConfiguration(ccfg);
+
+        return cfg;
+    }
+
+    /** {@inheritDoc} */
+    @Override protected int gridCount() {
+        return 3;
+    }
+
+    /** {@inheritDoc} */
+    @Override protected int keyCount() {
+        return 3;
+    }
+
+    /** {@inheritDoc} */
+    @Override protected int maxKeyValue() {
+        return 3;
+    }
+
+    /** {@inheritDoc} */
+    @Override protected int iterations() {
+        return 20;
+    }
+
+    /** {@inheritDoc} */
+    @Override protected boolean isTestDebug() {
+        return false;
+    }
+
+    /** {@inheritDoc} */
+    @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/GridCacheReplicatedMvccTxTimeoutSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/replicated/GridCacheReplicatedMvccTxTimeoutSelfTest.java
new file mode 100644
index 0000000..2f95323
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/replicated/GridCacheReplicatedMvccTxTimeoutSelfTest.java
@@ -0,0 +1,44 @@
+/*
+ * 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.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.distributed.IgniteMvccTxTimeoutAbstractTest;
+
+import static org.apache.ignite.cache.CacheMode.REPLICATED;
+
+/**
+ * Simple cache test.
+ */
+public class GridCacheReplicatedMvccTxTimeoutSelfTest extends IgniteMvccTxTimeoutAbstractTest {
+    /** {@inheritDoc} */
+    @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception {
+        IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName);
+
+        CacheConfiguration ccfg = defaultCacheConfiguration();
+
+        ccfg.setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL_SNAPSHOT);
+        ccfg.setCacheMode(REPLICATED);
+
+        cfg.setCacheConfiguration(ccfg);
+
+        return cfg;
+    }
+}
\ No newline at end of file
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/replicated/GridCacheReplicatedTxMultiThreadedSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/replicated/GridCacheReplicatedTxMultiThreadedSelfTest.java
index 0044581..a4f3117 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/replicated/GridCacheReplicatedTxMultiThreadedSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/replicated/GridCacheReplicatedTxMultiThreadedSelfTest.java
@@ -20,12 +20,7 @@
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.configuration.TransactionConfiguration;
-import org.apache.ignite.internal.processors.cache.GridCacheProcessor;
 import org.apache.ignite.internal.processors.cache.IgniteTxMultiThreadedAbstractTest;
-import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
-import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder;
-import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
-import org.apache.log4j.Level;
 
 import static org.apache.ignite.cache.CacheMode.REPLICATED;
 import static org.apache.ignite.cache.CacheWriteSynchronizationMode.FULL_SYNC;
@@ -34,23 +29,12 @@
  * Tests for replicated transactions.
  */
 public class GridCacheReplicatedTxMultiThreadedSelfTest extends IgniteTxMultiThreadedAbstractTest {
-    /** Cache debug flag. */
-    private static final boolean CACHE_DEBUG = false;
-
-    /** Log to file flag. */
-    private static final boolean LOG_TO_FILE = true;
-
-    /** */
-    private TcpDiscoveryIpFinder ipFinder = new TcpDiscoveryVmIpFinder(true);
-
     /** {@inheritDoc} */
     @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception {
         IgniteConfiguration c = super.getConfiguration(igniteInstanceName);
 
         TransactionConfiguration tCfg = new TransactionConfiguration();
 
-        tCfg.setTxSerializableEnabled(true);
-
         c.setTransactionConfiguration(tCfg);
 
         CacheConfiguration cc = defaultCacheConfiguration();
@@ -63,15 +47,6 @@
 
         c.setCacheConfiguration(cc);
 
-        TcpDiscoverySpi spi = new TcpDiscoverySpi();
-
-        spi.setIpFinder(ipFinder);
-
-        c.setDiscoverySpi(spi);
-
-        if (CACHE_DEBUG)
-            resetLog4j(Level.DEBUG, LOG_TO_FILE, GridCacheProcessor.class.getPackage().getName());
-
         return c;
     }
 
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/replicated/GridCacheReplicatedTxSingleThreadedSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/replicated/GridCacheReplicatedTxSingleThreadedSelfTest.java
index c9f3aee..80b2f3b 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/replicated/GridCacheReplicatedTxSingleThreadedSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/replicated/GridCacheReplicatedTxSingleThreadedSelfTest.java
@@ -19,12 +19,7 @@
 
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
-import org.apache.ignite.internal.processors.cache.GridCacheProcessor;
 import org.apache.ignite.internal.processors.cache.IgniteTxSingleThreadedAbstractTest;
-import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
-import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder;
-import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
-import org.apache.log4j.Level;
 
 import static org.apache.ignite.cache.CacheMode.REPLICATED;
 import static org.apache.ignite.cache.CacheWriteSynchronizationMode.FULL_SYNC;
@@ -33,41 +28,19 @@
  * Tests for replicated transactions.
  */
 public class GridCacheReplicatedTxSingleThreadedSelfTest extends IgniteTxSingleThreadedAbstractTest {
-    /** Cache debug flag. */
-    private static final boolean CACHE_DEBUG = false;
-
-    /** Log to file flag. */
-    private static final boolean LOG_TO_FILE = true;
-
-    /** */
-    private TcpDiscoveryIpFinder ipFinder = new TcpDiscoveryVmIpFinder(true);
-
-    /** {@inheritDoc} */
+     /** {@inheritDoc} */
     @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception {
-        IgniteConfiguration c = super.getConfiguration(igniteInstanceName);
+        IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName);
 
-        c.getTransactionConfiguration().setTxSerializableEnabled(true);
+        CacheConfiguration ccfg = defaultCacheConfiguration();
 
-        CacheConfiguration cc = defaultCacheConfiguration();
+        ccfg.setCacheMode(REPLICATED);
+        ccfg.setEvictionPolicy(null);
+        ccfg.setWriteSynchronizationMode(FULL_SYNC);
 
-        cc.setCacheMode(REPLICATED);
+        cfg.setCacheConfiguration(ccfg);
 
-        cc.setEvictionPolicy(null);
-
-        cc.setWriteSynchronizationMode(FULL_SYNC);
-
-        c.setCacheConfiguration(cc);
-
-        TcpDiscoverySpi spi = new TcpDiscoverySpi();
-
-        spi.setIpFinder(ipFinder);
-
-        c.setDiscoverySpi(spi);
-
-        if (CACHE_DEBUG)
-            resetLog4j(Level.DEBUG, LOG_TO_FILE, GridCacheProcessor.class.getPackage().getName());
-
-        return c;
+        return cfg;
     }
 
     /** {@inheritDoc} */
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/replicated/preloader/GridCacheReplicatedPreloadSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/replicated/preloader/GridCacheReplicatedPreloadSelfTest.java
index 947fb1e..8101172 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/replicated/preloader/GridCacheReplicatedPreloadSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/replicated/preloader/GridCacheReplicatedPreloadSelfTest.java
@@ -17,12 +17,9 @@
 
 package org.apache.ignite.internal.processors.cache.distributed.replicated.preloader;
 
-import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.Iterator;
-import java.util.List;
 import java.util.Map;
 import java.util.Random;
 import java.util.UUID;
@@ -39,10 +36,7 @@
 import org.apache.ignite.cache.CacheEntryEventSerializableFilter;
 import org.apache.ignite.cache.CachePeekMode;
 import org.apache.ignite.cache.CacheRebalanceMode;
-import org.apache.ignite.cache.affinity.AffinityFunction;
-import org.apache.ignite.cache.affinity.AffinityFunctionContext;
 import org.apache.ignite.cache.affinity.AffinityKeyMapper;
-import org.apache.ignite.cluster.ClusterNode;
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.events.Event;
@@ -51,15 +45,17 @@
 import org.apache.ignite.internal.binary.BinaryMarshaller;
 import org.apache.ignite.internal.processors.cache.GridCacheAdapter;
 import org.apache.ignite.internal.processors.cache.GridCacheEntryEx;
+import org.apache.ignite.internal.util.lang.GridAbsPredicate;
 import org.apache.ignite.internal.util.typedef.F;
 import org.apache.ignite.internal.util.typedef.P2;
-import org.apache.ignite.internal.util.typedef.internal.U;
 import org.apache.ignite.lang.IgnitePredicate;
 import org.apache.ignite.plugin.CachePluginConfiguration;
 import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
 import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder;
 import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
 import org.apache.ignite.spi.eventstorage.memory.MemoryEventStorageSpi;
+import org.apache.ignite.testframework.GridTestUtils;
+import org.apache.ignite.testframework.MvccFeatureChecker;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
 
 import static org.apache.ignite.cache.CacheMode.REPLICATED;
@@ -85,9 +81,6 @@
     private int batchSize = 4096;
 
     /** */
-    private int poolSize = 2;
-
-    /** */
     private volatile boolean extClassloadingAtCfg = false;
 
     /** */
@@ -119,6 +112,8 @@
     @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception {
         IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName);
 
+        cfg.setRebalanceThreadPoolSize(2);
+
         TcpDiscoverySpi disco = new TcpDiscoverySpi();
 
         disco.setIpFinder(ipFinder);
@@ -173,7 +168,6 @@
         cacheCfg.setWriteSynchronizationMode(FULL_SYNC);
         cacheCfg.setRebalanceMode(preloadMode);
         cacheCfg.setRebalanceBatchSize(batchSize);
-        cacheCfg.setRebalanceThreadPoolSize(poolSize);
 
         if (extClassloadingAtCfg)
             loadExternalClassesToCfg(cacheCfg);
@@ -571,14 +565,17 @@
      * @throws Exception If test failed.
      */
     public void testExternalClassesAtEventP2pDisabled() throws Exception {
-        testExternalClassesAtEvent0(true);
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.CACHE_EVENTS);
 
+        testExternalClassesAtEvent0(true);
     }
 
     /**
      * @throws Exception If test failed.
      */
     public void testExternalClassesAtEvent() throws Exception {
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.CACHE_EVENTS);
+
         testExternalClassesAtEvent0(false);
     }
 
@@ -656,19 +653,24 @@
         try {
             IgniteCache<Integer, String> cache1 = startGrid(1).cache(DEFAULT_CACHE_NAME);
 
-            int keyCnt = 2000;
+            final int keyCnt = 2000;
 
             for (int i = 0; i < keyCnt; i++)
                 cache1.put(i, "val" + i);
 
-            IgniteCache<Integer, String> cache2 = startGrid(2).cache(DEFAULT_CACHE_NAME);
+            final IgniteCache<Integer, String> cache2 = startGrid(2).cache(DEFAULT_CACHE_NAME);
 
             int size = cache2.localSize(CachePeekMode.ALL);
 
             info("Size of cache2: " + size);
 
-            assert waitCacheSize(cache2, keyCnt, getTestTimeout()) :
-                "Actual cache size: " + cache2.localSize(CachePeekMode.ALL);
+            boolean awaitSize = GridTestUtils.waitForCondition(new GridAbsPredicate() {
+                @Override public boolean apply() {
+                    return cache2.localSize(CachePeekMode.ALL) >= keyCnt;
+                }
+            }, getTestTimeout());
+
+            assertTrue("Actual cache size: " + cache2.localSize(CachePeekMode.ALL), awaitSize);
         }
         finally {
             stopAllGrids();
@@ -676,32 +678,6 @@
     }
 
     /**
-     * @param cache Cache.
-     * @param expSize Lower bound of expected size.
-     * @param timeout Timeout.
-     * @return {@code true} if success.
-     * @throws InterruptedException If thread was interrupted.
-     */
-    @SuppressWarnings({"BusyWait"})
-    private boolean waitCacheSize(IgniteCache<Integer, String> cache, int expSize, long timeout)
-        throws InterruptedException {
-        assert cache != null;
-        assert expSize > 0;
-        assert timeout >= 0;
-
-        long end = System.currentTimeMillis() + timeout;
-
-        while (cache.localSize(CachePeekMode.ALL) < expSize) {
-            Thread.sleep(50);
-
-            if (end - System.currentTimeMillis() <= 0)
-                break;
-        }
-
-        return cache.localSize(CachePeekMode.ALL) >= expSize;
-    }
-
-    /**
      * @throws Exception If test failed.
      */
     public void testBatchSize1() throws Exception {
@@ -788,7 +764,7 @@
 
             info("Beginning data population...");
 
-            int cnt = 2500;
+            final int cnt = 2500;
 
             Map<Integer, String> map = null;
 
@@ -816,7 +792,7 @@
                 info("Cache size is OK for grid index: " + gridIdx);
             }
 
-            IgniteCache<Integer, String> lastCache = startGrid(gridCnt).cache(DEFAULT_CACHE_NAME);
+            final IgniteCache<Integer, String> lastCache = startGrid(gridCnt).cache(DEFAULT_CACHE_NAME);
 
             // Let preloading start.
             Thread.sleep(1000);
@@ -828,8 +804,15 @@
 
             stopGrid(idx);
 
-            assert waitCacheSize(lastCache, cnt, 20 * 1000) :
-                "Actual cache size: " + lastCache.localSize(CachePeekMode.ALL);
+            awaitPartitionMapExchange(true, true, null);
+
+            boolean awaitSize = GridTestUtils.waitForCondition(new GridAbsPredicate() {
+                @Override public boolean apply() {
+                    return lastCache.localSize(CachePeekMode.ALL) >= cnt;
+                }
+            }, 20_000);
+
+            assertTrue("Actual cache size: " + lastCache.localSize(CachePeekMode.ALL), awaitSize);
         }
         finally {
             stopAllGrids();
@@ -867,64 +850,6 @@
     }
 
     /**
-     * Test affinity.
-     */
-    private static class TestAffinityFunction implements AffinityFunction {
-        /** {@inheritDoc} */
-        @Override public int partitions() {
-            return 2;
-        }
-
-        /** {@inheritDoc} */
-        @Override public int partition(Object key) {
-            if (key instanceof Number)
-                return ((Number)key).intValue() % 2;
-
-            return key == null ? 0 : U.safeAbs(key.hashCode() % 2);
-        }
-
-        /** {@inheritDoc} */
-        @Override public List<List<ClusterNode>> assignPartitions(AffinityFunctionContext affCtx) {
-            List<List<ClusterNode>> res = new ArrayList<>(partitions());
-
-            for (int part = 0; part < partitions(); part++)
-                res.add(nodes(part, affCtx.currentTopologySnapshot()));
-
-            return res;
-        }
-
-        /** {@inheritDoc} */
-        @SuppressWarnings({"RedundantTypeArguments"})
-        public List<ClusterNode> nodes(int part, Collection<ClusterNode> nodes) {
-            Collection<ClusterNode> col = new HashSet<>(nodes);
-
-            if (col.size() <= 1)
-                return new ArrayList<>(col);
-
-            for (Iterator<ClusterNode> iter = col.iterator(); iter.hasNext(); ) {
-                ClusterNode node = iter.next();
-
-                boolean even = node.<Boolean>attribute("EVEN");
-
-                if ((even && part != 0) || (!even && part != 1))
-                    iter.remove();
-            }
-
-            return new ArrayList<>(col);
-        }
-
-        /** {@inheritDoc} */
-        @Override public void reset() {
-            // No-op.
-        }
-
-        /** {@inheritDoc} */
-        @Override public void removeNode(UUID nodeId) {
-            // No-op.
-        }
-    }
-
-    /**
      *
      */
     private static class MessageListener implements P2<UUID, Object> {
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/eviction/paged/PageEvictionMultinodeAbstractTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/eviction/paged/PageEvictionMultinodeAbstractTest.java
index 777c2d7..e30f1cf 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/eviction/paged/PageEvictionMultinodeAbstractTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/eviction/paged/PageEvictionMultinodeAbstractTest.java
@@ -25,6 +25,7 @@
 import org.apache.ignite.cache.CacheWriteSynchronizationMode;
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.testframework.MvccFeatureChecker;
 
 /**
  *
@@ -46,6 +47,9 @@
 
     /** {@inheritDoc} */
     @Override protected void beforeTestsStarted() throws Exception {
+        if (MvccFeatureChecker.forcedMvcc())
+            fail("https://issues.apache.org/jira/browse/IGNITE-10448");
+
         startGridsMultiThreaded(4, false);
 
         clientGrid = startGrid("client");
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/integration/IgniteCacheLoadAllAbstractTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/integration/IgniteCacheLoadAllAbstractTest.java
index 6b4f976..3d9b7bd 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/integration/IgniteCacheLoadAllAbstractTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/integration/IgniteCacheLoadAllAbstractTest.java
@@ -22,6 +22,7 @@
 import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
 import javax.cache.Cache;
 import javax.cache.configuration.Factory;
 import javax.cache.integration.CacheLoader;
@@ -34,7 +35,7 @@
 import org.apache.ignite.cluster.ClusterNode;
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.internal.processors.cache.IgniteCacheAbstractTest;
-import java.util.concurrent.ConcurrentHashMap;
+import org.apache.ignite.testframework.MvccFeatureChecker;
 
 /**
  * Test for {@link Cache#loadAll(Set, boolean, CompletionListener)}.
@@ -47,6 +48,13 @@
     private static ConcurrentHashMap<Object, Object> storeMap;
 
     /** {@inheritDoc} */
+    @Override public void setUp() throws Exception {
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.CACHE_STORE);
+
+        super.setUp();
+    }
+
+    /** {@inheritDoc} */
     @SuppressWarnings("unchecked")
     @Override protected CacheConfiguration cacheConfiguration(String igniteInstanceName) throws Exception {
         CacheConfiguration ccfg = super.cacheConfiguration(igniteInstanceName);
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/integration/IgniteCacheTxLoaderWriterTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/integration/IgniteCacheTxLoaderWriterTest.java
index fc4ec78..75a4cd9 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/integration/IgniteCacheTxLoaderWriterTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/integration/IgniteCacheTxLoaderWriterTest.java
@@ -20,6 +20,7 @@
 import org.apache.ignite.cache.CacheAtomicityMode;
 import org.apache.ignite.cache.CacheMode;
 import org.apache.ignite.configuration.NearCacheConfiguration;
+import org.apache.ignite.testframework.MvccFeatureChecker;
 
 import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL;
 import static org.apache.ignite.cache.CacheMode.PARTITIONED;
@@ -29,6 +30,13 @@
  */
 public class IgniteCacheTxLoaderWriterTest extends IgniteCacheLoaderWriterAbstractTest {
     /** {@inheritDoc} */
+    @Override public void setUp() throws Exception {
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.CACHE_STORE);
+
+        super.setUp();
+    }
+
+    /** {@inheritDoc} */
     @Override protected int gridCount() {
         return 3;
     }
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/integration/IgniteCacheTxLocalLoadAllTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/integration/IgniteCacheTxLocalLoadAllTest.java
index 97374bf..645a9ff 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/integration/IgniteCacheTxLocalLoadAllTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/integration/IgniteCacheTxLocalLoadAllTest.java
@@ -20,6 +20,7 @@
 import org.apache.ignite.cache.CacheAtomicityMode;
 import org.apache.ignite.cache.CacheMode;
 import org.apache.ignite.configuration.NearCacheConfiguration;
+import org.apache.ignite.testframework.MvccFeatureChecker;
 
 import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL;
 import static org.apache.ignite.cache.CacheMode.LOCAL;
@@ -29,6 +30,12 @@
  */
 public class IgniteCacheTxLocalLoadAllTest extends IgniteCacheLoadAllAbstractTest {
     /** {@inheritDoc} */
+    @Override public void setUp() throws Exception {
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.LOCAL_CACHE);
+
+        super.setUp();
+    }
+    /** {@inheritDoc} */
     @Override protected int gridCount() {
         return 1;
     }
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/integration/IgniteCacheTxLocalNoLoadPreviousValueTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/integration/IgniteCacheTxLocalNoLoadPreviousValueTest.java
index 686b4ca..2e52a63 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/integration/IgniteCacheTxLocalNoLoadPreviousValueTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/integration/IgniteCacheTxLocalNoLoadPreviousValueTest.java
@@ -20,6 +20,7 @@
 import org.apache.ignite.cache.CacheAtomicityMode;
 import org.apache.ignite.cache.CacheMode;
 import org.apache.ignite.configuration.NearCacheConfiguration;
+import org.apache.ignite.testframework.MvccFeatureChecker;
 
 import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL;
 import static org.apache.ignite.cache.CacheMode.LOCAL;
@@ -29,6 +30,13 @@
  */
 public class IgniteCacheTxLocalNoLoadPreviousValueTest extends IgniteCacheNoLoadPreviousValueAbstractTest {
     /** {@inheritDoc} */
+    @Override public void setUp() throws Exception {
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.LOCAL_CACHE);
+
+        super.setUp();
+    }
+
+    /** {@inheritDoc} */
     @Override protected int gridCount() {
         return 1;
     }
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/integration/IgniteCacheTxLocalNoReadThroughTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/integration/IgniteCacheTxLocalNoReadThroughTest.java
index 5235c9d..e25a965 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/integration/IgniteCacheTxLocalNoReadThroughTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/integration/IgniteCacheTxLocalNoReadThroughTest.java
@@ -20,6 +20,7 @@
 import org.apache.ignite.cache.CacheAtomicityMode;
 import org.apache.ignite.cache.CacheMode;
 import org.apache.ignite.configuration.NearCacheConfiguration;
+import org.apache.ignite.testframework.MvccFeatureChecker;
 
 import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL;
 import static org.apache.ignite.cache.CacheMode.LOCAL;
@@ -29,6 +30,13 @@
  */
 public class IgniteCacheTxLocalNoReadThroughTest extends IgniteCacheNoReadThroughAbstractTest {
     /** {@inheritDoc} */
+    @Override public void setUp() throws Exception {
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.LOCAL_CACHE);
+
+        super.setUp();
+    }
+
+    /** {@inheritDoc} */
     @Override protected int gridCount() {
         return 1;
     }
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/integration/IgniteCacheTxLocalNoWriteThroughTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/integration/IgniteCacheTxLocalNoWriteThroughTest.java
index 7985c57..ddc9352 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/integration/IgniteCacheTxLocalNoWriteThroughTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/integration/IgniteCacheTxLocalNoWriteThroughTest.java
@@ -20,6 +20,7 @@
 import org.apache.ignite.cache.CacheAtomicityMode;
 import org.apache.ignite.cache.CacheMode;
 import org.apache.ignite.configuration.NearCacheConfiguration;
+import org.apache.ignite.testframework.MvccFeatureChecker;
 
 import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL;
 import static org.apache.ignite.cache.CacheMode.LOCAL;
@@ -29,6 +30,13 @@
  */
 public class IgniteCacheTxLocalNoWriteThroughTest extends IgniteCacheNoWriteThroughAbstractTest {
     /** {@inheritDoc} */
+    @Override public void setUp() throws Exception {
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.LOCAL_CACHE);
+
+        super.setUp();
+    }
+
+    /** {@inheritDoc} */
     @Override protected int gridCount() {
         return 1;
     }
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/integration/IgniteCacheTxNearEnabledNoLoadPreviousValueTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/integration/IgniteCacheTxNearEnabledNoLoadPreviousValueTest.java
index ce42e39..c343402 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/integration/IgniteCacheTxNearEnabledNoLoadPreviousValueTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/integration/IgniteCacheTxNearEnabledNoLoadPreviousValueTest.java
@@ -18,12 +18,20 @@
 package org.apache.ignite.internal.processors.cache.integration;
 
 import org.apache.ignite.configuration.NearCacheConfiguration;
+import org.apache.ignite.testframework.MvccFeatureChecker;
 
 /**
  *
  */
 public class IgniteCacheTxNearEnabledNoLoadPreviousValueTest extends IgniteCacheTxNoLoadPreviousValueTest {
     /** {@inheritDoc} */
+    @Override public void setUp() throws Exception {
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.NEAR_CACHE);
+
+        super.setUp();
+    }
+
+    /** {@inheritDoc} */
     @Override protected NearCacheConfiguration nearConfiguration() {
         return new NearCacheConfiguration();
     }
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/integration/IgniteCacheTxNearEnabledNoWriteThroughTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/integration/IgniteCacheTxNearEnabledNoWriteThroughTest.java
index ea12cce..be9bc34 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/integration/IgniteCacheTxNearEnabledNoWriteThroughTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/integration/IgniteCacheTxNearEnabledNoWriteThroughTest.java
@@ -18,12 +18,20 @@
 package org.apache.ignite.internal.processors.cache.integration;
 
 import org.apache.ignite.configuration.NearCacheConfiguration;
+import org.apache.ignite.testframework.MvccFeatureChecker;
 
 /**
  *
  */
 public class IgniteCacheTxNearEnabledNoWriteThroughTest extends IgniteCacheTxNoWriteThroughTest {
     /** {@inheritDoc} */
+    @Override public void setUp() throws Exception {
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.NEAR_CACHE);
+
+        super.setUp();
+    }
+
+    /** {@inheritDoc} */
     @Override protected NearCacheConfiguration nearConfiguration() {
         return new NearCacheConfiguration();
     }
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/integration/IgniteCacheTxNoLoadPreviousValueTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/integration/IgniteCacheTxNoLoadPreviousValueTest.java
index ce9ef9b..094aa1a 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/integration/IgniteCacheTxNoLoadPreviousValueTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/integration/IgniteCacheTxNoLoadPreviousValueTest.java
@@ -20,6 +20,7 @@
 import org.apache.ignite.cache.CacheAtomicityMode;
 import org.apache.ignite.cache.CacheMode;
 import org.apache.ignite.configuration.NearCacheConfiguration;
+import org.apache.ignite.testframework.MvccFeatureChecker;
 
 import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL;
 import static org.apache.ignite.cache.CacheMode.PARTITIONED;
@@ -29,6 +30,13 @@
  */
 public class IgniteCacheTxNoLoadPreviousValueTest extends IgniteCacheNoLoadPreviousValueAbstractTest {
     /** {@inheritDoc} */
+    @Override public void setUp() throws Exception {
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.CACHE_STORE);
+
+        super.setUp();
+    }
+
+    /** {@inheritDoc} */
     @Override protected int gridCount() {
         return 3;
     }
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/integration/IgniteCacheTxNoReadThroughTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/integration/IgniteCacheTxNoReadThroughTest.java
index 90bc768..a94caff 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/integration/IgniteCacheTxNoReadThroughTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/integration/IgniteCacheTxNoReadThroughTest.java
@@ -20,6 +20,7 @@
 import org.apache.ignite.cache.CacheAtomicityMode;
 import org.apache.ignite.cache.CacheMode;
 import org.apache.ignite.configuration.NearCacheConfiguration;
+import org.apache.ignite.testframework.MvccFeatureChecker;
 
 import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL;
 import static org.apache.ignite.cache.CacheMode.PARTITIONED;
@@ -29,6 +30,13 @@
  */
 public class IgniteCacheTxNoReadThroughTest extends IgniteCacheNoReadThroughAbstractTest {
     /** {@inheritDoc} */
+    @Override public void setUp() throws Exception {
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.CACHE_STORE);
+
+        super.setUp();
+    }
+
+    /** {@inheritDoc} */
     @Override protected int gridCount() {
         return 3;
     }
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/integration/IgniteCacheTxNoWriteThroughTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/integration/IgniteCacheTxNoWriteThroughTest.java
index 325d969..e984dfb 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/integration/IgniteCacheTxNoWriteThroughTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/integration/IgniteCacheTxNoWriteThroughTest.java
@@ -20,6 +20,7 @@
 import org.apache.ignite.cache.CacheAtomicityMode;
 import org.apache.ignite.cache.CacheMode;
 import org.apache.ignite.configuration.NearCacheConfiguration;
+import org.apache.ignite.testframework.MvccFeatureChecker;
 
 import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL;
 import static org.apache.ignite.cache.CacheMode.PARTITIONED;
@@ -29,6 +30,13 @@
  */
 public class IgniteCacheTxNoWriteThroughTest extends IgniteCacheNoWriteThroughAbstractTest {
     /** {@inheritDoc} */
+    @Override public void setUp() throws Exception {
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.CACHE_STORE);
+
+        super.setUp();
+    }
+
+    /** {@inheritDoc} */
     @Override protected int gridCount() {
         return 3;
     }
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/integration/IgniteCacheTxStoreSessionTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/integration/IgniteCacheTxStoreSessionTest.java
index b9e884b..77f54af 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/integration/IgniteCacheTxStoreSessionTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/integration/IgniteCacheTxStoreSessionTest.java
@@ -25,6 +25,7 @@
 import org.apache.ignite.cache.CacheMode;
 import org.apache.ignite.configuration.NearCacheConfiguration;
 import org.apache.ignite.internal.util.typedef.F;
+import org.apache.ignite.testframework.MvccFeatureChecker;
 import org.apache.ignite.transactions.Transaction;
 import org.apache.ignite.transactions.TransactionConcurrency;
 import org.apache.ignite.transactions.TransactionIsolation;
@@ -39,6 +40,13 @@
  */
 public class IgniteCacheTxStoreSessionTest extends IgniteCacheStoreSessionAbstractTest {
     /** {@inheritDoc} */
+    @Override public void setUp() throws Exception {
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.CACHE_STORE);
+
+        super.setUp();
+    }
+
+    /** {@inheritDoc} */
     @Override protected int gridCount() {
         return 3;
     }
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/integration/IgniteCacheTxStoreSessionWriteBehindCoalescingTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/integration/IgniteCacheTxStoreSessionWriteBehindCoalescingTest.java
index a90b4f1..ea2b8a3 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/integration/IgniteCacheTxStoreSessionWriteBehindCoalescingTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/integration/IgniteCacheTxStoreSessionWriteBehindCoalescingTest.java
@@ -22,6 +22,7 @@
 import javax.cache.integration.CacheWriterException;
 import org.apache.ignite.cache.CacheAtomicityMode;
 import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.testframework.MvccFeatureChecker;
 
 import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL;
 
@@ -31,6 +32,13 @@
  */
 public class IgniteCacheTxStoreSessionWriteBehindCoalescingTest extends IgniteCacheStoreSessionWriteBehindAbstractTest {
     /** {@inheritDoc} */
+    @Override public void setUp() throws Exception {
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.CACHE_STORE);
+
+        super.setUp();
+    }
+
+    /** {@inheritDoc} */
     @Override protected CacheAtomicityMode atomicityMode() {
         return TRANSACTIONAL;
     }
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/integration/IgniteCacheTxStoreSessionWriteBehindTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/integration/IgniteCacheTxStoreSessionWriteBehindTest.java
index b72aba3..ae6bcae 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/integration/IgniteCacheTxStoreSessionWriteBehindTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/integration/IgniteCacheTxStoreSessionWriteBehindTest.java
@@ -18,6 +18,7 @@
 package org.apache.ignite.internal.processors.cache.integration;
 
 import org.apache.ignite.cache.CacheAtomicityMode;
+import org.apache.ignite.testframework.MvccFeatureChecker;
 
 import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL;
 
@@ -26,6 +27,13 @@
  */
 public class IgniteCacheTxStoreSessionWriteBehindTest extends IgniteCacheStoreSessionWriteBehindAbstractTest {
     /** {@inheritDoc} */
+    @Override public void setUp() throws Exception {
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.CACHE_STORE);
+
+        super.setUp();
+    }
+
+    /** {@inheritDoc} */
     @Override protected CacheAtomicityMode atomicityMode() {
         return TRANSACTIONAL;
     }
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/local/GridCacheDaemonNodeLocalSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/local/GridCacheDaemonNodeLocalSelfTest.java
index 8578db7..aa63fe6 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/local/GridCacheDaemonNodeLocalSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/local/GridCacheDaemonNodeLocalSelfTest.java
@@ -19,6 +19,7 @@
 
 import org.apache.ignite.cache.CacheMode;
 import org.apache.ignite.internal.processors.cache.GridCacheDaemonNodeAbstractSelfTest;
+import org.apache.ignite.testframework.MvccFeatureChecker;
 
 import static org.apache.ignite.cache.CacheMode.LOCAL;
 
@@ -27,6 +28,13 @@
  */
 public class GridCacheDaemonNodeLocalSelfTest extends GridCacheDaemonNodeAbstractSelfTest {
     /** {@inheritDoc} */
+    @Override protected void beforeTestsStarted() throws Exception {
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.LOCAL_CACHE);
+
+        super.beforeTestsStarted();
+    }
+
+    /** {@inheritDoc} */
     @Override protected CacheMode cacheMode() {
         return LOCAL;
     }
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/local/GridCacheLocalByteArrayValuesSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/local/GridCacheLocalByteArrayValuesSelfTest.java
index a6be82b..e6c4771 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/local/GridCacheLocalByteArrayValuesSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/local/GridCacheLocalByteArrayValuesSelfTest.java
@@ -26,6 +26,7 @@
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.internal.processors.cache.GridCacheAbstractByteArrayValuesSelfTest;
 import org.apache.ignite.internal.util.typedef.F;
+import org.apache.ignite.testframework.MvccFeatureChecker;
 import org.apache.ignite.transactions.Transaction;
 import org.apache.ignite.transactions.TransactionConcurrency;
 import org.jetbrains.annotations.Nullable;
@@ -67,6 +68,8 @@
 
     /** {@inheritDoc} */
     @Override protected void beforeTestsStarted() throws Exception {
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.LOCAL_CACHE);
+
         ignite = startGrid(1);
 
         cache = ignite.cache(CACHE_REGULAR);
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/local/GridCacheLocalEventSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/local/GridCacheLocalEventSelfTest.java
index c0b6071..716e5dd 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/local/GridCacheLocalEventSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/local/GridCacheLocalEventSelfTest.java
@@ -30,7 +30,7 @@
     /** {@inheritDoc} */
     @Override public void beforeTestsStarted() throws Exception {
         MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.LOCAL_CACHE);
-
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.CACHE_EVENTS);
 
         super.beforeTestsStarted();
     }
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/mvcc/CacheMvccAbstractTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/mvcc/CacheMvccAbstractTest.java
index 4283d1c..a6100d8 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/mvcc/CacheMvccAbstractTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/mvcc/CacheMvccAbstractTest.java
@@ -61,6 +61,8 @@
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.configuration.TransactionConfiguration;
 import org.apache.ignite.configuration.WALMode;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.GridKernalContext;
 import org.apache.ignite.internal.IgniteEx;
 import org.apache.ignite.internal.IgniteFutureCancelledCheckedException;
@@ -249,6 +251,11 @@
         super.afterTest();
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * @param cfgC Optional closure applied to cache configuration.
      * @throws Exception If failed.
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/IgniteBaselineAffinityTopologyActivationTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/IgniteBaselineAffinityTopologyActivationTest.java
index 838c732..cc824be 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/IgniteBaselineAffinityTopologyActivationTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/IgniteBaselineAffinityTopologyActivationTest.java
@@ -36,6 +36,8 @@
 import org.apache.ignite.configuration.DataStorageConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.configuration.WALMode;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.IgniteEx;
 import org.apache.ignite.internal.IgniteInternalFuture;
 import org.apache.ignite.internal.cluster.DetachedClusterNode;
@@ -112,6 +114,11 @@
         cleanPersistenceDir();
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * Verifies that when old but compatible node
      * (it is the node that once wasn't presented in branchingHistory but hasn't participated in any branching point)
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/IgnitePdsCacheConfigurationFileConsistencyCheckTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/IgnitePdsCacheConfigurationFileConsistencyCheckTest.java
index 74a395023..80f5616 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/IgnitePdsCacheConfigurationFileConsistencyCheckTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/IgnitePdsCacheConfigurationFileConsistencyCheckTest.java
@@ -32,6 +32,8 @@
 import org.apache.ignite.configuration.DataRegionConfiguration;
 import org.apache.ignite.configuration.DataStorageConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.IgniteEx;
 import org.apache.ignite.internal.processors.cache.DynamicCacheDescriptor;
 import org.apache.ignite.internal.processors.cache.GridCacheSharedContext;
@@ -97,6 +99,11 @@
         super.afterTest();
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * Tests that ignite can start when caches' configurations with same name in different groups stored.
      *
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/IgnitePdsCacheRebalancingAbstractTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/IgnitePdsCacheRebalancingAbstractTest.java
index 389a7fe..b338f60 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/IgnitePdsCacheRebalancingAbstractTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/IgnitePdsCacheRebalancingAbstractTest.java
@@ -49,6 +49,8 @@
 import org.apache.ignite.configuration.DataStorageConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.configuration.WALMode;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.IgniteEx;
 import org.apache.ignite.internal.IgniteInternalFuture;
 import org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridDhtLocalPartition;
@@ -158,6 +160,11 @@
         return cfg;
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * @param cacheCfgs Cache cfgs.
      */
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 25d54ab..1002c98 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
@@ -37,6 +37,8 @@
 import org.apache.ignite.configuration.DataStorageConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.configuration.WALMode;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.IgniteInternalFuture;
 import org.apache.ignite.internal.util.tostring.GridToStringInclude;
 import org.apache.ignite.internal.util.typedef.internal.S;
@@ -119,6 +121,11 @@
         cleanPersistenceDir();
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * @throws Exception if failed.
      */
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/IgnitePdsTaskCancelingTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/IgnitePdsTaskCancelingTest.java
index 6b53339..9409f9d 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/IgnitePdsTaskCancelingTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/IgnitePdsTaskCancelingTest.java
@@ -87,6 +87,9 @@
 
         cfg.setDataStorageConfiguration(getDataStorageConfiguration());
 
+        // Set the thread pool size according to the NUM_TASKS.
+        cfg.setPublicThreadPoolSize(16);
+
         return cfg;
     }
 
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 56426f3..04af1cc 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
@@ -23,6 +23,7 @@
 import java.nio.MappedByteBuffer;
 import java.nio.file.OpenOption;
 import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ThreadLocalRandom;
 import java.util.concurrent.atomic.AtomicReference;
 import org.apache.ignite.Ignite;
 import org.apache.ignite.IgniteCache;
@@ -51,6 +52,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.GridTestUtils;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
 import org.junit.Assert;
 
@@ -64,6 +66,12 @@
     private static boolean disableWalDuringRebalancing = true;
 
     /** */
+    private static boolean enablePendingTxTracker = false;
+
+    /** */
+    private static int dfltCacheBackupCnt = 0;
+
+    /** */
     private static final AtomicReference<CountDownLatch> supplyMessageLatch = new AtomicReference<>();
 
     /** */
@@ -92,7 +100,8 @@
         cfg.setCacheConfiguration(
             new CacheConfiguration(DEFAULT_CACHE_NAME)
                 // Test checks internal state before and after rebalance, so it is configured to be triggered manually
-                .setRebalanceDelay(-1),
+                .setRebalanceDelay(-1)
+                .setBackups(dfltCacheBackupCnt),
 
             new CacheConfiguration(REPL_CACHE)
                 .setRebalanceDelay(-1)
@@ -147,6 +156,9 @@
         System.setProperty(IgniteSystemProperties.IGNITE_DISABLE_WAL_DURING_REBALANCING,
             Boolean.toString(disableWalDuringRebalancing));
 
+        System.setProperty(IgniteSystemProperties.IGNITE_PENDING_TX_TRACKER_ENABLED,
+            Boolean.toString(enablePendingTxTracker));
+
         return cfg;
     }
 
@@ -184,6 +196,17 @@
         cleanPersistenceDir();
 
         disableWalDuringRebalancing = true;
+        enablePendingTxTracker = false;
+        dfltCacheBackupCnt = 0;
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void afterTestsStopped() throws Exception {
+        super.afterTestsStopped();
+
+        System.clearProperty(IgniteSystemProperties.IGNITE_DISABLE_WAL_DURING_REBALANCING);
+
+        System.clearProperty(IgniteSystemProperties.IGNITE_PENDING_TX_TRACKER_ENABLED);
     }
 
     /**
@@ -286,6 +309,60 @@
     /**
      * @throws Exception If failed.
      */
+    public void testWalDisabledDuringRebalancingWithPendingTxTracker() throws Exception {
+        enablePendingTxTracker = true;
+        dfltCacheBackupCnt = 2;
+
+        Ignite ignite = startGrids(3);
+
+        ignite.cluster().active(true);
+
+        ignite.cluster().setBaselineTopology(3);
+
+        IgniteCache<Integer, Integer> cache = ignite.cache(DEFAULT_CACHE_NAME);
+
+        stopGrid(2);
+
+        awaitExchange((IgniteEx)ignite);
+
+        doLoad(cache, 4, 10_000);
+
+        IgniteEx newIgnite = startGrid(2);
+
+        awaitExchange(newIgnite);
+
+        CacheGroupContext grpCtx = newIgnite.cachex(DEFAULT_CACHE_NAME).context().group();
+
+        assertFalse(grpCtx.walEnabled());
+
+        long rebalanceStartedTs = System.currentTimeMillis();
+
+        for (Ignite g : G.allGrids())
+            g.cache(DEFAULT_CACHE_NAME).rebalance();
+
+        awaitPartitionMapExchange();
+
+        assertTrue(grpCtx.walEnabled());
+
+        long rebalanceFinishedTs = System.currentTimeMillis();
+
+        CheckpointHistory cpHist =
+            ((GridCacheDatabaseSharedManager)newIgnite.context().cache().context().database()).checkpointHistory();
+
+        assertNotNull(cpHist);
+
+        // Ensure there was a checkpoint on WAL re-activation.
+        assertEquals(
+            1,
+            cpHist.checkpoints()
+                .stream()
+                .filter(ts -> rebalanceStartedTs <= ts && ts <= rebalanceFinishedTs)
+                .count());
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
     public void testLocalAndGlobalWalStateInterdependence() throws Exception {
         Ignite ignite = startGrids(3);
 
@@ -532,6 +609,29 @@
     }
 
     /**
+     * Put random values to cache in multiple threads until time interval given expires.
+     *
+     * @param cache Cache to modify.
+     * @param threadCnt Number ot threads to be used.
+     * @param duration Time interval in milliseconds.
+     * @throws Exception When something goes wrong.
+     */
+    private void doLoad(IgniteCache<Integer, Integer> cache, int threadCnt, long duration) throws Exception {
+        GridTestUtils.runMultiThreaded(() -> {
+            long stopTs = U.currentTimeMillis() + duration;
+
+            int keysCnt = getKeysCount();
+
+            ThreadLocalRandom rnd = ThreadLocalRandom.current();
+
+            do {
+                cache.put(rnd.nextInt(keysCnt), rnd.nextInt());
+            }
+            while (U.currentTimeMillis() < stopTs);
+        }, threadCnt, "load-cache");
+    }
+
+    /**
      *
      */
     private static class TestFileIOFactory implements FileIOFactory {
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/IgnitePdsCacheWalDisabledOnRebalancingTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/IgnitePdsCacheWalDisabledOnRebalancingTest.java
new file mode 100644
index 0000000..1246db1
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/IgnitePdsCacheWalDisabledOnRebalancingTest.java
@@ -0,0 +1,266 @@
+/*
+ * 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.cache.persistence.db;
+
+import java.io.File;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import org.apache.ignite.Ignite;
+import org.apache.ignite.IgniteCache;
+import org.apache.ignite.IgniteSystemProperties;
+import org.apache.ignite.cache.CacheAtomicityMode;
+import org.apache.ignite.cache.CacheMode;
+import org.apache.ignite.cache.affinity.rendezvous.RendezvousAffinityFunction;
+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.configuration.WALMode;
+import org.apache.ignite.internal.IgniteEx;
+import org.apache.ignite.internal.TestRecordingCommunicationSpi;
+import org.apache.ignite.internal.processors.cache.distributed.dht.preloader.GridDhtPartitionDemandMessage;
+import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.lang.IgniteBiPredicate;
+import org.apache.ignite.mxbean.CacheGroupMetricsMXBean;
+import org.apache.ignite.plugin.extensions.communication.Message;
+import org.apache.ignite.testframework.GridTestUtils;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+
+import static org.apache.ignite.internal.processors.cache.persistence.file.FilePageStoreManager.DFLT_STORE_DIR;
+
+/**
+ * Test scenarios with rebalancing, IGNITE_DISABLE_WAL_DURING_REBALANCING optimization and topology changes
+ * such as client nodes join/leave, server nodes from BLT leave/join, server nodes out of BLT join/leave.
+ */
+public class IgnitePdsCacheWalDisabledOnRebalancingTest extends GridCommonAbstractTest {
+    /** Block message predicate to set to Communication SPI in node configuration. */
+    private IgniteBiPredicate<ClusterNode, Message> blockMessagePredicate;
+
+    /** */
+    private static final int CACHE1_PARTS_NUM = 8;
+
+    /** */
+    private static final int CACHE2_PARTS_NUM = 16;
+
+    /** */
+    private static final int CACHE3_PARTS_NUM = 32;
+
+    /** */
+    private static final int CACHE_SIZE = 2_000;
+
+    /** */
+    private static final String CACHE3_NAME = "cache3";
+
+    /** {@inheritDoc} */
+    @Override protected void beforeTest() throws Exception {
+        super.beforeTest();
+
+        cleanPersistenceDir();
+
+        System.setProperty(IgniteSystemProperties.IGNITE_DISABLE_WAL_DURING_REBALANCING, "true");
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void afterTest() throws Exception {
+        stopAllGrids();
+
+        cleanPersistenceDir();
+
+        System.clearProperty(IgniteSystemProperties.IGNITE_DISABLE_WAL_DURING_REBALANCING);
+    }
+
+    /** {@inheritDoc} */
+    @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception {
+        IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName);
+
+        CacheConfiguration ccfg1 = new CacheConfiguration("cache1")
+            .setAtomicityMode(CacheAtomicityMode.ATOMIC)
+            .setCacheMode(CacheMode.REPLICATED)
+            .setAffinity(new RendezvousAffinityFunction(false, CACHE1_PARTS_NUM));
+
+        CacheConfiguration ccfg2 = new CacheConfiguration("cache2")
+            .setBackups(1)
+            .setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL)
+            .setCacheMode(CacheMode.PARTITIONED)
+            .setAffinity(new RendezvousAffinityFunction(false, CACHE2_PARTS_NUM));
+
+        CacheConfiguration ccfg3 = new CacheConfiguration(CACHE3_NAME)
+            .setBackups(2)
+            .setAtomicityMode(CacheAtomicityMode.ATOMIC)
+            .setCacheMode(CacheMode.PARTITIONED)
+            .setAffinity(new RendezvousAffinityFunction(false, CACHE3_PARTS_NUM));
+
+        cfg.setCacheConfiguration(ccfg1, ccfg2, ccfg3);
+
+        if ("client".equals(igniteInstanceName))
+            cfg.setClientMode(true);
+        else {
+            DataStorageConfiguration dsCfg = new DataStorageConfiguration()
+                .setConcurrencyLevel(Runtime.getRuntime().availableProcessors() * 4)
+                .setWalMode(WALMode.LOG_ONLY)
+                .setDefaultDataRegionConfiguration(
+                    new DataRegionConfiguration()
+                        .setPersistenceEnabled(true)
+                        .setMaxSize(256 * 1024 * 1024));
+
+            cfg.setDataStorageConfiguration(dsCfg);
+        }
+
+        TestRecordingCommunicationSpi commSpi = new TestRecordingCommunicationSpi();
+        commSpi.blockMessages(blockMessagePredicate);
+
+        cfg.setCommunicationSpi(commSpi);
+
+
+        return cfg;
+    }
+
+    /**
+     * If client joins topology during rebalancing process, rebalancing finishes successfully,
+     * all partitions are owned as expected when rebalancing finishes.
+     */
+    public void testClientJoinsLeavesDuringRebalancing() throws Exception {
+        Ignite ig0 = startGrids(2);
+
+        ig0.active(true);
+
+        for (int i = 0; i < 3; i++)
+            fillCache(ig0.getOrCreateCache("cache" + i), CACHE_SIZE);
+
+        String ig1Name = "node01-" + grid(1).localNode().consistentId();
+
+        stopGrid(1);
+
+        cleanPersistenceFiles(ig1Name);
+
+        int groupId = ((IgniteEx) ig0).cachex(CACHE3_NAME).context().groupId();
+
+        blockMessagePredicate = (node, msg) -> {
+            if (msg instanceof GridDhtPartitionDemandMessage)
+                return ((GridDhtPartitionDemandMessage) msg).groupId() == groupId;
+
+            return false;
+        };
+
+        IgniteEx ig1 = startGrid(1);
+
+        startGrid("client");
+
+        stopGrid("client");
+
+        CacheGroupMetricsMXBean mxBean = ig1.cachex(CACHE3_NAME).context().group().mxBean();
+
+        assertTrue("Unexpected moving partitions count: " + mxBean.getLocalNodeMovingPartitionsCount(),
+            mxBean.getLocalNodeMovingPartitionsCount() == CACHE3_PARTS_NUM);
+
+        TestRecordingCommunicationSpi commSpi = (TestRecordingCommunicationSpi) ig1
+            .configuration().getCommunicationSpi();
+
+        commSpi.stopBlock();
+
+        boolean waitResult = GridTestUtils.waitForCondition(
+            () -> mxBean.getLocalNodeMovingPartitionsCount() == 0,
+            30_000);
+
+        assertTrue("Failed to wait for owning all partitions, parts in moving state: "
+            + mxBean.getLocalNodeMovingPartitionsCount(), waitResult);
+    }
+
+    /**
+     * If server nodes from BLT leave topology and then join again after additional keys were put to caches,
+     * rebalance starts.
+     * 
+     * Test verifies that all moving partitions get owned after rebalance finishes.
+     *
+     * @throws Exception If failed.
+     */
+    public void testServerNodesFromBltLeavesAndJoinsDuringRebalancing() throws Exception {
+        Ignite ig0 = startGridsMultiThreaded(4);
+
+        fillCache(ig0.cache(CACHE3_NAME), CACHE_SIZE);
+
+        List<Integer> nonAffinityKeys1 = nearKeys(grid(1).cache(CACHE3_NAME), 100, CACHE_SIZE / 2);
+        List<Integer> nonAffinityKeys2 = nearKeys(grid(2).cache(CACHE3_NAME), 100, CACHE_SIZE / 2);
+
+        stopGrid(1);
+        stopGrid(2);
+
+        Set<Integer> nonAffinityKeysSet = new HashSet<>();
+
+        nonAffinityKeysSet.addAll(nonAffinityKeys1);
+        nonAffinityKeysSet.addAll(nonAffinityKeys2);
+
+        fillCache(ig0.cache(CACHE3_NAME), nonAffinityKeysSet);
+
+        int groupId = ((IgniteEx) ig0).cachex(CACHE3_NAME).context().groupId();
+
+        blockMessagePredicate = (node, msg) -> {
+            if (msg instanceof GridDhtPartitionDemandMessage)
+                return ((GridDhtPartitionDemandMessage) msg).groupId() == groupId;
+
+            return false;
+        };
+
+        IgniteEx ig1 = startGrid(1);
+
+        CacheGroupMetricsMXBean mxBean = ig1.cachex(CACHE3_NAME).context().group().mxBean();
+
+        TestRecordingCommunicationSpi commSpi = (TestRecordingCommunicationSpi) ig1
+            .configuration().getCommunicationSpi();
+
+        startGrid(2);
+
+        commSpi.stopBlock();
+
+        boolean allOwned = GridTestUtils.waitForCondition(
+            () -> mxBean.getLocalNodeMovingPartitionsCount() == 0, 30_000);
+
+        assertTrue("Partitions were not owned, there are " + mxBean.getLocalNodeMovingPartitionsCount() +
+            " partitions in MOVING state", allOwned);
+    }
+
+    /** */
+    private void cleanPersistenceFiles(String igName) throws Exception {
+        String ig1DbPath = Paths.get(DFLT_STORE_DIR, igName).toString();
+
+        File igDbDir = U.resolveWorkDirectory(U.defaultWorkDirectory(), ig1DbPath, false);
+
+        U.delete(igDbDir);
+        Files.createDirectory(igDbDir.toPath());
+
+        String ig1DbWalPath = Paths.get(DFLT_STORE_DIR, "wal", igName).toString();
+
+        U.delete(U.resolveWorkDirectory(U.defaultWorkDirectory(), ig1DbWalPath, false));
+    }
+
+    /** */
+    private void fillCache(IgniteCache cache, int cacheSize) {
+        for (int i = 0; i < cacheSize; i++)
+            cache.put(i, "value_" + i);
+    }
+
+    /** */
+    private void fillCache(IgniteCache cache, Collection<Integer> keys) {
+        for (Integer key : keys)
+            cache.put(key, "value_" + key);
+    }
+}
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/IgnitePdsRebalancingOnNotStableTopologyTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/IgnitePdsRebalancingOnNotStableTopologyTest.java
index 8b3c875..cc81a3e 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/IgnitePdsRebalancingOnNotStableTopologyTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/IgnitePdsRebalancingOnNotStableTopologyTest.java
@@ -32,6 +32,8 @@
 import org.apache.ignite.configuration.DataStorageConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.configuration.WALMode;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.util.typedef.internal.U;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
 import org.apache.ignite.testframework.junits.multijvm.IgniteProcessProxy;
@@ -204,4 +206,9 @@
     @Override protected long getTestTimeout() {
         return TimeUnit.MINUTES.toMillis(10);
     }
+
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
 }
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/wal/IgniteWalFlushFailoverTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/wal/IgniteWalFlushFailoverTest.java
index 8b182c9..e930c8b 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/wal/IgniteWalFlushFailoverTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/wal/IgniteWalFlushFailoverTest.java
@@ -30,6 +30,8 @@
 import org.apache.ignite.configuration.DataStorageConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.configuration.WALMode;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.GridKernalState;
 import org.apache.ignite.internal.IgniteEx;
 import org.apache.ignite.internal.processors.cache.persistence.file.FileIO;
@@ -95,6 +97,11 @@
         return cfg;
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * Test flushing error recovery when flush is triggered asynchronously by timeout
      *
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/wal/IgniteWalFlushMultiNodeFailoverAbstractSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/wal/IgniteWalFlushMultiNodeFailoverAbstractSelfTest.java
index 232591c..d520827 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/wal/IgniteWalFlushMultiNodeFailoverAbstractSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/wal/IgniteWalFlushMultiNodeFailoverAbstractSelfTest.java
@@ -34,6 +34,8 @@
 import org.apache.ignite.configuration.DataStorageConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.configuration.WALMode;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.failure.StopNodeFailureHandler;
 import org.apache.ignite.internal.pagemem.wal.IgniteWriteAheadLogManager;
 import org.apache.ignite.internal.processors.cache.persistence.file.FileIO;
@@ -93,6 +95,11 @@
         return 120_000;
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * @return WAL mode used in test.
      */
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/wal/WalCompactionTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/wal/WalCompactionTest.java
index 14525f0..43dc395 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/wal/WalCompactionTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/wal/WalCompactionTest.java
@@ -31,6 +31,8 @@
 import org.apache.ignite.configuration.DataStorageConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.configuration.WALMode;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.IgniteEx;
 import org.apache.ignite.internal.pagemem.FullPageId;
 import org.apache.ignite.internal.pagemem.wal.record.PageSnapshot;
@@ -111,6 +113,11 @@
         cleanPersistenceDir();
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * Tests applying updates from compacted WAL archive.
      *
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/standbycluster/IgniteChangeGlobalStateFailOverTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/standbycluster/IgniteChangeGlobalStateFailOverTest.java
index 1ef269e..053146a 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/standbycluster/IgniteChangeGlobalStateFailOverTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/standbycluster/IgniteChangeGlobalStateFailOverTest.java
@@ -25,6 +25,8 @@
 import org.apache.ignite.Ignite;
 import org.apache.ignite.IgniteCache;
 import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.IgniteInternalFuture;
 
 import static java.lang.Thread.sleep;
@@ -54,6 +56,11 @@
         return 4;
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * @throws Exception If failed.
      */
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/standbycluster/IgniteNoParrallelClusterIsAllowedTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/standbycluster/IgniteNoParrallelClusterIsAllowedTest.java
index 7180d7b..f8ad2de 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/standbycluster/IgniteNoParrallelClusterIsAllowedTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/standbycluster/IgniteNoParrallelClusterIsAllowedTest.java
@@ -18,6 +18,8 @@
 package org.apache.ignite.internal.processors.cache.persistence.standbycluster;
 
 import junit.framework.AssertionFailedError;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.util.typedef.internal.U;
 import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder;
 import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
@@ -29,6 +31,11 @@
     /** */
     private static final TcpDiscoveryIpFinder vmIpFinder = new TcpDiscoveryVmIpFinder(true);
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * @throws Exception if failed.
      */
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/standbycluster/reconnect/IgniteAbstractStandByClientReconnectTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/standbycluster/reconnect/IgniteAbstractStandByClientReconnectTest.java
index 176d34e..434b499 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/standbycluster/reconnect/IgniteAbstractStandByClientReconnectTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/standbycluster/reconnect/IgniteAbstractStandByClientReconnectTest.java
@@ -30,6 +30,8 @@
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.events.Event;
 import org.apache.ignite.events.EventType;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.IgniteEx;
 import org.apache.ignite.internal.processors.cache.DynamicCacheDescriptor;
 import org.apache.ignite.internal.util.typedef.internal.CU;
@@ -153,6 +155,11 @@
         return cfg;
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * @param disconnectedLatch Disconnect latch. Will be fired when client disconnect event is received.
      * @param reconnectedLatch Reconnect latch. Will be fired when cilent reconnect event is receoved.
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/query/CacheScanQueryFailoverTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/query/CacheScanQueryFailoverTest.java
index 0633138..53f2f62 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/query/CacheScanQueryFailoverTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/query/CacheScanQueryFailoverTest.java
@@ -27,6 +27,8 @@
 import org.apache.ignite.cache.query.ScanQuery;
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.failure.StopNodeOrHaltFailureHandler;
 import org.apache.ignite.lang.IgniteBiPredicate;
 import org.apache.ignite.lang.IgniteClosure;
@@ -82,6 +84,11 @@
         return cfg;
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * @throws Exception If failed.
      */
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/query/IndexingSpiQueryTxSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/query/IndexingSpiQueryTxSelfTest.java
index d3f6896..ff39afb 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/query/IndexingSpiQueryTxSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/query/IndexingSpiQueryTxSelfTest.java
@@ -26,6 +26,8 @@
 import org.apache.ignite.cache.CacheAtomicityMode;
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.IgniteEx;
 import org.apache.ignite.internal.processors.cache.GridCacheAbstractSelfTest;
 import org.apache.ignite.internal.transactions.IgniteTxHeuristicCheckedException;
@@ -70,6 +72,11 @@
         return cfg;
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /** */
     public void testIndexingSpiWithTxClient() throws Exception {
         IgniteEx client = startGrid("client");
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/query/continuous/CacheContinuousQueryAsyncFailoverMvccTxSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/query/continuous/CacheContinuousQueryAsyncFailoverMvccTxSelfTest.java
index 7c15f38..aa60aeb 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/query/continuous/CacheContinuousQueryAsyncFailoverMvccTxSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/query/continuous/CacheContinuousQueryAsyncFailoverMvccTxSelfTest.java
@@ -47,11 +47,6 @@
     }
 
     /** {@inheritDoc} */
-    @Override public void testLeftPrimaryAndBackupNodes() throws Exception {
-        fail("https://issues.apache.org/jira/browse/IGNITE-10047");
-    }
-
-    /** {@inheritDoc} */
     @Override public void testFailoverStartStopBackup() throws Exception {
         fail("https://issues.apache.org/jira/browse/IGNITE-10391");
     }
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/query/continuous/CacheContinuousQueryFailoverAbstractSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/query/continuous/CacheContinuousQueryFailoverAbstractSelfTest.java
index e7c2261..e1883fd 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/query/continuous/CacheContinuousQueryFailoverAbstractSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/query/continuous/CacheContinuousQueryFailoverAbstractSelfTest.java
@@ -68,6 +68,8 @@
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.configuration.NearCacheConfiguration;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.IgniteEx;
 import org.apache.ignite.internal.IgniteInternalFuture;
 import org.apache.ignite.internal.IgniteInterruptedCheckedException;
@@ -202,6 +204,11 @@
         stopAllGrids();
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * @return Cache mode.
      */
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/query/continuous/CacheContinuousQueryFailoverMvccTxSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/query/continuous/CacheContinuousQueryFailoverMvccTxSelfTest.java
index 2d578f2..df27087 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/query/continuous/CacheContinuousQueryFailoverMvccTxSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/query/continuous/CacheContinuousQueryFailoverMvccTxSelfTest.java
@@ -42,11 +42,6 @@
     }
 
     /** {@inheritDoc} */
-    @Override public void testLeftPrimaryAndBackupNodes() throws Exception {
-        fail("https://issues.apache.org/jira/browse/IGNITE-10047");
-    }
-
-    /** {@inheritDoc} */
     @Override public void testFailoverStartStopBackup() throws Exception {
         fail("https://issues.apache.org/jira/browse/IGNITE-10391");
     }
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/query/continuous/CacheContinuousWithTransformerFailoverTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/query/continuous/CacheContinuousWithTransformerFailoverTest.java
index 241dc2a..933dccb 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/query/continuous/CacheContinuousWithTransformerFailoverTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/query/continuous/CacheContinuousWithTransformerFailoverTest.java
@@ -33,6 +33,8 @@
 import org.apache.ignite.cache.query.QueryCursor;
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.lang.IgniteClosure;
 import org.apache.ignite.lang.IgniteOutClosure;
 import org.apache.ignite.resources.LoggerResource;
@@ -80,6 +82,11 @@
         stopAllGrids();
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * @throws Exception If failed.
      */
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/query/continuous/ClientReconnectContinuousQueryTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/query/continuous/ClientReconnectContinuousQueryTest.java
index 9ec25d3..7cea3f5 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/query/continuous/ClientReconnectContinuousQueryTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/query/continuous/ClientReconnectContinuousQueryTest.java
@@ -29,6 +29,8 @@
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.events.Event;
 import org.apache.ignite.events.EventType;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.IgniteEx;
 import org.apache.ignite.internal.IgniteInternalFuture;
 import org.apache.ignite.internal.managers.communication.GridIoManager;
@@ -90,6 +92,11 @@
         return cfg;
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * @return Transaction snapshot.
      */
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/query/continuous/IgniteCacheContinuousQueryReconnectTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/query/continuous/IgniteCacheContinuousQueryReconnectTest.java
index b104a65..edcbe78 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/query/continuous/IgniteCacheContinuousQueryReconnectTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/query/continuous/IgniteCacheContinuousQueryReconnectTest.java
@@ -31,6 +31,8 @@
 import org.apache.ignite.cache.query.ContinuousQuery;
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
 
 import static org.apache.ignite.cache.CacheAtomicityMode.ATOMIC;
@@ -72,6 +74,11 @@
         stopAllGrids();
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * @return Atomic mode.
      */
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/store/GridCacheWriteBehindStoreAbstractTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/store/GridCacheWriteBehindStoreAbstractTest.java
index 1f0e45e..7463fa7 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/store/GridCacheWriteBehindStoreAbstractTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/store/GridCacheWriteBehindStoreAbstractTest.java
@@ -34,6 +34,7 @@
 import org.apache.ignite.internal.util.typedef.internal.U;
 import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
 import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
+import org.apache.ignite.testframework.MvccFeatureChecker;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
 import org.apache.ignite.transactions.Transaction;
 import org.jetbrains.annotations.Nullable;
@@ -52,6 +53,13 @@
     /** Cache store. */
     private static final GridCacheTestStore store = new GridCacheTestStore();
 
+    /** {@inheritDoc} */
+    @Override public void setUp() throws Exception {
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.CACHE_STORE);
+
+        super.setUp();
+    }
+
     /**
      *
      */
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/store/GridCacheWriteBehindStoreLocalTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/store/GridCacheWriteBehindStoreLocalTest.java
index 59dd4b4..160203e 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/store/GridCacheWriteBehindStoreLocalTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/store/GridCacheWriteBehindStoreLocalTest.java
@@ -18,12 +18,20 @@
 package org.apache.ignite.internal.processors.cache.store;
 
 import org.apache.ignite.cache.CacheMode;
+import org.apache.ignite.testframework.MvccFeatureChecker;
 
 /**
  * Tests {@link org.apache.ignite.internal.processors.cache.store.GridCacheWriteBehindStore} in grid configuration.
  */
 public class GridCacheWriteBehindStoreLocalTest extends GridCacheWriteBehindStoreAbstractTest {
     /** {@inheritDoc} */
+    @Override public void setUp() throws Exception {
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.LOCAL_CACHE);
+
+        super.setUp();
+    }
+
+    /** {@inheritDoc} */
     @Override protected CacheMode cacheMode() {
         return CacheMode.LOCAL;
     }
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/store/GridCacheWriteBehindStoreMultithreadedSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/store/GridCacheWriteBehindStoreMultithreadedSelfTest.java
index 4fce452..a9558aa 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/store/GridCacheWriteBehindStoreMultithreadedSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/store/GridCacheWriteBehindStoreMultithreadedSelfTest.java
@@ -187,33 +187,42 @@
         // 50 milliseconds should be enough.
         delegate.setOperationDelay(50);
 
-        initStore(2, writeCoalescing);
+        Set<Integer> exp = null;
 
-        Set<Integer> exp;
+        int start = 0;
+        int end = 0;
 
-        int start = store.getWriteBehindTotalCriticalOverflowCount();
+        long startTime = System.currentTimeMillis();
 
-        try {
-            //We will have in total 5 * CACHE_SIZE keys that should be enough to grow map size to critical value.
-            exp = runPutGetRemoveMultithreaded(5, CACHE_SIZE);
-        }
-        finally {
-            log.info(">>> Done inserting, shutting down the store");
+        while (end - start == 0 && System.currentTimeMillis() - startTime < getTestTimeout()) {
+            initStore(2, writeCoalescing);
 
-            shutdownStore();
+            start = store.getWriteBehindTotalCriticalOverflowCount();
+
+            try {
+                //We will have in total 5 * CACHE_SIZE keys that should be enough to grow map size to critical value.
+                exp = runPutGetRemoveMultithreaded(5, CACHE_SIZE);
+            }
+            finally {
+                log.info(">>> Done inserting, shutting down the store");
+
+                shutdownStore();
+            }
+
+            end = store.getWriteBehindTotalCriticalOverflowCount();
         }
 
         // Restore delay.
         delegate.setOperationDelay(0);
 
-        Map<Integer, String> map = delegate.getMap();
-
-        int end = store.getWriteBehindTotalCriticalOverflowCount();
+        assertNotNull(exp);
 
         log.info(">>> There are " + exp.size() + " keys in store, " + (end - start) + " overflows detected");
 
         assertTrue("No cache overflows detected (a bug or too few keys or too few delay?)", end > start);
 
+        Map<Integer, String> map = delegate.getMap();
+
         Collection<Integer> extra = new HashSet<>(map.keySet());
 
         extra.removeAll(exp);
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/store/GridCacheWriteBehindStorePartitionedMultiNodeSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/store/GridCacheWriteBehindStorePartitionedMultiNodeSelfTest.java
index de61058..d60dc4a 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/store/GridCacheWriteBehindStorePartitionedMultiNodeSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/store/GridCacheWriteBehindStorePartitionedMultiNodeSelfTest.java
@@ -35,6 +35,7 @@
 import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
 import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder;
 import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
+import org.apache.ignite.testframework.MvccFeatureChecker;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
 import org.apache.ignite.transactions.Transaction;
 
@@ -93,6 +94,13 @@
     }
 
     /** {@inheritDoc} */
+    @Override protected void beforeTestsStarted() throws Exception {
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.CACHE_STORE);
+
+        super.beforeTestsStarted();
+    }
+
+    /** {@inheritDoc} */
     @Override protected void afterTestsStopped() throws Exception {
         stores = null;
     }
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/store/IgnteCacheClientWriteBehindStoreAbstractTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/store/IgnteCacheClientWriteBehindStoreAbstractTest.java
index a64104e..23bb781 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/store/IgnteCacheClientWriteBehindStoreAbstractTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/store/IgnteCacheClientWriteBehindStoreAbstractTest.java
@@ -28,12 +28,20 @@
 import org.apache.ignite.internal.processors.cache.IgniteCacheAbstractTest;
 import org.apache.ignite.internal.util.lang.GridAbsPredicate;
 import org.apache.ignite.testframework.GridTestUtils;
+import org.apache.ignite.testframework.MvccFeatureChecker;
 
 /**
  * Tests that write behind store is updated if client does not have store.
  */
 public abstract class IgnteCacheClientWriteBehindStoreAbstractTest extends IgniteCacheAbstractTest {
     /** {@inheritDoc} */
+    @Override protected void beforeTestsStarted() throws Exception {
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.CACHE_STORE);
+
+        super.beforeTestsStarted();
+    }
+
+    /** {@inheritDoc} */
     @Override protected int gridCount() {
         return 3;
     }
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TransactionIntegrityWithPrimaryIndexCorruptionTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TransactionIntegrityWithPrimaryIndexCorruptionTest.java
index fd31ee5..616bf97 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TransactionIntegrityWithPrimaryIndexCorruptionTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TransactionIntegrityWithPrimaryIndexCorruptionTest.java
@@ -34,6 +34,7 @@
 import org.apache.ignite.internal.processors.cache.persistence.tree.util.PageHandler;
 import org.apache.ignite.internal.processors.cache.tree.SearchRow;
 import org.apache.ignite.testframework.GridTestUtils;
+import org.apache.ignite.testframework.MvccFeatureChecker;
 
 import static org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridDhtPartitionState.OWNING;
 
@@ -45,6 +46,14 @@
     private static volatile boolean corruptionEnabled;
 
     /** {@inheritDoc} */
+    @Override protected void beforeTest() throws Exception {
+        if (MvccFeatureChecker.forcedMvcc())
+            fail("https://issues.apache.org/jira/browse/IGNITE-10470");
+
+        super.beforeTest();
+    }
+
+    /** {@inheritDoc} */
     @Override protected void afterTest() throws Exception {
         corruptionEnabled = false;
 
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxLabelTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxLabelTest.java
index d89ba0b..50b107d 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxLabelTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxLabelTest.java
@@ -18,13 +18,27 @@
 package org.apache.ignite.internal.processors.cache.transactions;
 
 import org.apache.ignite.Ignite;
-import org.apache.ignite.internal.processors.cache.GridCacheAbstractSelfTest;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
 import org.apache.ignite.transactions.Transaction;
 
 /**
  * Tests transaction labels.
  */
-public class TxLabelTest extends GridCacheAbstractSelfTest {
+public class TxLabelTest extends GridCommonAbstractTest {
+    /** {@inheritDoc} */
+    @Override protected void beforeTestsStarted() throws Exception {
+        super.beforeTestsStarted();
+
+        startGrid(0).getOrCreateCache(defaultCacheConfiguration());
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void afterTestsStopped() throws Exception {
+        stopAllGrids();
+
+        super.afterTestsStopped();
+    }
+
     /**
      * Tests transaction labels.
      */
@@ -55,9 +69,4 @@
             tx.commit();
         }
     }
-
-    /** {@inheritDoc} */
-    @Override protected int gridCount() {
-        return 1;
-    }
 }
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxOptimisticPrepareOnUnstableTopologyTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxOptimisticPrepareOnUnstableTopologyTest.java
index cbdcffe..87550fd 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxOptimisticPrepareOnUnstableTopologyTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxOptimisticPrepareOnUnstableTopologyTest.java
@@ -25,6 +25,8 @@
 import org.apache.ignite.IgniteCache;
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.IgniteEx;
 import org.apache.ignite.internal.IgniteInternalFuture;
 import org.apache.ignite.internal.IgniteKernal;
@@ -87,6 +89,11 @@
         return c;
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      *
      */
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxRollbackAsyncNearCacheTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxRollbackAsyncNearCacheTest.java
index 5caa1a0..dc115e1 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxRollbackAsyncNearCacheTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxRollbackAsyncNearCacheTest.java
@@ -17,6 +17,8 @@
 
 package org.apache.ignite.internal.processors.cache.transactions;
 
+import org.apache.ignite.testframework.MvccFeatureChecker;
+
 /**
  * Tests an ability to async rollback near transactions.
  */
@@ -25,4 +27,11 @@
     @Override protected boolean nearCacheEnabled() {
         return true;
     }
+
+    /** {@inheritDoc} */
+    @Override public void setUp() throws Exception {
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.NEAR_CACHE);
+
+        super.setUp();
+    }
 }
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 e5e35b8..8076746 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
@@ -48,6 +48,8 @@
 import org.apache.ignite.configuration.NearCacheConfiguration;
 import org.apache.ignite.events.Event;
 import org.apache.ignite.events.EventType;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.IgniteEx;
 import org.apache.ignite.internal.IgniteFutureCancelledCheckedException;
 import org.apache.ignite.internal.IgniteInternalFuture;
@@ -57,6 +59,7 @@
 import org.apache.ignite.internal.processors.cache.GridCacheContext;
 import org.apache.ignite.internal.processors.cache.GridCacheSharedContext;
 import org.apache.ignite.internal.processors.cache.distributed.near.GridNearLockRequest;
+import org.apache.ignite.internal.processors.cache.distributed.near.GridNearTxEnlistRequest;
 import org.apache.ignite.internal.processors.cache.distributed.near.GridNearTxFinishRequest;
 import org.apache.ignite.internal.processors.cache.distributed.near.GridNearTxLocal;
 import org.apache.ignite.internal.util.future.GridFutureAdapter;
@@ -81,6 +84,7 @@
 import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
 import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
 import org.apache.ignite.testframework.GridTestUtils.SF;
+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;
@@ -96,7 +100,6 @@
 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;
 import static org.apache.ignite.transactions.TransactionIsolation.REPEATABLE_READ;
 import static org.apache.ignite.transactions.TransactionIsolation.SERIALIZABLE;
 import static org.apache.ignite.transactions.TransactionState.ROLLED_BACK;
@@ -165,10 +168,11 @@
     }
 
     /**
-     *
      * @return {@code True} if persistence must be enabled for test.
      */
-    protected boolean persistenceEnabled() { return false; }
+    protected boolean persistenceEnabled() {
+        return false;
+    }
 
     /** {@inheritDoc} */
     @Override protected void beforeTest() throws Exception {
@@ -190,6 +194,11 @@
         stopAllGrids();
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * @return Started client.
      * @throws Exception If f nodeailed.
@@ -211,6 +220,9 @@
      *
      */
     public void testRollbackSimple() throws Exception {
+        if (MvccFeatureChecker.forcedMvcc())
+            fail("https://issues.apache.org/jira/browse/IGNITE-7952");
+
         startClient();
 
         for (Ignite ignite : G.allGrids()) {
@@ -225,7 +237,7 @@
      */
     private void testRollbackSimple0(Ignite near) throws Exception {
         // Normal rollback after put.
-        Transaction tx = near.transactions().txStart(PESSIMISTIC, READ_COMMITTED);
+        Transaction tx = near.transactions().txStart(PESSIMISTIC, REPEATABLE_READ);
 
         near.cache(CACHE_NAME).put(0, 0);
 
@@ -339,14 +351,13 @@
     }
 
     /**
-     *
      * @param holdLockNode Node holding the write lock.
      * @param tryLockNode Node trying to acquire lock.
      * @param useTimeout {@code True} if need to start tx with timeout.
-     *
      * @throws Exception If failed.
      */
-    private void testSynchronousRollback0(Ignite holdLockNode, final Ignite tryLockNode, final boolean useTimeout) throws Exception {
+    private void testSynchronousRollback0(Ignite holdLockNode, final Ignite tryLockNode,
+        final boolean useTimeout) throws Exception {
         final CountDownLatch keyLocked = new CountDownLatch(1);
 
         CountDownLatch waitCommit = new CountDownLatch(1);
@@ -390,7 +401,7 @@
                         txReadyFut.onDone(tx);
 
                         // Will block on lock request until rolled back asynchronously.
-                        Object o = tryLockNode.cache(CACHE_NAME).get(0);
+                        Object o = tryLockNode.cache(CACHE_NAME).getAndPut(0, 0);
 
                         assertNull(o); // If rolled back by close, previous get will return null.
                     }
@@ -409,7 +420,7 @@
 
                 int proc = 1;
 
-                while(true) {
+                while (true) {
                     try {
                         Transaction tx = txReadyFut.get();
 
@@ -480,6 +491,9 @@
      *
      */
     public void testEnlistManyReadOptimistic() throws Exception {
+        if (MvccFeatureChecker.forcedMvcc())
+            return; // Optimistic transactions are not supported by MVCC.
+
         testEnlistMany(false, SERIALIZABLE, OPTIMISTIC);
     }
 
@@ -487,14 +501,17 @@
      *
      */
     public void testEnlistManyWriteOptimistic() throws Exception {
+        if (MvccFeatureChecker.forcedMvcc())
+            return; // Optimistic transactions are not supported by MVCC.
+
         testEnlistMany(true, SERIALIZABLE, OPTIMISTIC);
     }
 
-
     /**
      *
      */
-    private void testEnlistMany(boolean write, TransactionIsolation isolation, TransactionConcurrency conc) throws Exception {
+    private void testEnlistMany(boolean write, TransactionIsolation isolation,
+        TransactionConcurrency conc) throws Exception {
         final Ignite client = startClient();
 
         Map<Integer, Integer> entries = new HashMap<>();
@@ -504,7 +521,7 @@
 
         IgniteInternalFuture<?> fut = null;
 
-        try(Transaction tx = client.transactions().txStart(conc, isolation, 0, 0)) {
+        try (Transaction tx = client.transactions().txStart(conc, isolation, 0, 0)) {
             fut = rollbackAsync(tx, 200);
 
             if (write)
@@ -531,13 +548,20 @@
      * Rollback tx while near lock request is delayed.
      */
     public void testRollbackDelayNearLockRequest() throws Exception {
+        if (MvccFeatureChecker.forcedMvcc())
+            fail("https://issues.apache.org/jira/browse/IGNITE-9470");
+
         final Ignite client = startClient();
 
         final Ignite prim = primaryNode(0, CACHE_NAME);
 
         final TestRecordingCommunicationSpi spi = (TestRecordingCommunicationSpi)client.configuration().getCommunicationSpi();
 
-        spi.blockMessages(GridNearLockRequest.class, prim.name());
+        boolean mvcc = MvccFeatureChecker.forcedMvcc();
+
+        Class msgCls = mvcc ? GridNearTxEnlistRequest.class : GridNearLockRequest.class;
+
+        spi.blockMessages(msgCls, prim.name());
 
         final IgniteInternalFuture<Void> rollbackFut = runAsync(new Callable<Void>() {
             @Override public Void call() throws Exception {
@@ -549,13 +573,13 @@
             }
         }, "tx-rollback-thread");
 
-        try(final Transaction tx = client.transactions().txStart()) {
+        try (final Transaction tx = client.transactions().txStart()) {
             client.cache(CACHE_NAME).put(0, 0);
 
             fail();
         }
         catch (CacheException e) {
-            assertTrue(X.hasCause(e, TransactionRollbackException.class));
+            assertTrue(X.getFullStackTrace(e),X.hasCause(e, TransactionRollbackException.class));
         }
 
         rollbackFut.get();
@@ -608,7 +632,7 @@
             }
         }, "tx-rollback-thread");
 
-        try(final Transaction tx = client.transactions().txStart()) {
+        try (final Transaction tx = client.transactions().txStart()) {
             txRef.set(tx);
 
             client.cache(CACHE_NAME).put(0, 0);
@@ -630,6 +654,9 @@
      *
      */
     public void testMixedAsyncRollbackTypes() throws Exception {
+        if (MvccFeatureChecker.forcedMvcc())
+            fail("https://issues.apache.org/jira/browse/IGNITE-10434");
+
         final Ignite client = startClient();
 
         final AtomicBoolean stop = new AtomicBoolean();
@@ -660,6 +687,8 @@
         for (Ignite ignite : G.allGrids())
             perNodeTxs.put(ignite, new ArrayBlockingQueue<>(1000));
 
+        boolean mvcc = MvccFeatureChecker.forcedMvcc();
+
         IgniteInternalFuture<?> txFut = multithreadedAsync(() -> {
             while (!stop.get()) {
                 int nodeId = r.nextInt(GRID_CNT + 1);
@@ -667,8 +696,8 @@
                 // Choose random node to start tx on.
                 Ignite node = nodeId == GRID_CNT || nearCacheEnabled() ? client : grid(nodeId);
 
-                TransactionConcurrency conc = TC_VALS[r.nextInt(TC_VALS.length)];
-                TransactionIsolation isolation = TI_VALS[r.nextInt(TI_VALS.length)];
+                TransactionConcurrency conc = mvcc ? PESSIMISTIC : TC_VALS[r.nextInt(TC_VALS.length)];
+                TransactionIsolation isolation = mvcc ? REPEATABLE_READ :TI_VALS[r.nextInt(TI_VALS.length)];
 
                 // Timeout is necessary otherwise deadlock is possible due to randomness of lock acquisition.
                 long timeout = r.nextInt(50) + 50;
@@ -757,7 +786,7 @@
                 Transaction tx;
 
                 // Rollback all transaction
-                while((tx = nodeQ.poll()) != null) {
+                while ((tx = nodeQ.poll()) != null) {
                     rolledBack.increment();
 
                     doSleep(r.nextInt(50)); // Add random sleep to increase completed txs count.
@@ -791,7 +820,7 @@
         for (BlockingQueue<Transaction> queue : perNodeTxs.values()) {
             Transaction tx;
 
-            while((tx = queue.poll()) != null) {
+            while ((tx = queue.poll()) != null) {
                 rolledBack.increment();
 
                 rollbackClo.apply(tx);
@@ -940,12 +969,12 @@
             @Override public boolean apply(Event evt) {
                 runAsync(new Runnable() {
                     @Override public void run() {
-                        try(Transaction tx = crd.transactions().withLabel("testLbl").txStart()) {
+                        try (Transaction tx = crd.transactions().withLabel("testLbl").txStart()) {
                             // Wait for node start.
                             waitForCondition(new GridAbsPredicate() {
                                 @Override public boolean apply() {
                                     return crd.cluster().topologyVersion() != GRID_CNT +
-                                        /** client node */ 1  + /** stop server node */ 1 + /** start server node */ 1;
+                                        /** client node */1 + /** stop server node */1 + /** start server node */1;
                                 }
                             }, 10_000);
 
@@ -1021,7 +1050,6 @@
      * @param keyLocked Latch for notifying until key is locked.
      * @param waitCommit Latch for waiting until commit is allowed.
      * @param timeout Timeout.
-     *
      * @return tx completion future.
      */
     private IgniteInternalFuture<?> lockInTx(final Ignite node, final CountDownLatch keyLocked,
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxRollbackOnIncorrectParamsTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxRollbackOnIncorrectParamsTest.java
index 8aafa8b..75b7625 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxRollbackOnIncorrectParamsTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxRollbackOnIncorrectParamsTest.java
@@ -28,6 +28,7 @@
 import org.apache.ignite.lang.IgniteBiPredicate;
 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;
@@ -39,6 +40,14 @@
  * Tests transaction rollback on incorrect tx params.
  */
 public class TxRollbackOnIncorrectParamsTest extends GridCommonAbstractTest {
+    /** {@inheritDoc} */
+    @Override protected void beforeTestsStarted() throws Exception {
+        if (MvccFeatureChecker.forcedMvcc())
+            fail("https://issues.apache.org/jira/browse/IGNITE-10415");
+
+        super.beforeTestsStarted();
+    }
+
     /**
      *
      */
@@ -61,14 +70,14 @@
         IgniteCache cache = ignite.getOrCreateCache(defaultCacheConfiguration());
 
         try (Transaction tx = ignite.transactions().txStart(
-            TransactionConcurrency.OPTIMISTIC, TransactionIsolation.REPEATABLE_READ, 200, 2)) {
+            TransactionConcurrency.PESSIMISTIC, TransactionIsolation.REPEATABLE_READ, 200, 2)) {
             cache.put(1, 1);
 
             tx.commit();
         }
 
         try (Transaction tx = ignite.transactions().txStart(
-            TransactionConcurrency.OPTIMISTIC, TransactionIsolation.REPEATABLE_READ, 100, 2)) {
+            TransactionConcurrency.PESSIMISTIC, TransactionIsolation.REPEATABLE_READ, 100, 2)) {
             cache.put(1, 2);
 
             tx.commit();
@@ -216,14 +225,14 @@
             EVT_TX_STARTED);
 
         try (Transaction tx = ignite.transactions().txStart(
-            TransactionConcurrency.OPTIMISTIC, TransactionIsolation.REPEATABLE_READ, 100, 2)) {
+            TransactionConcurrency.PESSIMISTIC, TransactionIsolation.REPEATABLE_READ, 100, 2)) {
             cacheLocal.put(1, 1);
 
             tx.commit();
         }
 
         try (Transaction tx = remote.transactions().txStart(
-            TransactionConcurrency.OPTIMISTIC, TransactionIsolation.REPEATABLE_READ, 100, 2)) {
+            TransactionConcurrency.PESSIMISTIC, TransactionIsolation.REPEATABLE_READ, 100, 2)) {
             cacheRemote.put(1, 2);
 
             tx.commit();
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxRollbackOnTimeoutTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxRollbackOnTimeoutTest.java
index 61e39ff..0ae15b0 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxRollbackOnTimeoutTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxRollbackOnTimeoutTest.java
@@ -57,6 +57,7 @@
 import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
 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.apache.ignite.transactions.Transaction;
 import org.apache.ignite.transactions.TransactionConcurrency;
@@ -94,6 +95,14 @@
     private static final int GRID_CNT = 3;
 
     /** {@inheritDoc} */
+    @Override protected void beforeTestsStarted() throws Exception {
+        if (MvccFeatureChecker.forcedMvcc())
+            fail("https://issues.apache.org/jira/browse/IGNITE-7388");
+
+        super.beforeTestsStarted();
+    }
+
+    /** {@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/transactions/TxRollbackOnTopologyChangeTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxRollbackOnTopologyChangeTest.java
index 3fd6fd3..f24ea63 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxRollbackOnTopologyChangeTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxRollbackOnTopologyChangeTest.java
@@ -28,6 +28,8 @@
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.configuration.TransactionConfiguration;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.IgniteEx;
 import org.apache.ignite.internal.IgniteInternalFuture;
 import org.apache.ignite.internal.TestRecordingCommunicationSpi;
@@ -106,6 +108,11 @@
         stopAllGrids();
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * Tests rollbacks on topology change.
      */
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxStateChangeEventTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxStateChangeEventTest.java
index 01c87ae..446609f 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxStateChangeEventTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxStateChangeEventTest.java
@@ -21,10 +21,14 @@
 import org.apache.ignite.Ignite;
 import org.apache.ignite.IgniteCache;
 import org.apache.ignite.IgniteEvents;
+import org.apache.ignite.IgniteTransactions;
+import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.events.Event;
 import org.apache.ignite.events.TransactionStateChangedEvent;
+import org.apache.ignite.internal.IgniteInterruptedCheckedException;
 import org.apache.ignite.internal.util.typedef.internal.U;
 import org.apache.ignite.lang.IgnitePredicate;
+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;
@@ -67,20 +71,20 @@
      *
      */
     public void testLocal() throws Exception {
-        test(true);
+        check(true);
     }
 
     /**
      *
      */
     public void testRemote() throws Exception {
-        test(false);
+        check(false);
     }
 
     /**
      *
      */
-    private void test(boolean loc) throws Exception {
+    private void check(boolean loc) throws Exception {
         Ignite ignite = startGrids(5);
 
         final IgniteEvents evts = loc ? ignite.events() : grid(3).events();
@@ -104,27 +108,51 @@
                 },
                 EVTS_TX);
 
-        IgniteCache cache = ignite.getOrCreateCache(defaultCacheConfiguration().setBackups(2));
+        IgniteTransactions txs = ignite.transactions();
 
-        // create & commit
-        try (Transaction tx = ignite.transactions().withLabel(lb).txStart(
-            TransactionConcurrency.PESSIMISTIC, TransactionIsolation.SERIALIZABLE, timeout, 3)) {
-            cache.put(1, 1);
+        IgniteCache<Integer, Integer> cache = ignite.getOrCreateCache(getCacheConfig());
 
-            tx.commit();
+        checkCommit(txs, cache);
+
+        if (!MvccFeatureChecker.forcedMvcc())
+            checkSuspendResume(txs, cache);
+
+        checkRollback(txs, cache);
+    }
+
+    /** */
+    @SuppressWarnings("unchecked")
+    private CacheConfiguration<Integer, Integer> getCacheConfig() {
+        return defaultCacheConfiguration().setBackups(2);
+    }
+
+    /**
+     * @param txs Transaction manager.
+     * @param cache Ignite cache.
+     */
+    private void checkRollback(IgniteTransactions txs, IgniteCache<Integer, Integer> cache) {
+        // create & rollback (pessimistic)
+        try (Transaction tx = txs.withLabel(lb).txStart(
+            TransactionConcurrency.PESSIMISTIC, TransactionIsolation.REPEATABLE_READ, timeout, 3)) {
+            cache.put(4, 5);
         }
 
         assertTrue(
             creation.get() &&
-                commit.get() &&
-                !rollback.get() &&
+                !commit.get() &&
+                rollback.get() &&
                 !suspend.get() &&
                 !resume.get());
+    }
 
-        clear();
-
+    /**
+     * @param txs Transaction manager.
+     * @param cache Ignite cache.
+     */
+    private void checkSuspendResume(IgniteTransactions txs,
+        IgniteCache<Integer, Integer> cache) throws IgniteInterruptedCheckedException {
         // create & suspend & resume & commit
-        try (Transaction tx = ignite.transactions().withLabel(lb).txStart(
+        try (Transaction tx = txs.withLabel(lb).txStart(
             TransactionConcurrency.OPTIMISTIC, TransactionIsolation.SERIALIZABLE, timeout, 3)) {
             cache.put(2, 7);
 
@@ -145,19 +173,29 @@
                 resume.get());
 
         clear();
+    }
 
-        // create & rollback (pessimistic)
-        try (Transaction tx = ignite.transactions().withLabel(lb).txStart(
-            TransactionConcurrency.PESSIMISTIC, TransactionIsolation.SERIALIZABLE, timeout, 3)) {
-            cache.put(4, 5);
+    /**
+     * @param txs Transaction manager.
+     * @param cache Ignite cache.
+     */
+    private void checkCommit(IgniteTransactions txs, IgniteCache<Integer, Integer> cache) {
+        // create & commit
+        try (Transaction tx = txs.withLabel(lb).txStart(
+            TransactionConcurrency.PESSIMISTIC, TransactionIsolation.REPEATABLE_READ, timeout, 3)) {
+            cache.put(1, 1);
+
+            tx.commit();
         }
 
         assertTrue(
             creation.get() &&
-                !commit.get() &&
-                rollback.get() &&
+                commit.get() &&
+                !rollback.get() &&
                 !suspend.get() &&
                 !resume.get());
+
+        clear();
     }
 
     /**
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxWithSmallTimeoutAndContentionOneKeyTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxWithSmallTimeoutAndContentionOneKeyTest.java
index 62f4635..cac0427 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxWithSmallTimeoutAndContentionOneKeyTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxWithSmallTimeoutAndContentionOneKeyTest.java
@@ -40,6 +40,7 @@
 import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
 import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder;
 import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
+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;
@@ -112,6 +113,9 @@
      * @return Random transaction type.
      */
     protected TransactionConcurrency transactionConcurrency() {
+        if (MvccFeatureChecker.forcedMvcc())
+            return PESSIMISTIC;
+
         ThreadLocalRandom random = ThreadLocalRandom.current();
 
         return random.nextBoolean() ? OPTIMISTIC : PESSIMISTIC;
@@ -121,6 +125,9 @@
      * @return Random transaction isolation level.
      */
     protected TransactionIsolation transactionIsolation(){
+        if (MvccFeatureChecker.forcedMvcc())
+            return REPEATABLE_READ;
+
         ThreadLocalRandom random = ThreadLocalRandom.current();
 
         switch (random.nextInt(3)) {
@@ -150,6 +157,9 @@
      * @throws Exception If failed.
      */
     public void test() throws Exception {
+        if (MvccFeatureChecker.forcedMvcc())
+            fail("https://issues.apache.org/jira/browse/IGNITE-10455");
+
         startGrids(4);
 
         client = true;
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/version/CacheVersionedEntryLocalTransactionalSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/version/CacheVersionedEntryLocalTransactionalSelfTest.java
index d7fc938..b217703 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/version/CacheVersionedEntryLocalTransactionalSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/version/CacheVersionedEntryLocalTransactionalSelfTest.java
@@ -19,6 +19,7 @@
 
 import org.apache.ignite.cache.CacheAtomicityMode;
 import org.apache.ignite.cache.CacheMode;
+import org.apache.ignite.testframework.MvccFeatureChecker;
 
 /**
  *
@@ -38,4 +39,12 @@
     @Override protected CacheAtomicityMode atomicityMode() {
         return CacheAtomicityMode.TRANSACTIONAL;
     }
+
+    /** {@inheritDoc} */
+    @Override public void setUp() throws Exception {
+        MvccFeatureChecker.failIfNotSupported(MvccFeatureChecker.Feature.LOCAL_CACHE);
+
+        super.setUp();
+    }
+
 }
\ No newline at end of file
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/continuous/GridEventConsumeSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/continuous/GridEventConsumeSelfTest.java
index d2d895e..6a31abb 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/continuous/GridEventConsumeSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/continuous/GridEventConsumeSelfTest.java
@@ -38,6 +38,8 @@
 import org.apache.ignite.events.DiscoveryEvent;
 import org.apache.ignite.events.Event;
 import org.apache.ignite.events.JobEvent;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.IgniteEx;
 import org.apache.ignite.internal.IgniteInternalFuture;
 import org.apache.ignite.internal.util.GridConcurrentHashSet;
@@ -158,6 +160,11 @@
         }
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * @param proc Continuous processor.
      * @return Local event routines.
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/database/IndexStorageSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/database/IndexStorageSelfTest.java
index bbdcd38..de2161a 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/database/IndexStorageSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/database/IndexStorageSelfTest.java
@@ -96,15 +96,24 @@
                 IndexStorageImpl metaStore = storeMap.get(cacheId);
 
                 if (metaStore == null) {
-                    metaStore = new IndexStorageImpl(mem, null, new AtomicLong(), cacheId,
-                        PageIdAllocator.INDEX_PARTITION, PageMemory.FLAG_IDX,
-                        null, mem.allocatePage(cacheId, PageIdAllocator.INDEX_PARTITION, PageMemory.FLAG_IDX), true,
-                            null);
+                    metaStore = new IndexStorageImpl(
+                        mem,
+                        null,
+                        new AtomicLong(),
+                        cacheId,
+                        false,
+                        PageIdAllocator.INDEX_PARTITION,
+                        PageMemory.FLAG_IDX,
+                        null,
+                        mem.allocatePage(cacheId, PageIdAllocator.INDEX_PARTITION, PageMemory.FLAG_IDX),
+                        true,
+                        null
+                    );
 
                     storeMap.put(cacheId, metaStore);
                 }
 
-                final RootPage rootPage = metaStore.getOrAllocateForTree(idxName);
+                final RootPage rootPage = metaStore.allocateIndex(idxName);
 
                 assertTrue(rootPage.isAllocated());
 
@@ -118,7 +127,7 @@
                     String idxName = entry.getKey();
                     FullPageId rootPageId = entry.getValue().pageId();
 
-                    final RootPage rootPage = storeMap.get(cacheId).getOrAllocateForTree(idxName);
+                    final RootPage rootPage = storeMap.get(cacheId).allocateIndex(idxName);
 
                     assertEquals("Invalid root page ID restored [cacheId=" + cacheId + ", idxName=" + idxName + ']',
                         rootPageId, rootPage.pageId());
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/datastreamer/DataStreamerClientReconnectAfterClusterRestartTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/datastreamer/DataStreamerClientReconnectAfterClusterRestartTest.java
index 239647c..0c33890 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/datastreamer/DataStreamerClientReconnectAfterClusterRestartTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/datastreamer/DataStreamerClientReconnectAfterClusterRestartTest.java
@@ -24,6 +24,8 @@
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.events.Event;
 import org.apache.ignite.events.EventType;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.lang.IgnitePredicate;
 import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
 import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
@@ -52,6 +54,11 @@
         return cfg;
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /** */
     public void testOneClient() throws Exception {
         clusterRestart(false, false);
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/igfs/IgfsBackupFailoverSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/igfs/IgfsBackupFailoverSelfTest.java
index ff9c51a..5abf125 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/igfs/IgfsBackupFailoverSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/igfs/IgfsBackupFailoverSelfTest.java
@@ -26,6 +26,8 @@
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.FileSystemConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.igfs.IgfsGroupDataBlocksKeyMapper;
 import org.apache.ignite.igfs.IgfsMode;
 import org.apache.ignite.igfs.IgfsOutputStream;
@@ -120,6 +122,11 @@
         checkTopology(numIgfsNodes);
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * Start grid with IGFS.
      *
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/rest/handlers/top/CacheTopologyCommandHandlerTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/rest/handlers/top/CacheTopologyCommandHandlerTest.java
index 5d7dfd7..c318ff8 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/rest/handlers/top/CacheTopologyCommandHandlerTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/rest/handlers/top/CacheTopologyCommandHandlerTest.java
@@ -25,6 +25,8 @@
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.ConnectorConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.IgniteInternalFuture;
 import org.apache.ignite.internal.IgniteKernal;
 import org.apache.ignite.internal.processors.rest.GridRestCommand;
@@ -67,6 +69,11 @@
         stopAllGrids();
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * @throws Exception If failed.
      */
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/service/GridServiceProxyClientReconnectSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/service/GridServiceProxyClientReconnectSelfTest.java
index 5fdcdc4..b9596c4 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/service/GridServiceProxyClientReconnectSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/service/GridServiceProxyClientReconnectSelfTest.java
@@ -23,6 +23,8 @@
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.events.Event;
 import org.apache.ignite.events.EventType;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.lang.IgnitePredicate;
 import org.apache.ignite.services.Service;
 import org.apache.ignite.services.ServiceContext;
@@ -54,6 +56,11 @@
         stopAllGrids();
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * @throws Exception If failed.
      */
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/service/ServiceDeploymentOnActivationTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/service/ServiceDeploymentOnActivationTest.java
index 52d706b9..29e38d3 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/service/ServiceDeploymentOnActivationTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/service/ServiceDeploymentOnActivationTest.java
@@ -164,7 +164,7 @@
     /**
      * @throws Exception If failed.
      */
-    public void _testClientsStaticConfigWithoutPersistence() throws Exception {
+    public void testClientsStaticConfigWithoutPersistence() throws Exception {
         fail("https://issues.apache.org/jira/browse/IGNITE-8279");
 
         persistence = false;
diff --git a/modules/core/src/test/java/org/apache/ignite/session/GridSessionJobFailoverSelfTest.java b/modules/core/src/test/java/org/apache/ignite/session/GridSessionJobFailoverSelfTest.java
index 85b2e93..ef59bc6 100644
--- a/modules/core/src/test/java/org/apache/ignite/session/GridSessionJobFailoverSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/session/GridSessionJobFailoverSelfTest.java
@@ -32,6 +32,8 @@
 import org.apache.ignite.compute.ComputeTaskSession;
 import org.apache.ignite.compute.ComputeTaskSessionFullSupport;
 import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.resources.TaskSessionResource;
 import org.apache.ignite.spi.failover.always.AlwaysFailoverSpi;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
@@ -58,6 +60,11 @@
         return cfg;
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * @throws Exception If failed.
      */
diff --git a/modules/core/src/test/java/org/apache/ignite/spi/collision/jobstealing/GridJobStealingCollisionSpiCustomTopologySelfTest.java b/modules/core/src/test/java/org/apache/ignite/spi/collision/jobstealing/GridJobStealingCollisionSpiCustomTopologySelfTest.java
index 2b88dbb..b2f566b 100644
--- a/modules/core/src/test/java/org/apache/ignite/spi/collision/jobstealing/GridJobStealingCollisionSpiCustomTopologySelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/spi/collision/jobstealing/GridJobStealingCollisionSpiCustomTopologySelfTest.java
@@ -25,6 +25,8 @@
 import java.util.UUID;
 import org.apache.ignite.GridTestTaskSession;
 import org.apache.ignite.cluster.ClusterNode;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.ClusterMetricsSnapshot;
 import org.apache.ignite.internal.util.typedef.internal.U;
 import org.apache.ignite.lang.IgniteUuid;
@@ -103,6 +105,11 @@
         return ctx;
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * Adds Failover SPI attribute.
      *
diff --git a/modules/core/src/test/java/org/apache/ignite/spi/communication/tcp/TcpCommunicationSpiDropNodesTest.java b/modules/core/src/test/java/org/apache/ignite/spi/communication/tcp/TcpCommunicationSpiDropNodesTest.java
index 08cf1f7..970d666 100644
--- a/modules/core/src/test/java/org/apache/ignite/spi/communication/tcp/TcpCommunicationSpiDropNodesTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/spi/communication/tcp/TcpCommunicationSpiDropNodesTest.java
@@ -29,6 +29,8 @@
 import org.apache.ignite.cluster.ClusterNode;
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.events.Event;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.IgniteEx;
 import org.apache.ignite.internal.IgniteInternalFuture;
 import org.apache.ignite.internal.util.lang.GridAbsPredicate;
@@ -108,6 +110,11 @@
         stopAllGrids();
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * @throws Exception If failed.
      */
diff --git a/modules/core/src/test/java/org/apache/ignite/spi/communication/tcp/TcpCommunicationSpiFaultyClientTest.java b/modules/core/src/test/java/org/apache/ignite/spi/communication/tcp/TcpCommunicationSpiFaultyClientTest.java
index 505d7a5..b65f6a0 100644
--- a/modules/core/src/test/java/org/apache/ignite/spi/communication/tcp/TcpCommunicationSpiFaultyClientTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/spi/communication/tcp/TcpCommunicationSpiFaultyClientTest.java
@@ -33,6 +33,8 @@
 import org.apache.ignite.cluster.ClusterNode;
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.events.Event;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.IgniteInternalFuture;
 import org.apache.ignite.internal.IgniteInterruptedCheckedException;
 import org.apache.ignite.internal.util.lang.GridAbsPredicate;
@@ -119,6 +121,11 @@
         stopAllGrids();
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * @throws Exception If failed.
      */
diff --git a/modules/core/src/test/java/org/apache/ignite/spi/communication/tcp/TcpCommunicationSpiSkipMessageSendTest.java b/modules/core/src/test/java/org/apache/ignite/spi/communication/tcp/TcpCommunicationSpiSkipMessageSendTest.java
index 2c17f95..588e79e 100644
--- a/modules/core/src/test/java/org/apache/ignite/spi/communication/tcp/TcpCommunicationSpiSkipMessageSendTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/spi/communication/tcp/TcpCommunicationSpiSkipMessageSendTest.java
@@ -34,6 +34,8 @@
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.events.Event;
 import org.apache.ignite.events.EventType;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.util.nio.GridCommunicationClient;
 import org.apache.ignite.internal.util.typedef.internal.U;
 import org.apache.ignite.lang.IgniteCallable;
@@ -102,6 +104,11 @@
         return cfg;
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * @throws Exception If failed.
      */
diff --git a/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/IgniteClientReconnectMassiveShutdownTest.java b/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/IgniteClientReconnectMassiveShutdownTest.java
index 6bd2a45..4289d64 100644
--- a/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/IgniteClientReconnectMassiveShutdownTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/IgniteClientReconnectMassiveShutdownTest.java
@@ -34,6 +34,8 @@
 import org.apache.ignite.cluster.ClusterTopologyException;
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.IgniteInternalFuture;
 import org.apache.ignite.internal.util.typedef.X;
 import org.apache.ignite.internal.util.typedef.internal.U;
@@ -92,6 +94,11 @@
         return 5 * 60 * 1000;
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * @throws Exception If any error occurs.
      */
diff --git a/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpClientDiscoveryMarshallerCheckSelfTest.java b/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpClientDiscoveryMarshallerCheckSelfTest.java
index f14e0b1..9c22bc4 100644
--- a/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpClientDiscoveryMarshallerCheckSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpClientDiscoveryMarshallerCheckSelfTest.java
@@ -20,6 +20,8 @@
 import org.apache.ignite.IgniteCheckedException;
 import org.apache.ignite.configuration.BinaryConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.binary.BinaryMarshaller;
 import org.apache.ignite.marshaller.jdk.JdkMarshaller;
 import org.apache.ignite.spi.IgniteSpiException;
@@ -79,6 +81,11 @@
         stopAllGrids();
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * @throws Exception If failed.
      */
diff --git a/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpClientDiscoverySpiSelfTest.java b/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpClientDiscoverySpiSelfTest.java
index c85e94e..30b68bb 100644
--- a/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpClientDiscoverySpiSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpClientDiscoverySpiSelfTest.java
@@ -42,6 +42,8 @@
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.events.DiscoveryEvent;
 import org.apache.ignite.events.Event;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.IgniteEx;
 import org.apache.ignite.internal.IgniteInternalFuture;
 import org.apache.ignite.internal.IgniteKernal;
@@ -269,6 +271,11 @@
         assert G.allGrids().isEmpty();
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * Checks whether to use failure detection timeout instead of setting explicit timeouts.
      *
diff --git a/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoveryMultiThreadedTest.java b/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoveryMultiThreadedTest.java
index b0e3f85..5976f34 100644
--- a/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoveryMultiThreadedTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoveryMultiThreadedTest.java
@@ -42,6 +42,8 @@
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.events.DiscoveryEvent;
 import org.apache.ignite.events.Event;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.IgniteClientDisconnectedCheckedException;
 import org.apache.ignite.internal.IgniteInternalFuture;
 import org.apache.ignite.internal.IgniteKernal;
@@ -165,6 +167,11 @@
     }
 
     /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
+    /** {@inheritDoc} */
     @Override protected long getTestTimeout() {
         return 5 * 60 * 1000;
     }
@@ -499,7 +506,9 @@
     /**
      * @throws Exception If failed.
      */
-    public void _testCustomEventOnJoinCoordinatorStop() throws Exception {
+    public void testCustomEventOnJoinCoordinatorStop() throws Exception {
+        fail("https://issues.apache.org/jira/browse/IGNITE-10198");
+
         for (int k = 0; k < 10; k++) {
             log.info("Iteration: " + k);
 
@@ -595,7 +604,9 @@
     /**
      * @throws Exception If failed.
      */
-    public void _testClientContinuousQueryCoordinatorStop() throws Exception {
+    public void testClientContinuousQueryCoordinatorStop() throws Exception {
+        fail("https://issues.apache.org/jira/browse/IGNITE-10198");
+
         for (int k = 0; k < 10; k++) {
             log.info("Iteration: " + k);
 
@@ -664,7 +675,9 @@
     /**
      * @throws Exception If failed.
      */
-    public void _testCustomEventNodeRestart() throws Exception {
+    public void testCustomEventNodeRestart() throws Exception {
+        fail("https://issues.apache.org/jira/browse/IGNITE-10249");
+
         clientFlagGlobal = false;
 
         Ignite ignite = startGrid(0);
diff --git a/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoveryNodeAttributesUpdateOnReconnectTest.java b/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoveryNodeAttributesUpdateOnReconnectTest.java
index 56dc4ec..241bc11 100644
--- a/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoveryNodeAttributesUpdateOnReconnectTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoveryNodeAttributesUpdateOnReconnectTest.java
@@ -27,6 +27,8 @@
 import org.apache.ignite.events.DiscoveryEvent;
 import org.apache.ignite.events.Event;
 import org.apache.ignite.events.EventType;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.IgniteClientReconnectAbstractTest;
 import org.apache.ignite.lang.IgnitePredicate;
 import org.apache.ignite.resources.LoggerResource;
@@ -82,6 +84,11 @@
         TestReconnectPluginProvider.enabled = true;
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * @throws Exception If failed.
      */
diff --git a/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoverySelfTest.java b/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoverySelfTest.java
index 32df795..1ff1a8d 100644
--- a/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoverySelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoverySelfTest.java
@@ -50,6 +50,8 @@
 import org.apache.ignite.events.DiscoveryEvent;
 import org.apache.ignite.events.Event;
 import org.apache.ignite.events.EventType;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.GridComponent;
 import org.apache.ignite.internal.IgniteEx;
 import org.apache.ignite.internal.IgniteInternalFuture;
@@ -242,6 +244,11 @@
         super.afterTest();
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * @throws Exception If any error occurs.
      */
diff --git a/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoverySpiFailureTimeoutSelfTest.java b/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoverySpiFailureTimeoutSelfTest.java
index a760e2e..02eb857 100644
--- a/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoverySpiFailureTimeoutSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoverySpiFailureTimeoutSelfTest.java
@@ -24,6 +24,8 @@
 import org.apache.ignite.IgniteCheckedException;
 import org.apache.ignite.cluster.ClusterNode;
 import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.spi.IgniteSpiOperationTimeoutException;
 import org.apache.ignite.spi.IgniteSpiOperationTimeoutHelper;
 import org.apache.ignite.spi.discovery.AbstractDiscoverySelfTest;
@@ -81,6 +83,11 @@
         return spi;
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * @throws Exception In case of error.
      */
diff --git a/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoverySpiReconnectDelayTest.java b/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoverySpiReconnectDelayTest.java
index 89df32c..68aa431 100644
--- a/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoverySpiReconnectDelayTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoverySpiReconnectDelayTest.java
@@ -29,6 +29,8 @@
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.events.DiscoveryEvent;
 import org.apache.ignite.events.Event;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.util.typedef.G;
 import org.apache.ignite.lang.IgniteBiPredicate;
 import org.apache.ignite.lang.IgnitePredicate;
@@ -58,6 +60,11 @@
         System.setProperty(IgniteSystemProperties.IGNITE_QUIET, "false");
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     //region Client joins after failNode()
 
     /** */
diff --git a/modules/core/src/test/java/org/apache/ignite/spi/loadbalancing/roundrobin/GridRoundRobinLoadBalancingSpiTopologyChangeSelfTest.java b/modules/core/src/test/java/org/apache/ignite/spi/loadbalancing/roundrobin/GridRoundRobinLoadBalancingSpiTopologyChangeSelfTest.java
index 3159e04..edaa0cf 100644
--- a/modules/core/src/test/java/org/apache/ignite/spi/loadbalancing/roundrobin/GridRoundRobinLoadBalancingSpiTopologyChangeSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/spi/loadbalancing/roundrobin/GridRoundRobinLoadBalancingSpiTopologyChangeSelfTest.java
@@ -23,6 +23,8 @@
 import org.apache.ignite.GridTestTaskSession;
 import org.apache.ignite.cluster.ClusterNode;
 import org.apache.ignite.compute.ComputeTaskSession;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.lang.IgniteUuid;
 import org.apache.ignite.testframework.GridSpiTestContext;
 import org.apache.ignite.testframework.GridTestNode;
@@ -54,6 +56,11 @@
         return spiCtx;
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * @throws Exception If failed.
      */
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 ee9b02a..c70d447 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
@@ -19,10 +19,15 @@
 
 import org.apache.ignite.IgniteSystemProperties;
 import org.apache.ignite.cache.CacheMode;
+import org.apache.ignite.internal.processors.query.IgniteSQLException;
+import org.apache.ignite.internal.util.typedef.X;
 import org.apache.ignite.transactions.TransactionConcurrency;
 import org.apache.ignite.transactions.TransactionIsolation;
 
 import static org.apache.ignite.IgniteSystemProperties.IGNITE_FORCE_MVCC_MODE_IN_TESTS;
+import static org.apache.ignite.internal.processors.cache.query.IgniteQueryErrorCode.TRANSACTION_SERIALIZATION_ERROR;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.fail;
 
 /**
@@ -41,7 +46,9 @@
         ENTRY_LOCK,
         CACHE_EVENTS,
         EVICTION,
-        EXPIRATION
+        EXPIRATION,
+        METRICS,
+        INTERCEPTOR
     }
 
     /**
@@ -105,11 +112,26 @@
     }
 
     /**
+     * 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.
+     */
+    public static void assertMvccWriteConflict(Exception e) {
+        IgniteSQLException sqlEx = X.cause(e, IgniteSQLException.class);
+
+        assertNotNull(sqlEx);
+
+        assertEquals(TRANSACTION_SERIALIZATION_ERROR, sqlEx.statusCode());
+    }
+
+    /**
      * Fails if feature is not supported in Mvcc mode.
      *
      * @param feature Mvcc feature.
      * @throws AssertionError If failed.
      */
+    @SuppressWarnings("fallthrough")
     private static void validateFeature(Feature feature) {
         switch (feature) {
             case NEAR_CACHE:
@@ -132,6 +154,12 @@
 
             case EXPIRATION:
                 fail("https://issues.apache.org/jira/browse/IGNITE-7311");
+
+            case METRICS:
+                fail("https://issues.apache.org/jira/browse/IGNITE-9224");
+
+            case INTERCEPTOR:
+                fail("https://issues.apache.org/jira/browse/IGNITE-9323");
         }
     }
 }
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 b2d12fd..1db255c 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
@@ -62,7 +62,6 @@
 import org.apache.ignite.configuration.NearCacheConfiguration;
 import org.apache.ignite.events.EventType;
 import org.apache.ignite.failure.FailureHandler;
-import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.GridKernalContext;
 import org.apache.ignite.internal.IgniteEx;
 import org.apache.ignite.internal.IgniteInternalFuture;
@@ -172,6 +171,9 @@
     /** */
     protected static final String DEFAULT_CACHE_NAME = "default";
 
+    /** Show that test is currently running. */
+    public static volatile boolean testIsRunning = false;
+
     /** Supports obtaining test name for JUnit4 cases. */
     @Rule public transient TestName nameRule = new TestName();
 
@@ -1736,7 +1738,7 @@
      * @return Failure handler implementation.
      */
     protected FailureHandler getFailureHandler(String igniteInstanceName) {
-        return new NoOpFailureHandler();
+        return new TestFailingFailureHandler();
     }
 
     /**
@@ -2112,6 +2114,8 @@
 
         Thread runner = new IgniteThread(getTestIgniteInstanceName(), "test-runner", new Runnable() {
             @Override public void run() {
+                testIsRunning = true;
+
                 try {
                     if (forceFailure)
                         fail("Forced failure: " + forceFailureMsg);
@@ -2122,6 +2126,8 @@
                     IgniteClosure<Throwable, Throwable> hnd = errorHandler();
 
                     ex.set(hnd != null ? hnd.apply(e) : e);
+                } finally {
+                    testIsRunning = false;
                 }
             }
         });
diff --git a/modules/core/src/test/java/org/apache/ignite/testframework/junits/TestFailingFailureHandler.java b/modules/core/src/test/java/org/apache/ignite/testframework/junits/TestFailingFailureHandler.java
new file mode 100644
index 0000000..5034225
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/testframework/junits/TestFailingFailureHandler.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.testframework.junits;
+
+import junit.framework.TestCase;
+import org.apache.ignite.Ignite;
+import org.apache.ignite.failure.FailureContext;
+import org.apache.ignite.failure.StopNodeFailureHandler;
+import org.apache.ignite.internal.util.typedef.internal.S;
+
+
+/**
+ * Stops node and fails test.
+ */
+public class TestFailingFailureHandler extends StopNodeFailureHandler {
+    /** {@inheritDoc} */
+    @Override public boolean handle(Ignite ignite, FailureContext failureCtx) {
+        if (!GridAbstractTest.testIsRunning) {
+            ignite.log().info("Critical issue detected after test finished. Test failure handler ignore it.");
+
+            return true;
+        }
+
+        boolean nodeStopped = super.handle(ignite, failureCtx);
+
+        TestCase.fail(failureCtx.toString());
+
+        return nodeStopped;
+    }
+
+    /** {@inheritDoc} */
+    @Override public String toString() {
+        return S.toString(TestFailingFailureHandler.class, this);
+    }
+}
diff --git a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBasicWithPersistenceTestSuite.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBasicWithPersistenceTestSuite.java
index 68085db..36f77cc 100644
--- a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBasicWithPersistenceTestSuite.java
+++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBasicWithPersistenceTestSuite.java
@@ -34,6 +34,7 @@
 import org.apache.ignite.internal.processors.service.ServiceDeploymentOnActivationTest;
 import org.apache.ignite.internal.processors.service.ServiceDeploymentOutsideBaselineTest;
 import org.apache.ignite.marshaller.GridMarshallerMappingConsistencyTest;
+import org.apache.ignite.util.GridCommandHandlerSslTest;
 import org.apache.ignite.util.GridCommandHandlerTest;
 import org.apache.ignite.util.GridInternalTaskUnusedWalSegmentsTest;
 import org.jetbrains.annotations.Nullable;
@@ -67,6 +68,7 @@
         suite.addTestSuite(FailureHandlingConfigurationTest.class);
 
         suite.addTestSuite(GridCommandHandlerTest.class);
+        suite.addTestSuite(GridCommandHandlerSslTest.class);
         suite.addTestSuite(GridInternalTaskUnusedWalSegmentsTest.class);
 
         suite.addTestSuite(GridNodeMetricsLogPdsSelfTest.class);
diff --git a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBinaryObjectsCacheTestSuite3.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBinaryObjectsCacheTestSuite3.java
index 0007813..8ab7c2c 100644
--- a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBinaryObjectsCacheTestSuite3.java
+++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBinaryObjectsCacheTestSuite3.java
@@ -17,9 +17,11 @@
 
 package org.apache.ignite.testsuites;
 
+import java.util.Collection;
 import junit.framework.TestSuite;
 import org.apache.ignite.internal.processors.cache.binary.GridCacheBinaryAtomicEntryProcessorDeploymentSelfTest;
 import org.apache.ignite.internal.processors.cache.binary.GridCacheBinaryTransactionalEntryProcessorDeploymentSelfTest;
+import org.apache.ignite.testframework.GridTestUtils;
 import org.apache.ignite.testframework.config.GridTestProperties;
 
 /**
@@ -43,14 +45,22 @@
      * @return Test suite.
      * @throws Exception If failed.
      */
-    public static TestSuite suite() throws Exception {
+    public static TestSuite suite()  {
+        return suite(null);
+    }
+
+    /**
+     * @param ignoredTests Ignored tests.
+     * @return IgniteCache test suite.
+     */
+    public static TestSuite suite(Collection<Class> ignoredTests) {
         GridTestProperties.setProperty(GridTestProperties.ENTRY_PROCESSOR_CLASS_NAME,
             "org.apache.ignite.tests.p2p.CacheDeploymentBinaryEntryProcessor");
 
-        TestSuite suite = IgniteCacheTestSuite3.suite();
+        TestSuite suite = IgniteCacheTestSuite3.suite(ignoredTests);
 
-        suite.addTestSuite(GridCacheBinaryAtomicEntryProcessorDeploymentSelfTest.class);
-        suite.addTestSuite(GridCacheBinaryTransactionalEntryProcessorDeploymentSelfTest.class);
+        GridTestUtils.addTestIfNeeded(suite,GridCacheBinaryAtomicEntryProcessorDeploymentSelfTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite,GridCacheBinaryTransactionalEntryProcessorDeploymentSelfTest.class, ignoredTests);
 
         return suite;
     }
diff --git a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheMvccTestSuite2.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheMvccTestSuite2.java
index e0d1eef..3c070bc 100644
--- a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheMvccTestSuite2.java
+++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheMvccTestSuite2.java
@@ -110,7 +110,7 @@
         ignoredTests.add(NearCacheSyncUpdateTest.class);
         ignoredTests.add(GridCacheNearMultiGetSelfTest.class);
 
-        // Optimistic tx tests.
+        // Irrelevant Tx tests.
         ignoredTests.add(GridCacheColocatedOptimisticTransactionSelfTest.class);
         ignoredTests.add(CacheOptimisticTransactionsWithFilterSingleServerTest.class);
         ignoredTests.add(CacheOptimisticTransactionsWithFilterTest.class);
diff --git a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheMvccTestSuite3.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheMvccTestSuite3.java
new file mode 100644
index 0000000..55dddbe
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheMvccTestSuite3.java
@@ -0,0 +1,133 @@
+/*
+ * 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 java.util.HashSet;
+import junit.framework.TestSuite;
+import org.apache.ignite.IgniteSystemProperties;
+import org.apache.ignite.internal.processors.cache.CacheInterceptorPartitionCounterLocalSanityTest;
+import org.apache.ignite.internal.processors.cache.CacheInterceptorPartitionCounterRandomOperationsTest;
+import org.apache.ignite.internal.processors.cache.GridCacheAtomicEntryProcessorDeploymentSelfTest;
+import org.apache.ignite.internal.processors.cache.GridCacheEntryVersionSelfTest;
+import org.apache.ignite.internal.processors.cache.GridCacheInterceptorAtomicNearEnabledSelfTest;
+import org.apache.ignite.internal.processors.cache.GridCacheInterceptorAtomicRebalanceTest;
+import org.apache.ignite.internal.processors.cache.GridCacheInterceptorAtomicReplicatedSelfTest;
+import org.apache.ignite.internal.processors.cache.GridCacheInterceptorAtomicSelfTest;
+import org.apache.ignite.internal.processors.cache.GridCacheInterceptorAtomicWithStoreReplicatedSelfTest;
+import org.apache.ignite.internal.processors.cache.GridCacheInterceptorAtomicWithStoreSelfTest;
+import org.apache.ignite.internal.processors.cache.GridCacheInterceptorLocalAtomicSelfTest;
+import org.apache.ignite.internal.processors.cache.GridCacheInterceptorLocalAtomicWithStoreSelfTest;
+import org.apache.ignite.internal.processors.cache.GridCacheValueBytesPreloadingSelfTest;
+import org.apache.ignite.internal.processors.cache.GridCacheVersionSelfTest;
+import org.apache.ignite.internal.processors.cache.GridCacheVersionTopologyChangeTest;
+import org.apache.ignite.internal.processors.cache.IgniteCacheGroupsTest;
+import org.apache.ignite.internal.processors.cache.binary.GridCacheBinaryAtomicEntryProcessorDeploymentSelfTest;
+import org.apache.ignite.internal.processors.cache.distributed.CacheAsyncOperationsTest;
+import org.apache.ignite.internal.processors.cache.distributed.GridCacheMixedModeSelfTest;
+import org.apache.ignite.internal.processors.cache.distributed.dht.GridCacheClientOnlySelfTest;
+import org.apache.ignite.internal.processors.cache.distributed.dht.IgniteTxReentryColocatedSelfTest;
+import org.apache.ignite.internal.processors.cache.distributed.dht.atomic.GridCacheValueConsistencyAtomicNearEnabledSelfTest;
+import org.apache.ignite.internal.processors.cache.distributed.dht.atomic.GridCacheValueConsistencyAtomicSelfTest;
+import org.apache.ignite.internal.processors.cache.distributed.near.GridCacheNearOnlySelfTest;
+import org.apache.ignite.internal.processors.cache.distributed.near.IgniteTxReentryNearSelfTest;
+import org.apache.ignite.internal.processors.cache.distributed.replicated.GridCacheReplicatedAtomicGetAndTransformStoreSelfTest;
+import org.apache.ignite.internal.processors.cache.distributed.replicated.GridCacheReplicatedMvccTxMultiThreadedSelfTest;
+import org.apache.ignite.internal.processors.cache.distributed.replicated.GridCacheReplicatedMvccTxSingleThreadedSelfTest;
+import org.apache.ignite.internal.processors.cache.distributed.replicated.GridCacheReplicatedMvccTxTimeoutSelfTest;
+import org.apache.ignite.internal.processors.cache.distributed.replicated.GridCacheReplicatedTxMultiThreadedSelfTest;
+import org.apache.ignite.internal.processors.cache.distributed.replicated.GridCacheReplicatedTxSingleThreadedSelfTest;
+import org.apache.ignite.internal.processors.cache.distributed.replicated.GridCacheReplicatedTxTimeoutSelfTest;
+import org.apache.ignite.internal.processors.cache.store.GridCacheWriteBehindStoreMultithreadedSelfTest;
+import org.apache.ignite.internal.processors.cache.store.GridCacheWriteBehindStoreSelfTest;
+import org.apache.ignite.internal.processors.cache.store.IgnteCacheClientWriteBehindStoreAtomicTest;
+import org.apache.ignite.internal.processors.cache.store.IgnteCacheClientWriteBehindStoreNonCoalescingTest;
+
+/**
+ * Test suite.
+ */
+public class IgniteCacheMvccTestSuite3 extends TestSuite {
+    /**
+     * @return IgniteCache test suite.
+     */
+    public static TestSuite suite() {
+        System.setProperty(IgniteSystemProperties.IGNITE_FORCE_MVCC_MODE_IN_TESTS, "true");
+
+        HashSet<Class> ignoredTests = new HashSet<>();
+
+        // Skip classes that already contains Mvcc tests
+        ignoredTests.add(GridCacheEntryVersionSelfTest.class);
+        ignoredTests.add(GridCacheVersionTopologyChangeTest.class);
+        ignoredTests.add(CacheAsyncOperationsTest.class);
+        ignoredTests.add(CacheInterceptorPartitionCounterLocalSanityTest.class);
+        ignoredTests.add(CacheInterceptorPartitionCounterRandomOperationsTest.class);
+        ignoredTests.add(IgniteCacheGroupsTest.class);
+
+        // Atomic caches
+        ignoredTests.add(GridCacheValueConsistencyAtomicSelfTest.class);
+        ignoredTests.add(GridCacheValueConsistencyAtomicNearEnabledSelfTest.class);
+        ignoredTests.add(GridCacheReplicatedAtomicGetAndTransformStoreSelfTest.class);
+        ignoredTests.add(GridCacheAtomicEntryProcessorDeploymentSelfTest.class);
+        ignoredTests.add(GridCacheValueBytesPreloadingSelfTest.class);
+        ignoredTests.add(GridCacheBinaryAtomicEntryProcessorDeploymentSelfTest.class);
+
+        ignoredTests.add(GridCacheClientOnlySelfTest.CasePartitionedAtomic.class);
+        ignoredTests.add(GridCacheClientOnlySelfTest.CaseReplicatedAtomic.class);
+        ignoredTests.add(GridCacheNearOnlySelfTest.CasePartitionedAtomic.class);
+        ignoredTests.add(GridCacheNearOnlySelfTest.CaseReplicatedAtomic.class);
+
+        ignoredTests.add(IgnteCacheClientWriteBehindStoreAtomicTest.class);
+        ignoredTests.add(IgnteCacheClientWriteBehindStoreNonCoalescingTest.class);
+
+        ignoredTests.add(GridCacheInterceptorLocalAtomicSelfTest.class);
+        ignoredTests.add(GridCacheInterceptorLocalAtomicWithStoreSelfTest.class);
+        ignoredTests.add(GridCacheInterceptorAtomicSelfTest.class);
+        ignoredTests.add(GridCacheInterceptorAtomicNearEnabledSelfTest.class);
+        ignoredTests.add(GridCacheInterceptorAtomicWithStoreSelfTest.class);
+        ignoredTests.add(GridCacheInterceptorAtomicReplicatedSelfTest.class);
+        ignoredTests.add(GridCacheInterceptorAtomicWithStoreReplicatedSelfTest.class);
+        ignoredTests.add(GridCacheInterceptorAtomicRebalanceTest.class);
+
+        // Irrelevant tx tests
+        ignoredTests.add(IgniteTxReentryNearSelfTest.class);
+        ignoredTests.add(IgniteTxReentryColocatedSelfTest.class);
+
+        // Other non-tx tests
+        ignoredTests.add(GridCacheWriteBehindStoreSelfTest.class);
+        ignoredTests.add(GridCacheWriteBehindStoreMultithreadedSelfTest.class);
+
+        ignoredTests.add(GridCacheVersionSelfTest.class);
+        ignoredTests.add(GridCacheMixedModeSelfTest.class);
+
+        // Skip classes which Mvcc implementations are added in this method below.
+        // TODO IGNITE-10175: refactor these tests (use assume) to support both mvcc and non-mvcc modes after moving to JUnit4/5.
+        ignoredTests.add(GridCacheReplicatedTxSingleThreadedSelfTest.class); // See GridCacheReplicatedMvccTxSingleThreadedSelfTest
+        ignoredTests.add(GridCacheReplicatedTxMultiThreadedSelfTest.class); // See GridCacheReplicatedMvccTxMultiThreadedSelfTest
+        ignoredTests.add(GridCacheReplicatedTxTimeoutSelfTest.class); // See GridCacheReplicatedMvccTxTimeoutSelfTest
+
+        TestSuite suite = new TestSuite("IgniteCache Mvcc Test Suite part 3");
+
+        suite.addTest(IgniteBinaryObjectsCacheTestSuite3.suite(ignoredTests));
+
+        // Add Mvcc clones.
+        suite.addTestSuite(GridCacheReplicatedMvccTxSingleThreadedSelfTest.class);
+        suite.addTestSuite(GridCacheReplicatedMvccTxMultiThreadedSelfTest.class);
+        suite.addTestSuite(GridCacheReplicatedMvccTxTimeoutSelfTest.class);
+
+        return suite;
+    }
+}
diff --git a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheMvccTestSuite4.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheMvccTestSuite4.java
new file mode 100644
index 0000000..9933633
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheMvccTestSuite4.java
@@ -0,0 +1,197 @@
+/*
+ * 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 java.util.HashSet;
+import junit.framework.TestSuite;
+import org.apache.ignite.IgniteSystemProperties;
+import org.apache.ignite.cache.store.CacheStoreListenerRWThroughDisabledAtomicCacheTest;
+import org.apache.ignite.internal.processors.cache.CacheConnectionLeakStoreTxTest;
+import org.apache.ignite.internal.processors.cache.CacheGetEntryOptimisticReadCommittedSelfTest;
+import org.apache.ignite.internal.processors.cache.CacheGetEntryOptimisticRepeatableReadSelfTest;
+import org.apache.ignite.internal.processors.cache.CacheGetEntryOptimisticSerializableSelfTest;
+import org.apache.ignite.internal.processors.cache.CacheGetEntryPessimisticReadCommittedSelfTest;
+import org.apache.ignite.internal.processors.cache.CacheGetEntryPessimisticRepeatableReadSelfTest;
+import org.apache.ignite.internal.processors.cache.CacheGetEntryPessimisticSerializableSelfTest;
+import org.apache.ignite.internal.processors.cache.CacheOffheapMapEntrySelfTest;
+import org.apache.ignite.internal.processors.cache.CacheReadThroughAtomicRestartSelfTest;
+import org.apache.ignite.internal.processors.cache.CacheReadThroughLocalAtomicRestartSelfTest;
+import org.apache.ignite.internal.processors.cache.CacheReadThroughReplicatedAtomicRestartSelfTest;
+import org.apache.ignite.internal.processors.cache.CacheStoreUsageMultinodeDynamicStartAtomicTest;
+import org.apache.ignite.internal.processors.cache.CacheStoreUsageMultinodeStaticStartAtomicTest;
+import org.apache.ignite.internal.processors.cache.CacheTxNotAllowReadFromBackupTest;
+import org.apache.ignite.internal.processors.cache.GridCacheMultinodeUpdateAtomicNearEnabledSelfTest;
+import org.apache.ignite.internal.processors.cache.GridCacheMultinodeUpdateAtomicSelfTest;
+import org.apache.ignite.internal.processors.cache.GridCacheVersionMultinodeTest;
+import org.apache.ignite.internal.processors.cache.IgniteCacheAtomicCopyOnReadDisabledTest;
+import org.apache.ignite.internal.processors.cache.IgniteCacheAtomicLocalPeekModesTest;
+import org.apache.ignite.internal.processors.cache.IgniteCacheAtomicLocalStoreValueTest;
+import org.apache.ignite.internal.processors.cache.IgniteCacheAtomicNearEnabledStoreValueTest;
+import org.apache.ignite.internal.processors.cache.IgniteCacheAtomicNearPeekModesTest;
+import org.apache.ignite.internal.processors.cache.IgniteCacheAtomicPeekModesTest;
+import org.apache.ignite.internal.processors.cache.IgniteCacheAtomicReplicatedPeekModesTest;
+import org.apache.ignite.internal.processors.cache.IgniteCacheAtomicStoreValueTest;
+import org.apache.ignite.internal.processors.cache.IgniteCacheConfigurationDefaultTemplateTest;
+import org.apache.ignite.internal.processors.cache.IgniteCacheContainsKeyAtomicTest;
+import org.apache.ignite.internal.processors.cache.IgniteCacheInvokeReadThroughSingleNodeTest;
+import org.apache.ignite.internal.processors.cache.IgniteCacheInvokeReadThroughTest;
+import org.apache.ignite.internal.processors.cache.IgniteCacheStartTest;
+import org.apache.ignite.internal.processors.cache.IgniteClientCacheInitializationFailTest;
+import org.apache.ignite.internal.processors.cache.IgniteDynamicCacheStartNoExchangeTimeoutTest;
+import org.apache.ignite.internal.processors.cache.IgniteDynamicCacheStartSelfTest;
+import org.apache.ignite.internal.processors.cache.IgniteDynamicCacheStartStopConcurrentTest;
+import org.apache.ignite.internal.processors.cache.IgniteDynamicClientCacheStartSelfTest;
+import org.apache.ignite.internal.processors.cache.IgniteExchangeFutureHistoryTest;
+import org.apache.ignite.internal.processors.cache.IgniteInternalCacheTypesTest;
+import org.apache.ignite.internal.processors.cache.IgniteStartCacheInTransactionAtomicSelfTest;
+import org.apache.ignite.internal.processors.cache.IgniteSystemCacheOnClientTest;
+import org.apache.ignite.internal.processors.cache.MarshallerCacheJobRunNodeRestartTest;
+import org.apache.ignite.internal.processors.cache.distributed.CacheDiscoveryDataConcurrentJoinTest;
+import org.apache.ignite.internal.processors.cache.distributed.CacheGetFutureHangsSelfTest;
+import org.apache.ignite.internal.processors.cache.distributed.CacheGroupsPreloadTest;
+import org.apache.ignite.internal.processors.cache.distributed.CacheNoValueClassOnServerNodeTest;
+import org.apache.ignite.internal.processors.cache.distributed.CacheResultIsNotNullOnPartitionLossTest;
+import org.apache.ignite.internal.processors.cache.distributed.IgniteCacheCreatePutTest;
+import org.apache.ignite.internal.processors.cache.distributed.IgniteCacheFailedUpdateResponseTest;
+import org.apache.ignite.internal.processors.cache.distributed.IgniteCacheReadFromBackupTest;
+import org.apache.ignite.internal.processors.cache.distributed.IgniteCacheSingleGetMessageTest;
+import org.apache.ignite.internal.processors.cache.distributed.dht.IgniteCrossCacheMvccTxSelfTest;
+import org.apache.ignite.internal.processors.cache.distributed.dht.IgniteCrossCacheTxSelfTest;
+import org.apache.ignite.internal.processors.cache.integration.IgniteCacheAtomicLoadAllTest;
+import org.apache.ignite.internal.processors.cache.integration.IgniteCacheAtomicLoaderWriterTest;
+import org.apache.ignite.internal.processors.cache.integration.IgniteCacheAtomicLocalLoadAllTest;
+import org.apache.ignite.internal.processors.cache.integration.IgniteCacheAtomicLocalNoLoadPreviousValueTest;
+import org.apache.ignite.internal.processors.cache.integration.IgniteCacheAtomicLocalNoReadThroughTest;
+import org.apache.ignite.internal.processors.cache.integration.IgniteCacheAtomicLocalNoWriteThroughTest;
+import org.apache.ignite.internal.processors.cache.integration.IgniteCacheAtomicNearEnabledNoLoadPreviousValueTest;
+import org.apache.ignite.internal.processors.cache.integration.IgniteCacheAtomicNearEnabledNoReadThroughTest;
+import org.apache.ignite.internal.processors.cache.integration.IgniteCacheAtomicNearEnabledNoWriteThroughTest;
+import org.apache.ignite.internal.processors.cache.integration.IgniteCacheAtomicNoLoadPreviousValueTest;
+import org.apache.ignite.internal.processors.cache.integration.IgniteCacheAtomicNoReadThroughTest;
+import org.apache.ignite.internal.processors.cache.integration.IgniteCacheAtomicNoWriteThroughTest;
+import org.apache.ignite.internal.processors.cache.integration.IgniteCacheAtomicStoreSessionTest;
+import org.apache.ignite.internal.processors.cache.integration.IgniteCacheAtomicStoreSessionWriteBehindTest;
+import org.apache.ignite.internal.processors.cache.integration.IgniteCacheJdbcBlobStoreNodeRestartTest;
+import org.apache.ignite.internal.processors.cache.version.CacheVersionedEntryLocalAtomicSwapDisabledSelfTest;
+import org.apache.ignite.internal.processors.cache.version.CacheVersionedEntryPartitionedAtomicSelfTest;
+import org.apache.ignite.internal.processors.cache.version.CacheVersionedEntryReplicatedAtomicSelfTest;
+
+/**
+ *
+ */
+public class IgniteCacheMvccTestSuite4 extends TestSuite {
+    /**
+     * @return IgniteCache test suite.
+     */
+    public static TestSuite suite() {
+        System.setProperty(IgniteSystemProperties.IGNITE_FORCE_MVCC_MODE_IN_TESTS, "true");
+
+        HashSet<Class> ignoredTests = new HashSet<>(128);
+
+        // Skip classes that already contains Mvcc tests
+        ignoredTests.add(GridCacheVersionMultinodeTest.class);
+        ignoredTests.add(IgniteCacheCreatePutTest.class);
+        ignoredTests.add(IgniteClientCacheInitializationFailTest.class);
+        ignoredTests.add(IgniteCacheFailedUpdateResponseTest.class);
+        ignoredTests.add(CacheGetEntryPessimisticRepeatableReadSelfTest.class);
+        ignoredTests.add(CacheTxNotAllowReadFromBackupTest.class);
+        ignoredTests.add(CacheOffheapMapEntrySelfTest.class);
+        ignoredTests.add(CacheGroupsPreloadTest.class);
+        ignoredTests.add(CacheConnectionLeakStoreTxTest.class);
+        ignoredTests.add(IgniteCacheInvokeReadThroughTest.class);
+        ignoredTests.add(IgniteCacheInvokeReadThroughSingleNodeTest.class);
+        ignoredTests.add(IgniteDynamicCacheStartSelfTest.class);
+        ignoredTests.add(IgniteDynamicClientCacheStartSelfTest.class);
+        ignoredTests.add(IgniteDynamicCacheStartNoExchangeTimeoutTest.class);
+        ignoredTests.add(IgniteCacheSingleGetMessageTest.class);
+        ignoredTests.add(IgniteCacheReadFromBackupTest.class);
+
+        // Optimistic tx tests.
+        ignoredTests.add(CacheGetEntryOptimisticReadCommittedSelfTest.class);
+        ignoredTests.add(CacheGetEntryOptimisticRepeatableReadSelfTest.class);
+        ignoredTests.add(CacheGetEntryOptimisticSerializableSelfTest.class);
+
+        // Irrelevant Tx tests.
+        ignoredTests.add(CacheGetEntryPessimisticReadCommittedSelfTest.class);
+        ignoredTests.add(CacheGetEntryPessimisticSerializableSelfTest.class);
+
+        // Atomic cache tests.
+        ignoredTests.add(GridCacheMultinodeUpdateAtomicSelfTest.class);
+        ignoredTests.add(GridCacheMultinodeUpdateAtomicNearEnabledSelfTest.class);
+        ignoredTests.add(IgniteCacheAtomicLoadAllTest.class);
+        ignoredTests.add(IgniteCacheAtomicLocalLoadAllTest.class);
+        ignoredTests.add(IgniteCacheAtomicLoaderWriterTest.class);
+        ignoredTests.add(IgniteCacheAtomicStoreSessionTest.class);
+        ignoredTests.add(IgniteCacheAtomicStoreSessionWriteBehindTest.class);
+        ignoredTests.add(IgniteCacheAtomicNoReadThroughTest.class);
+        ignoredTests.add(IgniteCacheAtomicNearEnabledNoReadThroughTest.class);
+        ignoredTests.add(IgniteCacheAtomicLocalNoReadThroughTest.class);
+        ignoredTests.add(IgniteCacheAtomicNoLoadPreviousValueTest.class);
+        ignoredTests.add(IgniteCacheAtomicNearEnabledNoLoadPreviousValueTest.class);
+        ignoredTests.add(IgniteCacheAtomicLocalNoLoadPreviousValueTest.class);
+        ignoredTests.add(IgniteCacheAtomicNoWriteThroughTest.class);
+        ignoredTests.add(IgniteCacheAtomicNearEnabledNoWriteThroughTest.class);
+        ignoredTests.add(IgniteCacheAtomicLocalNoWriteThroughTest.class);
+        ignoredTests.add(IgniteCacheAtomicPeekModesTest.class);
+        ignoredTests.add(IgniteCacheAtomicNearPeekModesTest.class);
+        ignoredTests.add(IgniteCacheAtomicReplicatedPeekModesTest.class);
+        ignoredTests.add(IgniteCacheAtomicLocalPeekModesTest.class);
+        ignoredTests.add(IgniteCacheAtomicCopyOnReadDisabledTest.class);
+        ignoredTests.add(IgniteCacheAtomicLocalStoreValueTest.class);
+        ignoredTests.add(IgniteCacheAtomicStoreValueTest.class);
+        ignoredTests.add(IgniteCacheAtomicNearEnabledStoreValueTest.class);
+        ignoredTests.add(CacheStoreListenerRWThroughDisabledAtomicCacheTest.class);
+        ignoredTests.add(CacheStoreUsageMultinodeStaticStartAtomicTest.class);
+        ignoredTests.add(CacheStoreUsageMultinodeDynamicStartAtomicTest.class);
+        ignoredTests.add(IgniteStartCacheInTransactionAtomicSelfTest.class);
+        ignoredTests.add(CacheReadThroughReplicatedAtomicRestartSelfTest.class);
+        ignoredTests.add(CacheReadThroughLocalAtomicRestartSelfTest.class);
+        ignoredTests.add(CacheReadThroughAtomicRestartSelfTest.class);
+        ignoredTests.add(CacheVersionedEntryLocalAtomicSwapDisabledSelfTest.class);
+        ignoredTests.add(CacheVersionedEntryPartitionedAtomicSelfTest.class);
+        ignoredTests.add(CacheGetFutureHangsSelfTest.class);
+        ignoredTests.add(IgniteCacheContainsKeyAtomicTest.class);
+        ignoredTests.add(CacheVersionedEntryReplicatedAtomicSelfTest.class);
+        ignoredTests.add(CacheResultIsNotNullOnPartitionLossTest.class);
+
+        // Other non-tx tests.
+        ignoredTests.add(IgniteDynamicCacheStartStopConcurrentTest.class);
+        ignoredTests.add(IgniteCacheConfigurationDefaultTemplateTest.class);
+        ignoredTests.add(IgniteCacheStartTest.class);
+        ignoredTests.add(CacheDiscoveryDataConcurrentJoinTest.class);
+        ignoredTests.add(IgniteCacheJdbcBlobStoreNodeRestartTest.class);
+        ignoredTests.add(IgniteInternalCacheTypesTest.class);
+        ignoredTests.add(IgniteExchangeFutureHistoryTest.class);
+        ignoredTests.add(CacheNoValueClassOnServerNodeTest.class);
+        ignoredTests.add(IgniteSystemCacheOnClientTest.class);
+        ignoredTests.add(MarshallerCacheJobRunNodeRestartTest.class);
+
+        // Skip classes which Mvcc implementations are added in this method below.
+        // TODO IGNITE-10175: refactor these tests (use assume) to support both mvcc and non-mvcc modes after moving to JUnit4/5.
+        ignoredTests.add(IgniteCrossCacheTxSelfTest.class);
+
+        TestSuite suite = new TestSuite("IgniteCache Mvcc Test Suite part 4");
+
+        suite.addTest(IgniteCacheTestSuite4.suite(ignoredTests));
+
+        // Add Mvcc clones.
+        suite.addTestSuite(IgniteCrossCacheMvccTxSelfTest.class);
+
+        return suite;
+    }
+}
diff --git a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheMvccTestSuite5.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheMvccTestSuite5.java
new file mode 100644
index 0000000..d422fc1
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheMvccTestSuite5.java
@@ -0,0 +1,94 @@
+/*
+ * 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 java.util.HashSet;
+import junit.framework.TestSuite;
+import org.apache.ignite.GridCacheAffinityBackupsSelfTest;
+import org.apache.ignite.IgniteCacheAffinitySelfTest;
+import org.apache.ignite.IgniteSystemProperties;
+import org.apache.ignite.cache.affinity.AffinityClientNodeSelfTest;
+import org.apache.ignite.cache.affinity.AffinityDistributionLoggingTest;
+import org.apache.ignite.cache.affinity.AffinityHistoryCleanupTest;
+import org.apache.ignite.cache.affinity.local.LocalAffinityFunctionTest;
+import org.apache.ignite.internal.GridCachePartitionExchangeManagerHistSizeTest;
+import org.apache.ignite.internal.processors.cache.CacheSerializableTransactionsTest;
+import org.apache.ignite.internal.processors.cache.ClusterReadOnlyModeTest;
+import org.apache.ignite.internal.processors.cache.ClusterStatePartitionedSelfTest;
+import org.apache.ignite.internal.processors.cache.ClusterStateReplicatedSelfTest;
+import org.apache.ignite.internal.processors.cache.ConcurrentCacheStartTest;
+import org.apache.ignite.internal.processors.cache.EntryVersionConsistencyReadThroughTest;
+import org.apache.ignite.internal.processors.cache.IgniteCachePutStackOverflowSelfTest;
+import org.apache.ignite.internal.processors.cache.IgniteCacheStoreCollectionTest;
+import org.apache.ignite.internal.processors.cache.PartitionsExchangeOnDiscoveryHistoryOverflowTest;
+import org.apache.ignite.internal.processors.cache.distributed.CacheLateAffinityAssignmentNodeJoinValidationTest;
+import org.apache.ignite.internal.processors.cache.distributed.IgniteCacheTxIteratorSelfTest;
+import org.apache.ignite.internal.processors.cache.distributed.dht.NotMappedPartitionInTxTest;
+import org.apache.ignite.internal.processors.cache.distributed.dht.atomic.IgniteCacheAtomicProtocolTest;
+import org.apache.ignite.internal.processors.cache.distributed.rebalancing.CacheManualRebalancingTest;
+import org.apache.ignite.internal.processors.cache.distributed.replicated.IgniteCacheSyncRebalanceModeSelfTest;
+import org.apache.ignite.internal.processors.cache.store.IgniteCacheWriteBehindNoUpdateSelfTest;
+
+/**
+ * Test suite.
+ */
+public class IgniteCacheMvccTestSuite5 extends TestSuite {
+    /**
+     * @return IgniteCache test suite.
+     */
+    public static TestSuite suite() {
+        System.setProperty(IgniteSystemProperties.IGNITE_FORCE_MVCC_MODE_IN_TESTS, "true");
+
+        HashSet<Class> ignoredTests = new HashSet<>(128);
+
+        // Skip classes that already contains Mvcc tests
+        ignoredTests.add(IgniteCacheStoreCollectionTest.class);
+        ignoredTests.add(EntryVersionConsistencyReadThroughTest.class);
+        ignoredTests.add(ClusterReadOnlyModeTest.class);
+        ignoredTests.add(NotMappedPartitionInTxTest.class);
+        ignoredTests.add(IgniteCacheTxIteratorSelfTest.class);
+
+        // Irrelevant Tx tests.
+        ignoredTests.add(CacheSerializableTransactionsTest.class);
+        ignoredTests.add(IgniteCachePutStackOverflowSelfTest.class);
+        ignoredTests.add(IgniteCacheAtomicProtocolTest.class);
+
+        // Other non-tx tests.
+        ignoredTests.add(CacheLateAffinityAssignmentNodeJoinValidationTest.class);
+        ignoredTests.add(IgniteCacheWriteBehindNoUpdateSelfTest.class);
+        ignoredTests.add(IgniteCacheSyncRebalanceModeSelfTest.class);
+        ignoredTests.add(ClusterStatePartitionedSelfTest.class);
+        ignoredTests.add(ClusterStateReplicatedSelfTest.class);
+        ignoredTests.add(CacheManualRebalancingTest.class);
+        ignoredTests.add(GridCacheAffinityBackupsSelfTest.class);
+        ignoredTests.add(IgniteCacheAffinitySelfTest.class);
+        ignoredTests.add(AffinityClientNodeSelfTest.class);
+        ignoredTests.add(LocalAffinityFunctionTest.class);
+        ignoredTests.add(AffinityHistoryCleanupTest.class);
+        ignoredTests.add(AffinityDistributionLoggingTest.class);
+        ignoredTests.add(PartitionsExchangeOnDiscoveryHistoryOverflowTest.class);
+        ignoredTests.add(GridCachePartitionExchangeManagerHistSizeTest.class);
+        ignoredTests.add(ConcurrentCacheStartTest.class);
+
+        TestSuite suite = new TestSuite("IgniteCache Mvcc Test Suite part 5");
+
+        suite.addTest(IgniteCacheTestSuite5.suite(ignoredTests));
+
+        return suite;
+    }
+}
diff --git a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheMvccTestSuite6.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheMvccTestSuite6.java
new file mode 100644
index 0000000..262f3b9
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheMvccTestSuite6.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.testsuites;
+
+import java.util.HashSet;
+import java.util.Set;
+import junit.framework.TestSuite;
+import org.apache.ignite.IgniteSystemProperties;
+import org.apache.ignite.internal.processors.cache.PartitionedAtomicCacheGetsDistributionTest;
+import org.apache.ignite.internal.processors.cache.PartitionedMvccTxPessimisticCacheGetsDistributionTest;
+import org.apache.ignite.internal.processors.cache.PartitionedTransactionalOptimisticCacheGetsDistributionTest;
+import org.apache.ignite.internal.processors.cache.PartitionedTransactionalPessimisticCacheGetsDistributionTest;
+import org.apache.ignite.internal.processors.cache.PartitionsExchangeCoordinatorFailoverTest;
+import org.apache.ignite.internal.processors.cache.ReplicatedAtomicCacheGetsDistributionTest;
+import org.apache.ignite.internal.processors.cache.ReplicatedMvccTxPessimisticCacheGetsDistributionTest;
+import org.apache.ignite.internal.processors.cache.ReplicatedTransactionalOptimisticCacheGetsDistributionTest;
+import org.apache.ignite.internal.processors.cache.ReplicatedTransactionalPessimisticCacheGetsDistributionTest;
+import org.apache.ignite.internal.processors.cache.datastructures.IgniteExchangeLatchManagerCoordinatorFailTest;
+import org.apache.ignite.internal.processors.cache.distributed.CacheExchangeMergeTest;
+import org.apache.ignite.internal.processors.cache.distributed.CacheParallelStartTest;
+import org.apache.ignite.internal.processors.cache.distributed.IgniteCache150ClientsTest;
+import org.apache.ignite.internal.processors.cache.distributed.IgniteOptimisticTxSuspendResumeTest;
+import org.apache.ignite.internal.processors.cache.transactions.TxOptimisticOnPartitionExchangeTest;
+import org.apache.ignite.internal.processors.cache.transactions.TxOptimisticPrepareOnUnstableTopologyTest;
+import org.apache.ignite.internal.processors.cache.transactions.TxRollbackOnTimeoutOnePhaseCommitTest;
+import org.apache.ignite.internal.processors.cache.transactions.TxStateChangeEventTest;
+
+/**
+ * Test suite.
+ */
+public class IgniteCacheMvccTestSuite6 extends TestSuite {
+    /**
+     * @return IgniteCache test suite.
+     */
+    public static TestSuite suite() {
+        System.setProperty(IgniteSystemProperties.IGNITE_FORCE_MVCC_MODE_IN_TESTS, "true");
+
+        Set<Class> ignoredTests = new HashSet<>();
+
+        // Skip classes that already contains Mvcc tests
+        ignoredTests.add(TxStateChangeEventTest.class);
+
+        // Atomic cache tests.
+        ignoredTests.add(ReplicatedAtomicCacheGetsDistributionTest.class);
+        ignoredTests.add(PartitionedAtomicCacheGetsDistributionTest.class);
+
+        // Irrelevant Tx tests.
+        ignoredTests.add(IgniteOptimisticTxSuspendResumeTest.class);
+        ignoredTests.add(TxOptimisticPrepareOnUnstableTopologyTest.class);
+        ignoredTests.add(ReplicatedTransactionalOptimisticCacheGetsDistributionTest.class);
+        ignoredTests.add(PartitionedTransactionalOptimisticCacheGetsDistributionTest.class);
+        ignoredTests.add(TxOptimisticOnPartitionExchangeTest.class);
+
+        ignoredTests.add(TxRollbackOnTimeoutOnePhaseCommitTest.class);
+
+        // Other non-tx tests.
+        ignoredTests.add(CacheExchangeMergeTest.class);
+        ignoredTests.add(IgniteExchangeLatchManagerCoordinatorFailTest.class);
+        ignoredTests.add(PartitionsExchangeCoordinatorFailoverTest.class);
+        ignoredTests.add(CacheParallelStartTest.class);
+        ignoredTests.add(IgniteCache150ClientsTest.class);
+
+        // Skip tests that has Mvcc clones.
+        ignoredTests.add(PartitionedTransactionalPessimisticCacheGetsDistributionTest.class); // See PartitionedMvccTxPessimisticCacheGetsDistributionTest.
+        ignoredTests.add(ReplicatedTransactionalPessimisticCacheGetsDistributionTest.class); //See ReplicatedMvccTxPessimisticCacheGetsDistributionTest
+
+        TestSuite suite = new TestSuite("IgniteCache Mvcc Test Suite part 6");
+
+        suite.addTest(IgniteCacheTestSuite6.suite(ignoredTests));
+
+        // Add mvcc versions for skipped tests.
+        suite.addTestSuite(PartitionedMvccTxPessimisticCacheGetsDistributionTest.class);
+        suite.addTestSuite(ReplicatedMvccTxPessimisticCacheGetsDistributionTest.class);
+
+        return suite;
+    }
+}
diff --git a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheMvccTestSuite7.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheMvccTestSuite7.java
new file mode 100644
index 0000000..403b5a0
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheMvccTestSuite7.java
@@ -0,0 +1,76 @@
+/*
+ * 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 java.util.HashSet;
+import junit.framework.TestSuite;
+import org.apache.ignite.IgniteSystemProperties;
+import org.apache.ignite.internal.processors.authentication.Authentication1kUsersNodeRestartTest;
+import org.apache.ignite.internal.processors.authentication.AuthenticationConfigurationClusterTest;
+import org.apache.ignite.internal.processors.authentication.AuthenticationOnNotActiveClusterTest;
+import org.apache.ignite.internal.processors.authentication.AuthenticationProcessorNPEOnStartTest;
+import org.apache.ignite.internal.processors.authentication.AuthenticationProcessorNodeRestartTest;
+import org.apache.ignite.internal.processors.authentication.AuthenticationProcessorSelfTest;
+import org.apache.ignite.internal.processors.cache.CacheDataRegionConfigurationTest;
+import org.apache.ignite.internal.processors.cache.CacheGroupMetricsMBeanTest;
+import org.apache.ignite.internal.processors.cache.MvccCacheGroupMetricsMBeanTest;
+import org.apache.ignite.internal.processors.cache.distributed.Cache64kPartitionsTest;
+import org.apache.ignite.internal.processors.cache.distributed.rebalancing.GridCacheRebalancingPartitionCountersMvccTest;
+import org.apache.ignite.internal.processors.cache.distributed.rebalancing.GridCacheRebalancingPartitionCountersTest;
+import org.apache.ignite.internal.processors.cache.persistence.db.CheckpointBufferDeadlockTest;
+
+/**
+ *
+ */
+public class IgniteCacheMvccTestSuite7  extends TestSuite {
+    /**
+     * @return IgniteCache test suite.
+     */
+    public static TestSuite suite() {
+        System.setProperty(IgniteSystemProperties.IGNITE_FORCE_MVCC_MODE_IN_TESTS, "true");
+
+        HashSet<Class> ignoredTests = new HashSet<>(128);
+
+        // Other non-tx tests.
+        ignoredTests.add(CheckpointBufferDeadlockTest.class);//
+        ignoredTests.add(AuthenticationConfigurationClusterTest.class);//
+        ignoredTests.add(AuthenticationProcessorSelfTest.class);
+        ignoredTests.add(AuthenticationOnNotActiveClusterTest.class);
+        ignoredTests.add(AuthenticationProcessorNodeRestartTest.class);
+        ignoredTests.add(AuthenticationProcessorNPEOnStartTest.class);
+        ignoredTests.add(Authentication1kUsersNodeRestartTest.class);
+        ignoredTests.add(CacheDataRegionConfigurationTest.class);
+        ignoredTests.add(Cache64kPartitionsTest.class);
+
+        // Skip classes which Mvcc implementations are added in this method below.
+        // TODO IGNITE-10175: refactor these tests (use assume) to support both mvcc and non-mvcc modes after moving to JUnit4/5.
+        ignoredTests.add(CacheGroupMetricsMBeanTest.class); // See MvccCacheGroupMetricsMBeanTest
+        ignoredTests.add(GridCacheRebalancingPartitionCountersTest.class); // See GridCacheRebalancingPartitionCountersMvccTest
+
+        TestSuite suite = new TestSuite("IgniteCache Mvcc Test Suite part 7");
+
+        suite.addTest(IgniteCacheTestSuite7.suite(ignoredTests));
+
+        // Add Mvcc clones.
+        suite.addTestSuite(MvccCacheGroupMetricsMBeanTest.class);
+        suite.addTestSuite(GridCacheRebalancingPartitionCountersMvccTest.class);
+
+
+        return suite;
+    }
+
+}
diff --git a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheMvccTestSuite9.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheMvccTestSuite9.java
new file mode 100644
index 0000000..17a9421
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheMvccTestSuite9.java
@@ -0,0 +1,57 @@
+/*
+ * 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 java.util.Collection;
+import java.util.HashSet;
+import junit.framework.TestSuite;
+import org.apache.ignite.IgniteSystemProperties;
+import org.apache.ignite.internal.processors.cache.IgniteCacheGetCustomCollectionsSelfTest;
+import org.apache.ignite.internal.processors.cache.IgniteCacheLoadRebalanceEvictionSelfTest;
+import org.apache.ignite.internal.processors.cache.distributed.CacheAtomicPrimarySyncBackPressureTest;
+import org.apache.ignite.internal.processors.cache.distributed.IgniteTxConcurrentRemoveObjectsTest;
+
+/**
+ * Test suite.
+ */
+public class IgniteCacheMvccTestSuite9 extends TestSuite {
+    /**
+     * @return IgniteCache test suite.
+     */
+    public static TestSuite suite() {
+        System.setProperty(IgniteSystemProperties.IGNITE_FORCE_MVCC_MODE_IN_TESTS, "true");
+
+        Collection<Class> ignoredTests = new HashSet<>();
+
+        // Skip classes that already contains Mvcc tests
+        ignoredTests.add(IgniteTxConcurrentRemoveObjectsTest.class);
+
+        // Atomic caches.
+        ignoredTests.add(CacheAtomicPrimarySyncBackPressureTest.class);
+
+        // Other non-tx tests.
+        ignoredTests.add(IgniteCacheGetCustomCollectionsSelfTest.class);
+        ignoredTests.add(IgniteCacheLoadRebalanceEvictionSelfTest.class);
+
+        TestSuite suite = new TestSuite("IgniteCache Mvcc Test Suite part 9");
+
+        suite.addTest(IgniteCacheTestSuite9.suite(ignoredTests));
+
+        return suite;
+    }
+}
diff --git a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheNearOnlySelfTestSuite.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheNearOnlySelfTestSuite.java
index 087007e..1519baa 100644
--- a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheNearOnlySelfTestSuite.java
+++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheNearOnlySelfTestSuite.java
@@ -17,10 +17,12 @@
 
 package org.apache.ignite.testsuites;
 
+import java.util.Collection;
 import junit.framework.TestSuite;
 import org.apache.ignite.internal.processors.cache.distributed.dht.GridCacheClientOnlySelfTest;
 import org.apache.ignite.internal.processors.cache.distributed.near.GridCacheNearOnlySelfTest;
 import org.apache.ignite.internal.processors.cache.distributed.near.GridCacheNearOnlyTopologySelfTest;
+import org.apache.ignite.testframework.GridTestUtils;
 
 /**
  * Test suite for near-only cache.
@@ -28,22 +30,29 @@
 public class IgniteCacheNearOnlySelfTestSuite {
     /**
      * @return Suite.
-     * @throws Exception If failed.
      */
-    public static TestSuite suite() throws Exception {
+    public static TestSuite suite() {
+        return suite(null);
+    }
+
+    /**
+     * @param ignoredTests Ignored tests.
+     * @return IgniteCache test suite.
+     */
+    public static TestSuite suite(Collection<Class> ignoredTests) {
         TestSuite suite = new TestSuite("Near-only cache test suite.");
 
-        suite.addTest(new TestSuite(GridCacheClientOnlySelfTest.CasePartitionedAtomic.class));
-        suite.addTest(new TestSuite(GridCacheClientOnlySelfTest.CasePartitionedTransactional.class));
-        suite.addTest(new TestSuite(GridCacheClientOnlySelfTest.CaseReplicatedAtomic.class));
-        suite.addTest(new TestSuite(GridCacheClientOnlySelfTest.CaseReplicatedTransactional.class));
+        GridTestUtils.addTestIfNeeded(suite,GridCacheClientOnlySelfTest.CasePartitionedAtomic.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite,GridCacheClientOnlySelfTest.CasePartitionedTransactional.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite,GridCacheClientOnlySelfTest.CaseReplicatedAtomic.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite,GridCacheClientOnlySelfTest.CaseReplicatedTransactional.class, ignoredTests);
 
-        suite.addTest(new TestSuite(GridCacheNearOnlyTopologySelfTest.class));
+        GridTestUtils.addTestIfNeeded(suite,GridCacheNearOnlyTopologySelfTest.class, ignoredTests);
 
-        suite.addTest(new TestSuite(GridCacheNearOnlySelfTest.CasePartitionedAtomic.class));
-        suite.addTest(new TestSuite(GridCacheNearOnlySelfTest.CasePartitionedTransactional.class));
-        suite.addTest(new TestSuite(GridCacheNearOnlySelfTest.CaseReplicatedAtomic.class));
-        suite.addTest(new TestSuite(GridCacheNearOnlySelfTest.CaseReplicatedTransactional.class));
+        GridTestUtils.addTestIfNeeded(suite,GridCacheNearOnlySelfTest.CasePartitionedAtomic.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite,GridCacheNearOnlySelfTest.CasePartitionedTransactional.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite,GridCacheNearOnlySelfTest.CaseReplicatedAtomic.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite,GridCacheNearOnlySelfTest.CaseReplicatedTransactional.class, ignoredTests);
 
         return suite;
     }
diff --git a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite.java
index dd03ef3..9781b85 100755
--- a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite.java
+++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite.java
@@ -107,6 +107,7 @@
 import org.apache.ignite.internal.processors.cache.IgniteCacheTxLocalInvokeTest;
 import org.apache.ignite.internal.processors.cache.IgniteCacheTxNearEnabledInvokeTest;
 import org.apache.ignite.internal.processors.cache.IgniteClientAffinityAssignmentSelfTest;
+import org.apache.ignite.internal.processors.cache.IgniteGetNonPlainKeyReadThroughSelfTest;
 import org.apache.ignite.internal.processors.cache.IgniteIncompleteCacheObjectSelfTest;
 import org.apache.ignite.internal.processors.cache.IgnitePutAllLargeBatchSelfTest;
 import org.apache.ignite.internal.processors.cache.IgnitePutAllUpdateNonPreloadedPartitionSelfTest;
@@ -366,6 +367,8 @@
 
         suite.addTestSuite(BinaryMetadataRegistrationInsideEntryProcessorTest.class);
 
+        suite.addTestSuite(IgniteGetNonPlainKeyReadThroughSelfTest.class);
+
         return suite;
     }
 }
diff --git a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite2.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite2.java
index 179f5e9..e367aad 100644
--- a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite2.java
+++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite2.java
@@ -17,7 +17,7 @@
 
 package org.apache.ignite.testsuites;
 
-import java.util.HashSet;
+import java.util.Collection;
 import junit.framework.TestSuite;
 import org.apache.ignite.cache.affinity.rendezvous.ClusterNodeAttributeAffinityBackupFilterSelfTest;
 import org.apache.ignite.cache.affinity.rendezvous.RendezvousAffinityFunctionBackupFilterSelfTest;
@@ -66,6 +66,7 @@
 import org.apache.ignite.internal.processors.cache.distributed.IgniteCacheClientNodeChangingTopologyTest;
 import org.apache.ignite.internal.processors.cache.distributed.IgniteCacheClientNodePartitionsExchangeTest;
 import org.apache.ignite.internal.processors.cache.distributed.IgniteCacheServerNodeConcurrentStart;
+import org.apache.ignite.internal.processors.cache.distributed.dht.CacheGetReadFromBackupFailoverTest;
 import org.apache.ignite.internal.processors.cache.distributed.dht.CachePartitionPartialCountersMapSelfTest;
 import org.apache.ignite.internal.processors.cache.distributed.dht.GridCacheColocatedOptimisticTransactionSelfTest;
 import org.apache.ignite.internal.processors.cache.distributed.dht.GridCacheColocatedPreloadRestartSelfTest;
@@ -153,7 +154,6 @@
 public class IgniteCacheTestSuite2 extends TestSuite {
     /**
      * @return IgniteCache test suite.
-     * @throws Exception Thrown in case of the failure.
      */
     public static TestSuite suite() {
         return suite(null);
@@ -162,9 +162,8 @@
     /**
      * @param ignoredTests Ignored tests.
      * @return IgniteCache test suite.
-     * @throws Exception Thrown in case of the failure.
      */
-    public static TestSuite suite(HashSet<Class> ignoredTests) {
+    public static TestSuite suite(Collection<Class> ignoredTests) {
         TestSuite suite = new TestSuite("IgniteCache Test Suite part 2");
 
         // Local cache.
@@ -248,6 +247,7 @@
         GridTestUtils.addTestIfNeeded(suite, CacheLoadingConcurrentGridStartSelfTestAllowOverwrite.class, ignoredTests);
         GridTestUtils.addTestIfNeeded(suite, CacheTxLoadingConcurrentGridStartSelfTestAllowOverwrite.class, ignoredTests);
         GridTestUtils.addTestIfNeeded(suite, GridPartitionedBackupLoadSelfTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite, CacheGetReadFromBackupFailoverTest.class, ignoredTests);
         GridTestUtils.addTestIfNeeded(suite, GridCachePartitionedLoadCacheSelfTest.class, ignoredTests);
         GridTestUtils.addTestIfNeeded(suite, GridCachePartitionedEventSelfTest.class, ignoredTests);
         GridTestUtils.addTestIfNeeded(suite, GridCachePartitionNotLoadedEventSelfTest.class, ignoredTests);
diff --git a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite3.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite3.java
index 2c2c7ef..98778ca 100644
--- a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite3.java
+++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite3.java
@@ -17,6 +17,7 @@
 
 package org.apache.ignite.testsuites;
 
+import java.util.Collection;
 import junit.framework.TestSuite;
 import org.apache.ignite.internal.processors.cache.CacheStartupInDeploymentModesTest;
 import org.apache.ignite.internal.processors.cache.GridCacheAtomicEntryProcessorDeploymentSelfTest;
@@ -70,12 +71,12 @@
 import org.apache.ignite.internal.processors.cache.distributed.replicated.GridCacheReplicatedTxSingleThreadedSelfTest;
 import org.apache.ignite.internal.processors.cache.distributed.replicated.GridCacheReplicatedTxTimeoutSelfTest;
 import org.apache.ignite.internal.processors.cache.distributed.replicated.GridCacheSyncReplicatedPreloadSelfTest;
-import org.apache.ignite.internal.processors.cache.distributed.replicated.GridReplicatedTxPreloadTest;
 import org.apache.ignite.internal.processors.cache.distributed.replicated.preloader.GridCacheReplicatedPreloadLifecycleSelfTest;
 import org.apache.ignite.internal.processors.cache.distributed.replicated.preloader.GridCacheReplicatedPreloadSelfTest;
 import org.apache.ignite.internal.processors.cache.distributed.replicated.preloader.GridCacheReplicatedPreloadStartStopEventsSelfTest;
 import org.apache.ignite.internal.processors.cache.local.GridCacheDaemonNodeLocalSelfTest;
 import org.apache.ignite.internal.processors.cache.local.GridCacheLocalByteArrayValuesSelfTest;
+import org.apache.ignite.testframework.GridTestUtils;
 
 /**
  * Test suite.
@@ -83,110 +84,116 @@
 public class IgniteCacheTestSuite3 extends TestSuite {
     /**
      * @return IgniteCache test suite.
-     * @throws Exception Thrown in case of the failure.
      */
-    public static TestSuite suite() throws Exception {
+    public static TestSuite suite() {
+        return suite(null);
+    }
+
+    /**
+     * @param ignoredTests Ignored tests.
+     * @return IgniteCache test suite.
+     */
+    public static TestSuite suite(Collection<Class> ignoredTests) {
         TestSuite suite = new TestSuite("IgniteCache Test Suite part 3");
 
-        suite.addTestSuite(IgniteCacheGroupsTest.class);
+        GridTestUtils.addTestIfNeeded(suite,IgniteCacheGroupsTest.class, ignoredTests);
 
         // Value consistency tests.
-        suite.addTestSuite(GridCacheValueConsistencyAtomicSelfTest.class);
-        suite.addTestSuite(GridCacheValueConsistencyAtomicNearEnabledSelfTest.class);
-        suite.addTestSuite(GridCacheValueConsistencyTransactionalSelfTest.class);
-        suite.addTestSuite(GridCacheValueConsistencyTransactionalNearEnabledSelfTest.class);
-        suite.addTestSuite(GridCacheValueBytesPreloadingSelfTest.class);
+        GridTestUtils.addTestIfNeeded(suite,GridCacheValueConsistencyAtomicSelfTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite,GridCacheValueConsistencyAtomicNearEnabledSelfTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite,GridCacheValueConsistencyTransactionalSelfTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite,GridCacheValueConsistencyTransactionalNearEnabledSelfTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite,GridCacheValueBytesPreloadingSelfTest.class, ignoredTests);
 
         // Replicated cache.
-        suite.addTestSuite(GridCacheReplicatedBasicApiTest.class);
-        suite.addTestSuite(GridCacheReplicatedBasicOpSelfTest.class);
-        suite.addTestSuite(GridCacheReplicatedBasicStoreSelfTest.class);
-        suite.addTestSuite(GridCacheReplicatedGetAndTransformStoreSelfTest.class);
-        suite.addTestSuite(GridCacheReplicatedAtomicGetAndTransformStoreSelfTest.class);
-        suite.addTestSuite(GridCacheReplicatedEventSelfTest.class);
-        suite.addTestSuite(GridCacheReplicatedEventDisabledSelfTest.class);
-        suite.addTestSuite(GridCacheReplicatedSynchronousCommitTest.class);
+        GridTestUtils.addTestIfNeeded(suite,GridCacheReplicatedBasicApiTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite,GridCacheReplicatedBasicOpSelfTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite,GridCacheReplicatedBasicStoreSelfTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite,GridCacheReplicatedGetAndTransformStoreSelfTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite,GridCacheReplicatedAtomicGetAndTransformStoreSelfTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite,GridCacheReplicatedEventSelfTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite,GridCacheReplicatedEventDisabledSelfTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite,GridCacheReplicatedSynchronousCommitTest.class, ignoredTests);
 
-        suite.addTestSuite(GridCacheReplicatedLockSelfTest.class);
-        suite.addTestSuite(GridCacheReplicatedMultiNodeLockSelfTest.class);
-        suite.addTestSuite(GridCacheReplicatedMultiNodeSelfTest.class);
-        suite.addTestSuite(GridCacheReplicatedNodeFailureSelfTest.class);
-        suite.addTestSuite(GridCacheReplicatedTxSingleThreadedSelfTest.class);
-        suite.addTestSuite(GridCacheReplicatedTxTimeoutSelfTest.class);
-        suite.addTestSuite(GridCacheReplicatedPreloadSelfTest.class);
-        suite.addTestSuite(GridCacheReplicatedPreloadLifecycleSelfTest.class);
-        suite.addTestSuite(GridCacheSyncReplicatedPreloadSelfTest.class);
+        GridTestUtils.addTestIfNeeded(suite,GridCacheReplicatedLockSelfTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite,GridCacheReplicatedMultiNodeLockSelfTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite,GridCacheReplicatedMultiNodeSelfTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite,GridCacheReplicatedNodeFailureSelfTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite,GridCacheReplicatedTxSingleThreadedSelfTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite,GridCacheReplicatedTxTimeoutSelfTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite,GridCacheReplicatedPreloadSelfTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite,GridCacheReplicatedPreloadLifecycleSelfTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite,GridCacheSyncReplicatedPreloadSelfTest.class, ignoredTests);
 
-        //suite.addTestSuite(GridCacheReplicatedEntrySetSelfTest.class);
-        //suite.addTestSuite(GridCacheReplicatedMarshallerTxTest.class);
-        //suite.addTestSuite(GridCacheReplicatedOnheapFullApiSelfTest.class);
-        //suite.addTestSuite(GridCacheReplicatedOnheapMultiNodeFullApiSelfTest.class);
-        //suite.addTestSuite(GridCacheReplicatedTxConcurrentGetTest.class);
-        //suite.addTestSuite(GridCacheReplicatedTxMultiNodeBasicTest.class);
-        //suite.addTestSuite(GridCacheReplicatedTxReadTest.class);
+        //GridTestUtils.addTestIfNeeded(suite,GridCacheReplicatedEntrySetSelfTest.class, ignoredTests);
+        //GridTestUtils.addTestIfNeeded(suite,GridCacheReplicatedMarshallerTxTest.class, ignoredTests);
+        //GridTestUtils.addTestIfNeeded(suite,GridCacheReplicatedOnheapFullApiSelfTest.class, ignoredTests);
+        //GridTestUtils.addTestIfNeeded(suite,GridCacheReplicatedOnheapMultiNodeFullApiSelfTest.class, ignoredTests);
+        //GridTestUtils.addTestIfNeeded(suite,GridCacheReplicatedTxConcurrentGetTest.class, ignoredTests);
+        //GridTestUtils.addTestIfNeeded(suite,GridCacheReplicatedTxMultiNodeBasicTest.class, ignoredTests);
+        //GridTestUtils.addTestIfNeeded(suite,GridCacheReplicatedTxReadTest.class, ignoredTests);
 
         // TODO GG-11141.
-//        suite.addTestSuite(GridCacheDeploymentSelfTest.class);
-//        suite.addTestSuite(GridCacheDeploymentOffHeapSelfTest.class);
-//        suite.addTestSuite(GridCacheDeploymentOffHeapValuesSelfTest.class);
-        suite.addTestSuite(CacheStartupInDeploymentModesTest.class);
-        suite.addTestSuite(GridCacheConditionalDeploymentSelfTest.class);
-        suite.addTestSuite(GridCacheAtomicEntryProcessorDeploymentSelfTest.class);
-        suite.addTestSuite(GridCacheTransactionalEntryProcessorDeploymentSelfTest.class);
-        suite.addTestSuite(IgniteCacheScanPredicateDeploymentSelfTest.class);
+//        GridTestUtils.addTestIfNeeded(suite,GridCacheDeploymentSelfTest.class, ignoredTests);
+//        GridTestUtils.addTestIfNeeded(suite,GridCacheDeploymentOffHeapSelfTest.class, ignoredTests);
+//        GridTestUtils.addTestIfNeeded(suite,GridCacheDeploymentOffHeapValuesSelfTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite,CacheStartupInDeploymentModesTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite,GridCacheConditionalDeploymentSelfTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite,GridCacheAtomicEntryProcessorDeploymentSelfTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite,GridCacheTransactionalEntryProcessorDeploymentSelfTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite,IgniteCacheScanPredicateDeploymentSelfTest.class, ignoredTests);
 
-        suite.addTestSuite(GridCachePutArrayValueSelfTest.class);
-        suite.addTestSuite(GridCacheReplicatedEvictionEventSelfTest.class);
-        suite.addTestSuite(GridCacheReplicatedTxMultiThreadedSelfTest.class);
-        suite.addTestSuite(GridCacheReplicatedPreloadEventsSelfTest.class);
-        suite.addTestSuite(GridCacheReplicatedPreloadStartStopEventsSelfTest.class);
-        suite.addTestSuite(GridReplicatedTxPreloadTest.class);
+        GridTestUtils.addTestIfNeeded(suite,GridCachePutArrayValueSelfTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite,GridCacheReplicatedEvictionEventSelfTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite,GridCacheReplicatedTxMultiThreadedSelfTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite,GridCacheReplicatedPreloadEventsSelfTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite,GridCacheReplicatedPreloadStartStopEventsSelfTest.class, ignoredTests);
 
-        suite.addTestSuite(IgniteTxReentryNearSelfTest.class);
-        suite.addTestSuite(IgniteTxReentryColocatedSelfTest.class);
+        GridTestUtils.addTestIfNeeded(suite,IgniteTxReentryNearSelfTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite,IgniteTxReentryColocatedSelfTest.class, ignoredTests);
 
         // Test for byte array value special case.
-        suite.addTestSuite(GridCacheLocalByteArrayValuesSelfTest.class);
-        suite.addTestSuite(GridCacheNearPartitionedP2PEnabledByteArrayValuesSelfTest.class);
-        suite.addTestSuite(GridCacheNearPartitionedP2PDisabledByteArrayValuesSelfTest.class);
-        suite.addTestSuite(GridCachePartitionedOnlyP2PEnabledByteArrayValuesSelfTest.class);
-        suite.addTestSuite(GridCachePartitionedOnlyP2PDisabledByteArrayValuesSelfTest.class);
-        suite.addTestSuite(GridCacheReplicatedP2PEnabledByteArrayValuesSelfTest.class);
-        suite.addTestSuite(GridCacheReplicatedP2PDisabledByteArrayValuesSelfTest.class);
+        GridTestUtils.addTestIfNeeded(suite,GridCacheLocalByteArrayValuesSelfTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite,GridCacheNearPartitionedP2PEnabledByteArrayValuesSelfTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite,GridCacheNearPartitionedP2PDisabledByteArrayValuesSelfTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite,GridCachePartitionedOnlyP2PEnabledByteArrayValuesSelfTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite,GridCachePartitionedOnlyP2PDisabledByteArrayValuesSelfTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite,GridCacheReplicatedP2PEnabledByteArrayValuesSelfTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite,GridCacheReplicatedP2PDisabledByteArrayValuesSelfTest.class, ignoredTests);
 
         // Near-only cache.
-        suite.addTest(IgniteCacheNearOnlySelfTestSuite.suite());
+        suite.addTest(IgniteCacheNearOnlySelfTestSuite.suite(ignoredTests));
 
         // Test cache with daemon nodes.
-        suite.addTestSuite(GridCacheDaemonNodeLocalSelfTest.class);
-        suite.addTestSuite(GridCacheDaemonNodePartitionedSelfTest.class);
-        suite.addTestSuite(GridCacheDaemonNodeReplicatedSelfTest.class);
+        GridTestUtils.addTestIfNeeded(suite,GridCacheDaemonNodeLocalSelfTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite,GridCacheDaemonNodePartitionedSelfTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite,GridCacheDaemonNodeReplicatedSelfTest.class, ignoredTests);
 
         // Write-behind.
-        suite.addTest(IgniteCacheWriteBehindTestSuite.suite());
+        suite.addTest(IgniteCacheWriteBehindTestSuite.suite(ignoredTests));
 
         // Transform.
-        suite.addTestSuite(GridCachePartitionedTransformWriteThroughBatchUpdateSelfTest.class);
+        GridTestUtils.addTestIfNeeded(suite,GridCachePartitionedTransformWriteThroughBatchUpdateSelfTest.class, ignoredTests);
 
-        suite.addTestSuite(GridCacheEntryVersionSelfTest.class);
-        suite.addTestSuite(GridCacheVersionSelfTest.class);
-        suite.addTestSuite(GridCacheVersionTopologyChangeTest.class);
+        GridTestUtils.addTestIfNeeded(suite,GridCacheEntryVersionSelfTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite,GridCacheVersionSelfTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite,GridCacheVersionTopologyChangeTest.class, ignoredTests);
 
         // Memory leak tests.
-        suite.addTestSuite(GridCacheReferenceCleanupSelfTest.class);
-        suite.addTestSuite(GridCacheReloadSelfTest.class);
+        GridTestUtils.addTestIfNeeded(suite,GridCacheReferenceCleanupSelfTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite,GridCacheReloadSelfTest.class, ignoredTests);
 
-        suite.addTestSuite(GridCacheMixedModeSelfTest.class);
+        GridTestUtils.addTestIfNeeded(suite,GridCacheMixedModeSelfTest.class, ignoredTests);
 
         // Cache interceptor tests.
-        suite.addTest(IgniteCacheInterceptorSelfTestSuite.suite());
+        suite.addTest(IgniteCacheInterceptorSelfTestSuite.suite(ignoredTests));
 
-        suite.addTestSuite(IgniteTxGetAfterStopTest.class);
+        GridTestUtils.addTestIfNeeded(suite,IgniteTxGetAfterStopTest.class, ignoredTests);
 
-        suite.addTestSuite(CacheAsyncOperationsTest.class);
+        GridTestUtils.addTestIfNeeded(suite,CacheAsyncOperationsTest.class, ignoredTests);
 
-        suite.addTestSuite(IgniteTxRemoveTimeoutObjectsTest.class);
-        suite.addTestSuite(IgniteTxRemoveTimeoutObjectsNearTest.class);
+        GridTestUtils.addTestIfNeeded(suite,IgniteTxRemoveTimeoutObjectsTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite,IgniteTxRemoveTimeoutObjectsNearTest.class, ignoredTests);
 
         return suite;
     }
diff --git a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite4.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite4.java
index 5f7377f..05aa54c 100644
--- a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite4.java
+++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite4.java
@@ -17,6 +17,7 @@
 
 package org.apache.ignite.testsuites;
 
+import java.util.HashSet;
 import junit.framework.TestSuite;
 import org.apache.ignite.cache.store.CacheStoreListenerRWThroughDisabledAtomicCacheTest;
 import org.apache.ignite.cache.store.CacheStoreListenerRWThroughDisabledTransactionalCacheTest;
@@ -26,12 +27,13 @@
 import org.apache.ignite.internal.processors.GridCacheTxLoadFromStoreOnLockSelfTest;
 import org.apache.ignite.internal.processors.cache.CacheClientStoreSelfTest;
 import org.apache.ignite.internal.processors.cache.CacheConnectionLeakStoreTxTest;
-import org.apache.ignite.internal.processors.cache.CacheGetEntryOptimisticReadCommittedSeltTest;
-import org.apache.ignite.internal.processors.cache.CacheGetEntryOptimisticRepeatableReadSeltTest;
-import org.apache.ignite.internal.processors.cache.CacheGetEntryOptimisticSerializableSeltTest;
-import org.apache.ignite.internal.processors.cache.CacheGetEntryPessimisticReadCommittedSeltTest;
-import org.apache.ignite.internal.processors.cache.CacheGetEntryPessimisticRepeatableReadSeltTest;
-import org.apache.ignite.internal.processors.cache.CacheGetEntryPessimisticSerializableSeltTest;
+import org.apache.ignite.internal.processors.cache.CacheEventWithTxLabelTest;
+import org.apache.ignite.internal.processors.cache.CacheGetEntryOptimisticReadCommittedSelfTest;
+import org.apache.ignite.internal.processors.cache.CacheGetEntryOptimisticRepeatableReadSelfTest;
+import org.apache.ignite.internal.processors.cache.CacheGetEntryOptimisticSerializableSelfTest;
+import org.apache.ignite.internal.processors.cache.CacheGetEntryPessimisticReadCommittedSelfTest;
+import org.apache.ignite.internal.processors.cache.CacheGetEntryPessimisticRepeatableReadSelfTest;
+import org.apache.ignite.internal.processors.cache.CacheGetEntryPessimisticSerializableSelfTest;
 import org.apache.ignite.internal.processors.cache.CacheOffheapMapEntrySelfTest;
 import org.apache.ignite.internal.processors.cache.CacheReadThroughAtomicRestartSelfTest;
 import org.apache.ignite.internal.processors.cache.CacheReadThroughLocalAtomicRestartSelfTest;
@@ -46,7 +48,6 @@
 import org.apache.ignite.internal.processors.cache.CacheStoreUsageMultinodeStaticStartAtomicTest;
 import org.apache.ignite.internal.processors.cache.CacheStoreUsageMultinodeStaticStartTxTest;
 import org.apache.ignite.internal.processors.cache.CacheTxNotAllowReadFromBackupTest;
-import org.apache.ignite.internal.processors.cache.CashEventWithTxLabelTest;
 import org.apache.ignite.internal.processors.cache.CrossCacheLockTest;
 import org.apache.ignite.internal.processors.cache.GridCacheMarshallingNodeJoinSelfTest;
 import org.apache.ignite.internal.processors.cache.GridCacheMultinodeUpdateAtomicNearEnabledSelfTest;
@@ -155,193 +156,202 @@
 import org.apache.ignite.internal.processors.cache.version.CacheVersionedEntryReplicatedAtomicSelfTest;
 import org.apache.ignite.internal.processors.cache.version.CacheVersionedEntryReplicatedTransactionalSelfTest;
 
+import static org.apache.ignite.testframework.GridTestUtils.addTestIfNeeded;
+
 /**
  * Test suite.
  */
 public class IgniteCacheTestSuite4 extends TestSuite {
     /**
      * @return IgniteCache test suite.
-     * @throws Exception Thrown in case of the failure.
      */
-    public static TestSuite suite() throws Exception {
+    public static TestSuite suite() {
+        return suite(null);
+    }
+
+    /**
+     * @param ignoredTests Ignored tests.
+     * @return IgniteCache test suite.
+     */
+    public static TestSuite suite(HashSet<Class> ignoredTests) {
         TestSuite suite = new TestSuite("IgniteCache Test Suite part 4");
 
         // Multi node update.
-        suite.addTestSuite(GridCacheMultinodeUpdateSelfTest.class);
-        suite.addTestSuite(GridCacheMultinodeUpdateNearEnabledSelfTest.class);
-        suite.addTestSuite(GridCacheMultinodeUpdateNearEnabledNoBackupsSelfTest.class);
-        suite.addTestSuite(GridCacheMultinodeUpdateAtomicSelfTest.class);
-        suite.addTestSuite(GridCacheMultinodeUpdateAtomicNearEnabledSelfTest.class);
+        addTestIfNeeded(suite, GridCacheMultinodeUpdateSelfTest.class, ignoredTests);
+        addTestIfNeeded(suite, GridCacheMultinodeUpdateNearEnabledSelfTest.class, ignoredTests);
+        addTestIfNeeded(suite, GridCacheMultinodeUpdateNearEnabledNoBackupsSelfTest.class, ignoredTests);
+        addTestIfNeeded(suite, GridCacheMultinodeUpdateAtomicSelfTest.class, ignoredTests);
+        addTestIfNeeded(suite, GridCacheMultinodeUpdateAtomicNearEnabledSelfTest.class, ignoredTests);
 
-        suite.addTestSuite(IgniteCacheAtomicLoadAllTest.class);
-        suite.addTestSuite(IgniteCacheAtomicLocalLoadAllTest.class);
-        suite.addTestSuite(IgniteCacheTxLoadAllTest.class);
-        suite.addTestSuite(IgniteCacheTxLocalLoadAllTest.class);
+        addTestIfNeeded(suite, IgniteCacheAtomicLoadAllTest.class, ignoredTests);
+        addTestIfNeeded(suite, IgniteCacheAtomicLocalLoadAllTest.class, ignoredTests);
+        addTestIfNeeded(suite, IgniteCacheTxLoadAllTest.class, ignoredTests);
+        addTestIfNeeded(suite, IgniteCacheTxLocalLoadAllTest.class, ignoredTests);
 
-        suite.addTestSuite(IgniteCacheAtomicLoaderWriterTest.class);
-        suite.addTestSuite(IgniteCacheTxLoaderWriterTest.class);
+        addTestIfNeeded(suite, IgniteCacheAtomicLoaderWriterTest.class, ignoredTests);
+        addTestIfNeeded(suite, IgniteCacheTxLoaderWriterTest.class, ignoredTests);
 
-        suite.addTestSuite(IgniteCacheAtomicStoreSessionTest.class);
-        suite.addTestSuite(IgniteCacheTxStoreSessionTest.class);
-        suite.addTestSuite(IgniteCacheAtomicStoreSessionWriteBehindTest.class);
-        suite.addTestSuite(IgniteCacheTxStoreSessionWriteBehindTest.class);
-        suite.addTestSuite(IgniteCacheTxStoreSessionWriteBehindCoalescingTest.class);
+        addTestIfNeeded(suite, IgniteCacheAtomicStoreSessionTest.class, ignoredTests);
+        addTestIfNeeded(suite, IgniteCacheTxStoreSessionTest.class, ignoredTests);
+        addTestIfNeeded(suite, IgniteCacheAtomicStoreSessionWriteBehindTest.class, ignoredTests);
+        addTestIfNeeded(suite, IgniteCacheTxStoreSessionWriteBehindTest.class, ignoredTests);
+        addTestIfNeeded(suite, IgniteCacheTxStoreSessionWriteBehindCoalescingTest.class, ignoredTests);
 
-        suite.addTestSuite(IgniteCacheAtomicNoReadThroughTest.class);
-        suite.addTestSuite(IgniteCacheAtomicNearEnabledNoReadThroughTest.class);
-        suite.addTestSuite(IgniteCacheAtomicLocalNoReadThroughTest.class);
-        suite.addTestSuite(IgniteCacheTxNoReadThroughTest.class);
-        suite.addTestSuite(IgniteCacheTxNearEnabledNoReadThroughTest.class);
-        suite.addTestSuite(IgniteCacheTxLocalNoReadThroughTest.class);
+        addTestIfNeeded(suite, IgniteCacheAtomicNoReadThroughTest.class, ignoredTests);
+        addTestIfNeeded(suite, IgniteCacheAtomicNearEnabledNoReadThroughTest.class, ignoredTests);
+        addTestIfNeeded(suite, IgniteCacheAtomicLocalNoReadThroughTest.class, ignoredTests);
+        addTestIfNeeded(suite, IgniteCacheTxNoReadThroughTest.class, ignoredTests);
+        addTestIfNeeded(suite, IgniteCacheTxNearEnabledNoReadThroughTest.class, ignoredTests);
+        addTestIfNeeded(suite, IgniteCacheTxLocalNoReadThroughTest.class, ignoredTests);
 
-        suite.addTestSuite(IgniteCacheAtomicNoLoadPreviousValueTest.class);
-        suite.addTestSuite(IgniteCacheAtomicNearEnabledNoLoadPreviousValueTest.class);
-        suite.addTestSuite(IgniteCacheAtomicLocalNoLoadPreviousValueTest.class);
-        suite.addTestSuite(IgniteCacheTxNoLoadPreviousValueTest.class);
-        suite.addTestSuite(IgniteCacheTxNearEnabledNoLoadPreviousValueTest.class);
-        suite.addTestSuite(IgniteCacheTxLocalNoLoadPreviousValueTest.class);
+        addTestIfNeeded(suite, IgniteCacheAtomicNoLoadPreviousValueTest.class, ignoredTests);
+        addTestIfNeeded(suite, IgniteCacheAtomicNearEnabledNoLoadPreviousValueTest.class, ignoredTests);
+        addTestIfNeeded(suite, IgniteCacheAtomicLocalNoLoadPreviousValueTest.class, ignoredTests);
+        addTestIfNeeded(suite, IgniteCacheTxNoLoadPreviousValueTest.class, ignoredTests);
+        addTestIfNeeded(suite, IgniteCacheTxNearEnabledNoLoadPreviousValueTest.class, ignoredTests);
+        addTestIfNeeded(suite, IgniteCacheTxLocalNoLoadPreviousValueTest.class, ignoredTests);
 
-        suite.addTestSuite(IgniteCacheAtomicNoWriteThroughTest.class);
-        suite.addTestSuite(IgniteCacheAtomicNearEnabledNoWriteThroughTest.class);
-        suite.addTestSuite(IgniteCacheAtomicLocalNoWriteThroughTest.class);
-        suite.addTestSuite(IgniteCacheTxNoWriteThroughTest.class);
-        suite.addTestSuite(IgniteCacheTxNearEnabledNoWriteThroughTest.class);
-        suite.addTestSuite(IgniteCacheTxLocalNoWriteThroughTest.class);
+        addTestIfNeeded(suite, IgniteCacheAtomicNoWriteThroughTest.class, ignoredTests);
+        addTestIfNeeded(suite, IgniteCacheAtomicNearEnabledNoWriteThroughTest.class, ignoredTests);
+        addTestIfNeeded(suite, IgniteCacheAtomicLocalNoWriteThroughTest.class, ignoredTests);
+        addTestIfNeeded(suite, IgniteCacheTxNoWriteThroughTest.class, ignoredTests);
+        addTestIfNeeded(suite, IgniteCacheTxNearEnabledNoWriteThroughTest.class, ignoredTests);
+        addTestIfNeeded(suite, IgniteCacheTxLocalNoWriteThroughTest.class, ignoredTests);
 
-        suite.addTestSuite(IgniteCacheAtomicPeekModesTest.class);
-        suite.addTestSuite(IgniteCacheAtomicNearPeekModesTest.class);
-        suite.addTestSuite(IgniteCacheAtomicReplicatedPeekModesTest.class);
-        suite.addTestSuite(IgniteCacheAtomicLocalPeekModesTest.class);
-        suite.addTestSuite(IgniteCacheTxPeekModesTest.class);
-        suite.addTestSuite(IgniteCacheTxNearPeekModesTest.class);
-        suite.addTestSuite(IgniteCacheTxLocalPeekModesTest.class);
-        suite.addTestSuite(IgniteCacheTxReplicatedPeekModesTest.class);
+        addTestIfNeeded(suite, IgniteCacheAtomicPeekModesTest.class, ignoredTests);
+        addTestIfNeeded(suite, IgniteCacheAtomicNearPeekModesTest.class, ignoredTests);
+        addTestIfNeeded(suite, IgniteCacheAtomicReplicatedPeekModesTest.class, ignoredTests);
+        addTestIfNeeded(suite, IgniteCacheAtomicLocalPeekModesTest.class, ignoredTests);
+        addTestIfNeeded(suite, IgniteCacheTxPeekModesTest.class, ignoredTests);
+        addTestIfNeeded(suite, IgniteCacheTxNearPeekModesTest.class, ignoredTests);
+        addTestIfNeeded(suite, IgniteCacheTxLocalPeekModesTest.class, ignoredTests);
+        addTestIfNeeded(suite, IgniteCacheTxReplicatedPeekModesTest.class, ignoredTests);
 
-        suite.addTestSuite(IgniteCacheInvokeReadThroughSingleNodeTest.class);
-        suite.addTestSuite(IgniteCacheInvokeReadThroughTest.class);
-        suite.addTestSuite(IgniteCacheReadThroughStoreCallTest.class);
-        suite.addTestSuite(GridCacheVersionMultinodeTest.class);
+        addTestIfNeeded(suite, IgniteCacheInvokeReadThroughSingleNodeTest.class, ignoredTests);
+        addTestIfNeeded(suite, IgniteCacheInvokeReadThroughTest.class, ignoredTests);
+        addTestIfNeeded(suite, IgniteCacheReadThroughStoreCallTest.class, ignoredTests);
+        addTestIfNeeded(suite, GridCacheVersionMultinodeTest.class, ignoredTests);
 
-        suite.addTestSuite(IgniteCacheNearReadCommittedTest.class);
-        suite.addTestSuite(IgniteCacheAtomicCopyOnReadDisabledTest.class);
-        suite.addTestSuite(IgniteCacheTxCopyOnReadDisabledTest.class);
+        addTestIfNeeded(suite, IgniteCacheNearReadCommittedTest.class, ignoredTests);
+        addTestIfNeeded(suite, IgniteCacheAtomicCopyOnReadDisabledTest.class, ignoredTests);
+        addTestIfNeeded(suite, IgniteCacheTxCopyOnReadDisabledTest.class, ignoredTests);
 
-        suite.addTestSuite(IgniteCacheTxPreloadNoWriteTest.class);
+        addTestIfNeeded(suite, IgniteCacheTxPreloadNoWriteTest.class, ignoredTests);
 
-        suite.addTestSuite(IgniteDynamicCacheStartSelfTest.class);
-        suite.addTestSuite(IgniteDynamicCacheMultinodeTest.class);
-        suite.addTestSuite(IgniteDynamicCacheStartFailTest.class);
-        suite.addTestSuite(IgniteDynamicCacheStartCoordinatorFailoverTest.class);
-        suite.addTestSuite(IgniteDynamicCacheWithConfigStartSelfTest.class);
-        suite.addTestSuite(IgniteCacheDynamicStopSelfTest.class);
-        suite.addTestSuite(IgniteDynamicCacheStartStopConcurrentTest.class);
-        suite.addTestSuite(IgniteCacheConfigurationTemplateTest.class);
-        suite.addTestSuite(IgniteCacheConfigurationDefaultTemplateTest.class);
-        suite.addTestSuite(IgniteDynamicClientCacheStartSelfTest.class);
-        suite.addTestSuite(IgniteDynamicCacheStartNoExchangeTimeoutTest.class);
-        suite.addTestSuite(CacheAffinityEarlyTest.class);
-        suite.addTestSuite(IgniteCacheCreatePutMultiNodeSelfTest.class);
-        suite.addTestSuite(IgniteCacheCreatePutTest.class);
-        suite.addTestSuite(CacheStartOnJoinTest.class);
-        suite.addTestSuite(IgniteCacheStartTest.class);
-        suite.addTestSuite(CacheDiscoveryDataConcurrentJoinTest.class);
-        suite.addTestSuite(IgniteClientCacheInitializationFailTest.class);
-        suite.addTestSuite(IgniteCacheFailedUpdateResponseTest.class);
+        addTestIfNeeded(suite, IgniteDynamicCacheStartSelfTest.class, ignoredTests);
+        addTestIfNeeded(suite, IgniteDynamicCacheMultinodeTest.class, ignoredTests);
+        addTestIfNeeded(suite, IgniteDynamicCacheStartFailTest.class, ignoredTests);
+        addTestIfNeeded(suite, IgniteDynamicCacheStartCoordinatorFailoverTest.class, ignoredTests);
+        addTestIfNeeded(suite, IgniteDynamicCacheWithConfigStartSelfTest.class, ignoredTests);
+        addTestIfNeeded(suite, IgniteCacheDynamicStopSelfTest.class, ignoredTests);
+        addTestIfNeeded(suite, IgniteDynamicCacheStartStopConcurrentTest.class, ignoredTests);
+        addTestIfNeeded(suite, IgniteCacheConfigurationTemplateTest.class, ignoredTests);
+        addTestIfNeeded(suite, IgniteCacheConfigurationDefaultTemplateTest.class, ignoredTests);
+        addTestIfNeeded(suite, IgniteDynamicClientCacheStartSelfTest.class, ignoredTests);
+        addTestIfNeeded(suite, IgniteDynamicCacheStartNoExchangeTimeoutTest.class, ignoredTests);
+        addTestIfNeeded(suite, CacheAffinityEarlyTest.class, ignoredTests);
+        addTestIfNeeded(suite, IgniteCacheCreatePutMultiNodeSelfTest.class, ignoredTests);
+        addTestIfNeeded(suite, IgniteCacheCreatePutTest.class, ignoredTests);
+        addTestIfNeeded(suite, CacheStartOnJoinTest.class, ignoredTests);
+        addTestIfNeeded(suite, IgniteCacheStartTest.class, ignoredTests);
+        addTestIfNeeded(suite, CacheDiscoveryDataConcurrentJoinTest.class, ignoredTests);
+        addTestIfNeeded(suite, IgniteClientCacheInitializationFailTest.class, ignoredTests);
+        addTestIfNeeded(suite, IgniteCacheFailedUpdateResponseTest.class, ignoredTests);
 
-        suite.addTestSuite(GridCacheTxLoadFromStoreOnLockSelfTest.class);
+        addTestIfNeeded(suite, GridCacheTxLoadFromStoreOnLockSelfTest.class, ignoredTests);
 
-        suite.addTestSuite(GridCacheMarshallingNodeJoinSelfTest.class);
+        addTestIfNeeded(suite, GridCacheMarshallingNodeJoinSelfTest.class, ignoredTests);
 
-        suite.addTestSuite(IgniteCacheJdbcBlobStoreNodeRestartTest.class);
+        addTestIfNeeded(suite, IgniteCacheJdbcBlobStoreNodeRestartTest.class, ignoredTests);
 
-        suite.addTestSuite(IgniteCacheAtomicLocalStoreValueTest.class);
-        suite.addTestSuite(IgniteCacheAtomicStoreValueTest.class);
-        suite.addTestSuite(IgniteCacheAtomicNearEnabledStoreValueTest.class);
-        suite.addTestSuite(IgniteCacheTxLocalStoreValueTest.class);
-        suite.addTestSuite(IgniteCacheTxStoreValueTest.class);
-        suite.addTestSuite(IgniteCacheTxNearEnabledStoreValueTest.class);
+        addTestIfNeeded(suite, IgniteCacheAtomicLocalStoreValueTest.class, ignoredTests);
+        addTestIfNeeded(suite, IgniteCacheAtomicStoreValueTest.class, ignoredTests);
+        addTestIfNeeded(suite, IgniteCacheAtomicNearEnabledStoreValueTest.class, ignoredTests);
+        addTestIfNeeded(suite, IgniteCacheTxLocalStoreValueTest.class, ignoredTests);
+        addTestIfNeeded(suite, IgniteCacheTxStoreValueTest.class, ignoredTests);
+        addTestIfNeeded(suite, IgniteCacheTxNearEnabledStoreValueTest.class, ignoredTests);
 
-        suite.addTestSuite(IgniteCacheLockFailoverSelfTest.class);
-        suite.addTestSuite(IgniteCacheMultiTxLockSelfTest.class);
+        addTestIfNeeded(suite, IgniteCacheLockFailoverSelfTest.class, ignoredTests);
+        addTestIfNeeded(suite, IgniteCacheMultiTxLockSelfTest.class, ignoredTests);
 
-        suite.addTestSuite(IgniteInternalCacheTypesTest.class);
+        addTestIfNeeded(suite, IgniteInternalCacheTypesTest.class, ignoredTests);
 
-        suite.addTestSuite(IgniteExchangeFutureHistoryTest.class);
+        addTestIfNeeded(suite, IgniteExchangeFutureHistoryTest.class, ignoredTests);
 
-        suite.addTestSuite(CacheNoValueClassOnServerNodeTest.class);
-        suite.addTestSuite(IgniteSystemCacheOnClientTest.class);
+        addTestIfNeeded(suite, CacheNoValueClassOnServerNodeTest.class, ignoredTests);
+        addTestIfNeeded(suite, IgniteSystemCacheOnClientTest.class, ignoredTests);
 
-        suite.addTestSuite(CacheRemoveAllSelfTest.class);
-        suite.addTestSuite(CacheGetEntryOptimisticReadCommittedSeltTest.class);
-        suite.addTestSuite(CacheGetEntryOptimisticRepeatableReadSeltTest.class);
-        suite.addTestSuite(CacheGetEntryOptimisticSerializableSeltTest.class);
-        suite.addTestSuite(CacheGetEntryPessimisticReadCommittedSeltTest.class);
-        suite.addTestSuite(CacheGetEntryPessimisticRepeatableReadSeltTest.class);
-        suite.addTestSuite(CacheGetEntryPessimisticSerializableSeltTest.class);
-        suite.addTestSuite(CacheTxNotAllowReadFromBackupTest.class);
+        addTestIfNeeded(suite, CacheRemoveAllSelfTest.class, ignoredTests);
+        addTestIfNeeded(suite, CacheGetEntryOptimisticReadCommittedSelfTest.class, ignoredTests);
+        addTestIfNeeded(suite, CacheGetEntryOptimisticRepeatableReadSelfTest.class, ignoredTests);
+        addTestIfNeeded(suite, CacheGetEntryOptimisticSerializableSelfTest.class, ignoredTests);
+        addTestIfNeeded(suite, CacheGetEntryPessimisticReadCommittedSelfTest.class, ignoredTests);
+        addTestIfNeeded(suite, CacheGetEntryPessimisticRepeatableReadSelfTest.class, ignoredTests);
+        addTestIfNeeded(suite, CacheGetEntryPessimisticSerializableSelfTest.class, ignoredTests);
+        addTestIfNeeded(suite, CacheTxNotAllowReadFromBackupTest.class, ignoredTests);
 
-        suite.addTestSuite(CacheStopAndDestroySelfTest.class);
+        addTestIfNeeded(suite, CacheStopAndDestroySelfTest.class, ignoredTests);
 
-        suite.addTestSuite(CacheOffheapMapEntrySelfTest.class);
+        addTestIfNeeded(suite, CacheOffheapMapEntrySelfTest.class, ignoredTests);
 
-        suite.addTestSuite(CacheJdbcStoreSessionListenerSelfTest.class);
-        suite.addTestSuite(CacheStoreSessionListenerLifecycleSelfTest.class);
-        suite.addTestSuite(CacheStoreListenerRWThroughDisabledAtomicCacheTest.class);
-        suite.addTestSuite(CacheStoreListenerRWThroughDisabledTransactionalCacheTest.class);
-        suite.addTestSuite(CacheStoreSessionListenerWriteBehindEnabledTest.class);
+        addTestIfNeeded(suite, CacheJdbcStoreSessionListenerSelfTest.class, ignoredTests);
+        addTestIfNeeded(suite, CacheStoreSessionListenerLifecycleSelfTest.class, ignoredTests);
+        addTestIfNeeded(suite, CacheStoreListenerRWThroughDisabledAtomicCacheTest.class, ignoredTests);
+        addTestIfNeeded(suite, CacheStoreListenerRWThroughDisabledTransactionalCacheTest.class, ignoredTests);
+        addTestIfNeeded(suite, CacheStoreSessionListenerWriteBehindEnabledTest.class, ignoredTests);
 
-        suite.addTestSuite(CacheClientStoreSelfTest.class);
-        suite.addTestSuite(CacheStoreUsageMultinodeStaticStartAtomicTest.class);
-        suite.addTestSuite(CacheStoreUsageMultinodeStaticStartTxTest.class);
-        suite.addTestSuite(CacheStoreUsageMultinodeDynamicStartAtomicTest.class);
-        suite.addTestSuite(CacheStoreUsageMultinodeDynamicStartTxTest.class);
-        suite.addTestSuite(CacheConnectionLeakStoreTxTest.class);
+        addTestIfNeeded(suite, CacheClientStoreSelfTest.class, ignoredTests);
+        addTestIfNeeded(suite, CacheStoreUsageMultinodeStaticStartAtomicTest.class, ignoredTests);
+        addTestIfNeeded(suite, CacheStoreUsageMultinodeStaticStartTxTest.class, ignoredTests);
+        addTestIfNeeded(suite, CacheStoreUsageMultinodeDynamicStartAtomicTest.class, ignoredTests);
+        addTestIfNeeded(suite, CacheStoreUsageMultinodeDynamicStartTxTest.class, ignoredTests);
+        addTestIfNeeded(suite, CacheConnectionLeakStoreTxTest.class, ignoredTests);
 
-        suite.addTestSuite(GridCacheStoreManagerDeserializationTest.class);
-        suite.addTestSuite(GridLocalCacheStoreManagerDeserializationTest.class);
+        addTestIfNeeded(suite, GridCacheStoreManagerDeserializationTest.class, ignoredTests);
+        addTestIfNeeded(suite, GridLocalCacheStoreManagerDeserializationTest.class, ignoredTests);
 
-        suite.addTestSuite(IgniteStartCacheInTransactionSelfTest.class);
-        suite.addTestSuite(IgniteStartCacheInTransactionAtomicSelfTest.class);
+        addTestIfNeeded(suite, IgniteStartCacheInTransactionSelfTest.class, ignoredTests);
+        addTestIfNeeded(suite, IgniteStartCacheInTransactionAtomicSelfTest.class, ignoredTests);
 
-        suite.addTestSuite(CacheReadThroughRestartSelfTest.class);
-        suite.addTestSuite(CacheReadThroughReplicatedRestartSelfTest.class);
-        suite.addTestSuite(CacheReadThroughReplicatedAtomicRestartSelfTest.class);
-        suite.addTestSuite(CacheReadThroughLocalRestartSelfTest.class);
-        suite.addTestSuite(CacheReadThroughLocalAtomicRestartSelfTest.class);
-        suite.addTestSuite(CacheReadThroughAtomicRestartSelfTest.class);
+        addTestIfNeeded(suite, CacheReadThroughRestartSelfTest.class, ignoredTests);
+        addTestIfNeeded(suite, CacheReadThroughReplicatedRestartSelfTest.class, ignoredTests);
+        addTestIfNeeded(suite, CacheReadThroughReplicatedAtomicRestartSelfTest.class, ignoredTests);
+        addTestIfNeeded(suite, CacheReadThroughLocalRestartSelfTest.class, ignoredTests);
+        addTestIfNeeded(suite, CacheReadThroughLocalAtomicRestartSelfTest.class, ignoredTests);
+        addTestIfNeeded(suite, CacheReadThroughAtomicRestartSelfTest.class, ignoredTests);
 
         // Versioned entry tests
-        suite.addTestSuite(CacheVersionedEntryLocalAtomicSwapDisabledSelfTest.class);
-        suite.addTestSuite(CacheVersionedEntryLocalTransactionalSelfTest.class);
-        suite.addTestSuite(CacheVersionedEntryPartitionedAtomicSelfTest.class);
-        suite.addTestSuite(CacheVersionedEntryPartitionedTransactionalSelfTest.class);
-        suite.addTestSuite(CacheVersionedEntryReplicatedAtomicSelfTest.class);
-        suite.addTestSuite(CacheVersionedEntryReplicatedTransactionalSelfTest.class);
+        addTestIfNeeded(suite, CacheVersionedEntryLocalAtomicSwapDisabledSelfTest.class, ignoredTests);
+        addTestIfNeeded(suite, CacheVersionedEntryLocalTransactionalSelfTest.class, ignoredTests);
+        addTestIfNeeded(suite, CacheVersionedEntryPartitionedAtomicSelfTest.class, ignoredTests);
+        addTestIfNeeded(suite, CacheVersionedEntryPartitionedTransactionalSelfTest.class, ignoredTests);
+        addTestIfNeeded(suite, CacheVersionedEntryReplicatedAtomicSelfTest.class, ignoredTests);
+        addTestIfNeeded(suite, CacheVersionedEntryReplicatedTransactionalSelfTest.class, ignoredTests);
 
-        suite.addTestSuite(GridCacheDhtTxPreloadSelfTest.class);
-        suite.addTestSuite(GridCacheNearTxPreloadSelfTest.class);
-        suite.addTestSuite(GridReplicatedTxPreloadTest.class);
-        suite.addTestSuite(CacheGroupsPreloadTest.class);
+        addTestIfNeeded(suite, GridCacheDhtTxPreloadSelfTest.class, ignoredTests);
+        addTestIfNeeded(suite, GridCacheNearTxPreloadSelfTest.class, ignoredTests);
+        addTestIfNeeded(suite, GridReplicatedTxPreloadTest.class, ignoredTests);
+        addTestIfNeeded(suite, CacheGroupsPreloadTest.class, ignoredTests);
 
-        suite.addTestSuite(IgniteDynamicCacheFilterTest.class);
+        addTestIfNeeded(suite, IgniteDynamicCacheFilterTest.class, ignoredTests);
 
-        suite.addTestSuite(CrossCacheLockTest.class);
-        suite.addTestSuite(IgniteCrossCacheTxSelfTest.class);
+        addTestIfNeeded(suite, CrossCacheLockTest.class, ignoredTests);
+        addTestIfNeeded(suite, IgniteCrossCacheTxSelfTest.class, ignoredTests);
 
-        suite.addTestSuite(CacheGetFutureHangsSelfTest.class);
+        addTestIfNeeded(suite, CacheGetFutureHangsSelfTest.class, ignoredTests);
 
-        suite.addTestSuite(IgniteCacheSingleGetMessageTest.class);
-        suite.addTestSuite(IgniteCacheReadFromBackupTest.class);
+        addTestIfNeeded(suite, IgniteCacheSingleGetMessageTest.class, ignoredTests);
+        addTestIfNeeded(suite, IgniteCacheReadFromBackupTest.class, ignoredTests);
 
-        suite.addTestSuite(MarshallerCacheJobRunNodeRestartTest.class);
+        addTestIfNeeded(suite, MarshallerCacheJobRunNodeRestartTest.class, ignoredTests);
 
-        suite.addTestSuite(IgniteCacheNearOnlyTxTest.class);
+        addTestIfNeeded(suite, IgniteCacheNearOnlyTxTest.class, ignoredTests);
 
-        suite.addTestSuite(IgniteCacheContainsKeyAtomicTest.class);
+        addTestIfNeeded(suite, IgniteCacheContainsKeyAtomicTest.class, ignoredTests);
 
-        suite.addTestSuite(CacheResultIsNotNullOnPartitionLossTest.class);
+        addTestIfNeeded(suite, CacheResultIsNotNullOnPartitionLossTest.class, ignoredTests);
 
-        suite.addTestSuite(CashEventWithTxLabelTest.class);
+        addTestIfNeeded(suite, CacheEventWithTxLabelTest.class, ignoredTests);
 
         return suite;
     }
diff --git a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite5.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite5.java
index 8776901..7bbc4ab 100644
--- a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite5.java
+++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite5.java
@@ -17,6 +17,7 @@
 
 package org.apache.ignite.testsuites;
 
+import java.util.HashSet;
 import junit.framework.TestSuite;
 import org.apache.ignite.GridCacheAffinityBackupsSelfTest;
 import org.apache.ignite.IgniteCacheAffinitySelfTest;
@@ -48,6 +49,7 @@
 import org.apache.ignite.internal.processors.cache.distributed.rebalancing.CacheManualRebalancingTest;
 import org.apache.ignite.internal.processors.cache.distributed.replicated.IgniteCacheSyncRebalanceModeSelfTest;
 import org.apache.ignite.internal.processors.cache.store.IgniteCacheWriteBehindNoUpdateSelfTest;
+import org.apache.ignite.testframework.GridTestUtils;
 
 /**
  * Test suite.
@@ -55,57 +57,66 @@
 public class IgniteCacheTestSuite5 extends TestSuite {
     /**
      * @return IgniteCache test suite.
-     * @throws Exception Thrown in case of the failure.
      */
-    public static TestSuite suite() throws Exception {
+    public static TestSuite suite() {
+        return suite(null);
+    }
+
+    /**
+     * @param ignoredTests Ignored tests.
+     * @return IgniteCache test suite.
+     */
+    public static TestSuite suite(HashSet<Class> ignoredTests) {
         TestSuite suite = new TestSuite("IgniteCache Test Suite part 5");
 
-        suite.addTestSuite(CacheSerializableTransactionsTest.class);
-        suite.addTestSuite(CacheNearReaderUpdateTest.class);
-        suite.addTestSuite(IgniteCacheStoreCollectionTest.class);
-        suite.addTestSuite(IgniteCacheWriteBehindNoUpdateSelfTest.class);
-        suite.addTestSuite(IgniteCachePutStackOverflowSelfTest.class);
-        suite.addTestSuite(CacheKeepBinaryTransactionTest.class);
+        GridTestUtils.addTestIfNeeded(suite,CacheSerializableTransactionsTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite,CacheNearReaderUpdateTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite,IgniteCacheStoreCollectionTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite,IgniteCacheWriteBehindNoUpdateSelfTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite,IgniteCachePutStackOverflowSelfTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite,CacheKeepBinaryTransactionTest.class, ignoredTests);
 
-        suite.addTestSuite(CacheLateAffinityAssignmentTest.class);
-        suite.addTestSuite(CacheLateAffinityAssignmentNodeJoinValidationTest.class);
-        suite.addTestSuite(EntryVersionConsistencyReadThroughTest.class);
-        suite.addTestSuite(IgniteCacheSyncRebalanceModeSelfTest.class);
+        GridTestUtils.addTestIfNeeded(suite,CacheLateAffinityAssignmentTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite,CacheLateAffinityAssignmentNodeJoinValidationTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite,EntryVersionConsistencyReadThroughTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite,IgniteCacheSyncRebalanceModeSelfTest.class, ignoredTests);
 
         suite.addTest(IgniteCacheReadThroughEvictionsVariationsSuite.suite());
-        suite.addTestSuite(IgniteCacheTxIteratorSelfTest.class);
 
-        suite.addTestSuite(ClusterStatePartitionedSelfTest.class);
-        suite.addTestSuite(ClusterStateReplicatedSelfTest.class);
-        suite.addTestSuite(ClusterReadOnlyModeTest.class);
-        suite.addTestSuite(IgniteCachePartitionLossPolicySelfTest.class);
-        suite.addTestSuite(IgniteCacheGroupsPartitionLossPolicySelfTest.class);
+        GridTestUtils.addTestIfNeeded(suite,IgniteCacheTxIteratorSelfTest.class, ignoredTests);
 
-        suite.addTestSuite(CacheRebalancingSelfTest.class);
-        suite.addTestSuite(CacheManualRebalancingTest.class);
+        GridTestUtils.addTestIfNeeded(suite,ClusterStatePartitionedSelfTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite,ClusterStateReplicatedSelfTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite,ClusterReadOnlyModeTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite,IgniteCachePartitionLossPolicySelfTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite,IgniteCacheGroupsPartitionLossPolicySelfTest.class, ignoredTests);
+
+        GridTestUtils.addTestIfNeeded(suite,CacheRebalancingSelfTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite,CacheManualRebalancingTest.class, ignoredTests);
 
         // Affinity tests.
-        suite.addTestSuite(GridCacheAffinityBackupsSelfTest.class);
-        suite.addTestSuite(IgniteCacheAffinitySelfTest.class);
-        suite.addTestSuite(AffinityClientNodeSelfTest.class);
-        suite.addTestSuite(LocalAffinityFunctionTest.class);
-        suite.addTestSuite(AffinityHistoryCleanupTest.class);
+        GridTestUtils.addTestIfNeeded(suite,GridCacheAffinityBackupsSelfTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite,IgniteCacheAffinitySelfTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite,AffinityClientNodeSelfTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite,LocalAffinityFunctionTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite,AffinityHistoryCleanupTest.class, ignoredTests);
 
-        suite.addTestSuite(AffinityDistributionLoggingTest.class);
+        GridTestUtils.addTestIfNeeded(suite,AffinityDistributionLoggingTest.class, ignoredTests);
 
-        suite.addTestSuite(IgniteCacheAtomicProtocolTest.class);
+        GridTestUtils.addTestIfNeeded(suite,IgniteCacheAtomicProtocolTest.class, ignoredTests);
 
-        suite.addTestSuite(PartitionsExchangeOnDiscoveryHistoryOverflowTest.class);
+        GridTestUtils.addTestIfNeeded(suite,PartitionsExchangeOnDiscoveryHistoryOverflowTest.class, ignoredTests);
 
-        suite.addTestSuite(GridCachePartitionExchangeManagerHistSizeTest.class);
+        GridTestUtils.addTestIfNeeded(suite,GridCachePartitionExchangeManagerHistSizeTest.class, ignoredTests);
 
-        suite.addTestSuite(NotMappedPartitionInTxTest.class);
+        GridTestUtils.addTestIfNeeded(suite,NotMappedPartitionInTxTest.class, ignoredTests);
 
-        suite.addTestSuite(ConcurrentCacheStartTest.class);
+        GridTestUtils.addTestIfNeeded(suite,ConcurrentCacheStartTest.class, ignoredTests);
 
-        //suite.addTestSuite(GridCacheAtomicPreloadSelfTest.class);
-        //suite.addTestSuite(IgniteCacheContainsKeyColocatedAtomicSelfTest.class);
-        //suite.addTestSuite(IgniteCacheContainsKeyNearAtomicSelfTest.class);
+        //GridTestUtils.addTestIfNeeded(suite,GridCacheAtomicPreloadSelfTest.class, ignoredTests);
+        //GridTestUtils.addTestIfNeeded(suite,IgniteCacheContainsKeyColocatedAtomicSelfTest.class, ignoredTests);
+        //GridTestUtils.addTestIfNeeded(suite,IgniteCacheContainsKeyNearAtomicSelfTest.class, ignoredTests);
+
         return suite;
     }
 }
diff --git a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite6.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite6.java
index 03cfb9f..c55eb9f 100644
--- a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite6.java
+++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite6.java
@@ -17,6 +17,7 @@
 
 package org.apache.ignite.testsuites;
 
+import java.util.Collection;
 import junit.framework.TestSuite;
 import org.apache.ignite.internal.processors.cache.CacheNoAffinityExchangeTest;
 import org.apache.ignite.internal.processors.cache.PartitionedAtomicCacheGetsDistributionTest;
@@ -49,6 +50,7 @@
 import org.apache.ignite.internal.processors.cache.transactions.TxRollbackOnTimeoutTest;
 import org.apache.ignite.internal.processors.cache.transactions.TxRollbackOnTopologyChangeTest;
 import org.apache.ignite.internal.processors.cache.transactions.TxStateChangeEventTest;
+import org.apache.ignite.testframework.GridTestUtils;
 
 /**
  * Test suite.
@@ -56,63 +58,70 @@
 public class IgniteCacheTestSuite6 extends TestSuite {
     /**
      * @return IgniteCache test suite.
-     * @throws Exception Thrown in case of the failure.
      */
-    public static TestSuite suite() throws Exception {
+    public static TestSuite suite() {
+        return suite(null);
+    }
+
+    /**
+     * @param ignoredTests Ignored tests.
+     * @return IgniteCache test suite.
+     */
+    public static TestSuite suite(Collection<Class> ignoredTests) {
         TestSuite suite = new TestSuite("IgniteCache Test Suite part 6");
 
-        suite.addTestSuite(GridCachePartitionEvictionDuringReadThroughSelfTest.class);
-        suite.addTestSuite(IgniteOptimisticTxSuspendResumeTest.class);
-        suite.addTestSuite(IgnitePessimisticTxSuspendResumeTest.class);
+        GridTestUtils.addTestIfNeeded(suite, GridCachePartitionEvictionDuringReadThroughSelfTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite, IgniteOptimisticTxSuspendResumeTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite, IgnitePessimisticTxSuspendResumeTest.class, ignoredTests);
 
-        suite.addTestSuite(CacheExchangeMergeTest.class);
+        GridTestUtils.addTestIfNeeded(suite, CacheExchangeMergeTest.class, ignoredTests);
 
-        suite.addTestSuite(TxRollbackOnTimeoutTest.class);
-        suite.addTestSuite(TxRollbackOnTimeoutNoDeadlockDetectionTest.class);
-        suite.addTestSuite(TxRollbackOnTimeoutNearCacheTest.class);
-        suite.addTestSuite(IgniteCacheThreadLocalTxTest.class);
-        suite.addTestSuite(TxRollbackAsyncTest.class);
-        suite.addTestSuite(TxRollbackAsyncNearCacheTest.class);
-        suite.addTestSuite(TxRollbackOnTopologyChangeTest.class);
-        suite.addTestSuite(TxRollbackOnTimeoutOnePhaseCommitTest.class);
+        GridTestUtils.addTestIfNeeded(suite, TxRollbackOnTimeoutTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite, TxRollbackOnTimeoutNoDeadlockDetectionTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite, TxRollbackOnTimeoutNearCacheTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite, IgniteCacheThreadLocalTxTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite, TxRollbackAsyncTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite, TxRollbackAsyncNearCacheTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite, TxRollbackOnTopologyChangeTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite, TxRollbackOnTimeoutOnePhaseCommitTest.class, ignoredTests);
 
-        suite.addTestSuite(TxOptimisticPrepareOnUnstableTopologyTest.class);
+        GridTestUtils.addTestIfNeeded(suite, TxOptimisticPrepareOnUnstableTopologyTest.class, ignoredTests);
 
-        suite.addTestSuite(TxLabelTest.class);
-        suite.addTestSuite(TxRollbackOnIncorrectParamsTest.class);
-        suite.addTestSuite(TxStateChangeEventTest.class);
+        GridTestUtils.addTestIfNeeded(suite, TxLabelTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite, TxRollbackOnIncorrectParamsTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite, TxStateChangeEventTest.class, ignoredTests);
 
-        suite.addTestSuite(TxMultiCacheAsyncOpsTest.class);
+        GridTestUtils.addTestIfNeeded(suite, TxMultiCacheAsyncOpsTest.class, ignoredTests);
 
-        suite.addTestSuite(TxOnCachesStartTest.class);
+        GridTestUtils.addTestIfNeeded(suite, TxOnCachesStartTest.class, ignoredTests);
 
-        suite.addTestSuite(IgniteCache150ClientsTest.class);
+        GridTestUtils.addTestIfNeeded(suite, IgniteCache150ClientsTest.class, ignoredTests);
 
 //        TODO enable this test after IGNITE-6753, now it takes too long
-//        suite.addTestSuite(IgniteOutOfMemoryPropagationTest.class);
+//        GridTestUtils.addTestIfNeeded(suite, IgniteOutOfMemoryPropagationTest.class, ignoredTests);
 
-        suite.addTestSuite(ReplicatedAtomicCacheGetsDistributionTest.class);
-        suite.addTestSuite(ReplicatedTransactionalOptimisticCacheGetsDistributionTest.class);
-        suite.addTestSuite(ReplicatedTransactionalPessimisticCacheGetsDistributionTest.class);
+        GridTestUtils.addTestIfNeeded(suite, ReplicatedAtomicCacheGetsDistributionTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite, ReplicatedTransactionalOptimisticCacheGetsDistributionTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite, ReplicatedTransactionalPessimisticCacheGetsDistributionTest.class, ignoredTests);
 
-        suite.addTestSuite(PartitionedAtomicCacheGetsDistributionTest.class);
-        suite.addTestSuite(PartitionedTransactionalOptimisticCacheGetsDistributionTest.class);
-        suite.addTestSuite(PartitionedTransactionalPessimisticCacheGetsDistributionTest.class);
+        GridTestUtils.addTestIfNeeded(suite, PartitionedAtomicCacheGetsDistributionTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite, PartitionedTransactionalOptimisticCacheGetsDistributionTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite, PartitionedTransactionalPessimisticCacheGetsDistributionTest.class, ignoredTests);
 
-        suite.addTestSuite(TxOptimisticOnPartitionExchangeTest.class);
+        GridTestUtils.addTestIfNeeded(suite, TxOptimisticOnPartitionExchangeTest.class, ignoredTests);
 
-        suite.addTestSuite(IgniteExchangeLatchManagerCoordinatorFailTest.class);
+        GridTestUtils.addTestIfNeeded(suite, IgniteExchangeLatchManagerCoordinatorFailTest.class, ignoredTests);
 
-        suite.addTestSuite(PartitionsExchangeCoordinatorFailoverTest.class);
-        suite.addTestSuite(CacheTryLockMultithreadedTest.class);
+        GridTestUtils.addTestIfNeeded(suite, PartitionsExchangeCoordinatorFailoverTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite, CacheTryLockMultithreadedTest.class, ignoredTests);
 
-        suite.addTestSuite(CacheParallelStartTest.class);
+        GridTestUtils.addTestIfNeeded(suite, CacheParallelStartTest.class, ignoredTests);
 
-        suite.addTestSuite(CacheNoAffinityExchangeTest.class);
+        GridTestUtils.addTestIfNeeded(suite, CacheNoAffinityExchangeTest.class, ignoredTests);
 
-        //suite.addTestSuite(CacheClientsConcurrentStartTest.class);
-        //suite.addTestSuite(GridCacheRebalancingOrderingTest.class);
-        //suite.addTestSuite(IgniteCacheClientMultiNodeUpdateTopologyLockTest.class);
+        //GridTestUtils.addTestIfNeeded(suite, CacheClientsConcurrentStartTest.class, ignoredTests);
+        //GridTestUtils.addTestIfNeeded(suite, GridCacheRebalancingOrderingTest.class, ignoredTests);
+        //GridTestUtils.addTestIfNeeded(suite, IgniteCacheClientMultiNodeUpdateTopologyLockTest.class, ignoredTests);
 
         return suite;
     }
diff --git a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite7.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite7.java
index d0734a8..f7e1020 100755
--- a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite7.java
+++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite7.java
@@ -34,7 +34,6 @@
 import org.apache.ignite.internal.processors.cache.WalModeChangeSelfTest;
 import org.apache.ignite.internal.processors.cache.distributed.Cache64kPartitionsTest;
 import org.apache.ignite.internal.processors.cache.distributed.CacheDataLossOnPartitionMoveTest;
-import org.apache.ignite.internal.processors.cache.distributed.CachePageWriteLockUnlockTest;
 import org.apache.ignite.internal.processors.cache.distributed.CacheRentingStateRepairTest;
 import org.apache.ignite.internal.processors.cache.distributed.dht.IgniteCacheStartWithLoadTest;
 import org.apache.ignite.internal.processors.cache.distributed.rebalancing.GridCacheRebalancingPartitionCountersTest;
@@ -45,6 +44,7 @@
 import org.apache.ignite.internal.processors.cache.transactions.TransactionIntegrityWithPrimaryIndexCorruptionTest;
 import org.apache.ignite.internal.processors.cache.transactions.TxRollbackAsyncWithPersistenceTest;
 import org.apache.ignite.internal.processors.cache.transactions.TxWithSmallTimeoutAndContentionOneKeyTest;
+import org.apache.ignite.testframework.GridTestUtils;
 
 /**
  * Test suite.
@@ -63,46 +63,44 @@
      * @return Test suite.
      * @throws Exception Thrown in case of the failure.
      */
-    public static TestSuite suite(Set<Class> ignoredTests) throws Exception {
+    public static TestSuite suite(Set<Class> ignoredTests) {
         TestSuite suite = new TestSuite("IgniteCache With Persistence Test Suite");
 
-        suite.addTestSuite(CheckpointBufferDeadlockTest.class);
-        suite.addTestSuite(IgniteCacheStartWithLoadTest.class);
+        GridTestUtils.addTestIfNeeded(suite, CheckpointBufferDeadlockTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite, IgniteCacheStartWithLoadTest.class, ignoredTests);
 
-        suite.addTestSuite(AuthenticationConfigurationClusterTest.class);
-        suite.addTestSuite(AuthenticationProcessorSelfTest.class);
-        suite.addTestSuite(AuthenticationOnNotActiveClusterTest.class);
-        suite.addTestSuite(AuthenticationProcessorNodeRestartTest.class);
-        suite.addTestSuite(AuthenticationProcessorNPEOnStartTest.class);
-        suite.addTestSuite(Authentication1kUsersNodeRestartTest.class);
+        GridTestUtils.addTestIfNeeded(suite, AuthenticationConfigurationClusterTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite, AuthenticationProcessorSelfTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite, AuthenticationOnNotActiveClusterTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite, AuthenticationProcessorNodeRestartTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite, AuthenticationProcessorNPEOnStartTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite, Authentication1kUsersNodeRestartTest.class, ignoredTests);
 
-        suite.addTestSuite(CacheDataRegionConfigurationTest.class);
+        GridTestUtils.addTestIfNeeded(suite, CacheDataRegionConfigurationTest.class, ignoredTests);
 
-        suite.addTestSuite(WalModeChangeAdvancedSelfTest.class);
-        suite.addTestSuite(WalModeChangeSelfTest.class);
-        suite.addTestSuite(WalModeChangeCoordinatorNotAffinityNodeSelfTest.class);
+        GridTestUtils.addTestIfNeeded(suite, WalModeChangeAdvancedSelfTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite, WalModeChangeSelfTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite, WalModeChangeCoordinatorNotAffinityNodeSelfTest.class, ignoredTests);
 
-        suite.addTestSuite(Cache64kPartitionsTest.class);
-        suite.addTestSuite(GridCacheRebalancingPartitionCountersTest.class);
-        suite.addTestSuite(GridCacheRebalancingWithAsyncClearingTest.class);
+        GridTestUtils.addTestIfNeeded(suite, Cache64kPartitionsTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite, GridCacheRebalancingPartitionCountersTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite, GridCacheRebalancingWithAsyncClearingTest.class, ignoredTests);
 
-        suite.addTestSuite(IgnitePdsCacheAssignmentNodeRestartsTest.class);
-        suite.addTestSuite(TxRollbackAsyncWithPersistenceTest.class);
+        GridTestUtils.addTestIfNeeded(suite, IgnitePdsCacheAssignmentNodeRestartsTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite, TxRollbackAsyncWithPersistenceTest.class, ignoredTests);
 
-        suite.addTestSuite(CacheGroupMetricsMBeanTest.class);
-        suite.addTestSuite(CacheMetricsManageTest.class);
-        suite.addTestSuite(PageEvictionMultinodeMixedRegionsTest.class);
+        GridTestUtils.addTestIfNeeded(suite, CacheGroupMetricsMBeanTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite, CacheMetricsManageTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite, PageEvictionMultinodeMixedRegionsTest.class, ignoredTests);
 
-        suite.addTestSuite(IgniteDynamicCacheStartFailWithPersistenceTest.class);
+        GridTestUtils.addTestIfNeeded(suite, IgniteDynamicCacheStartFailWithPersistenceTest.class, ignoredTests);
 
-        suite.addTestSuite(TxWithSmallTimeoutAndContentionOneKeyTest.class);
+        GridTestUtils.addTestIfNeeded(suite, TxWithSmallTimeoutAndContentionOneKeyTest.class, ignoredTests);
 
-        suite.addTestSuite(CacheRentingStateRepairTest.class);
+        GridTestUtils.addTestIfNeeded(suite, CacheRentingStateRepairTest.class, ignoredTests);
 
-        suite.addTestSuite(TransactionIntegrityWithPrimaryIndexCorruptionTest.class);
-        suite.addTestSuite(CacheDataLossOnPartitionMoveTest.class);
-
-        suite.addTestSuite(CachePageWriteLockUnlockTest.class);
+        GridTestUtils.addTestIfNeeded(suite, TransactionIntegrityWithPrimaryIndexCorruptionTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite, CacheDataLossOnPartitionMoveTest.class, ignoredTests);
 
         return suite;
     }
diff --git a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite9.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite9.java
index 157673e..23d71c1 100644
--- a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite9.java
+++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite9.java
@@ -17,6 +17,7 @@
 
 package org.apache.ignite.testsuites;
 
+import java.util.Collection;
 import junit.framework.TestSuite;
 import org.apache.ignite.internal.processors.cache.CachePutIfAbsentTest;
 import org.apache.ignite.internal.processors.cache.IgniteCacheGetCustomCollectionsSelfTest;
@@ -28,6 +29,7 @@
 import org.apache.ignite.internal.processors.cache.distributed.IgniteTxCacheWriteSynchronizationModesMultithreadedTest;
 import org.apache.ignite.internal.processors.cache.distributed.IgniteTxConcurrentRemoveObjectsTest;
 import org.apache.ignite.internal.processors.cache.transactions.TxDataConsistencyOnCommitFailureTest;
+import org.apache.ignite.testframework.GridTestUtils;
 
 /**
  * Test suite.
@@ -35,25 +37,32 @@
 public class IgniteCacheTestSuite9 extends TestSuite {
     /**
      * @return IgniteCache test suite.
-     * @throws Exception Thrown in case of the failure.
      */
-    public static TestSuite suite() throws Exception {
+    public static TestSuite suite() {
+        return suite(null);
+    }
+
+    /**
+     * @param ignoredTests Ignored tests.
+     * @return IgniteCache test suite.
+     */
+    public static TestSuite suite(Collection<Class> ignoredTests) {
         TestSuite suite = new TestSuite("IgniteCache Test Suite part 9");
 
-        suite.addTestSuite(IgniteCacheGetCustomCollectionsSelfTest.class);
-        suite.addTestSuite(IgniteCacheLoadRebalanceEvictionSelfTest.class);
-        suite.addTestSuite(IgniteCachePrimarySyncTest.class);
-        suite.addTestSuite(IgniteTxCachePrimarySyncTest.class);
-        suite.addTestSuite(IgniteTxCacheWriteSynchronizationModesMultithreadedTest.class);
-        suite.addTestSuite(CachePutIfAbsentTest.class);
+        GridTestUtils.addTestIfNeeded(suite, IgniteCacheGetCustomCollectionsSelfTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite, IgniteCacheLoadRebalanceEvictionSelfTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite, IgniteCachePrimarySyncTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite, IgniteTxCachePrimarySyncTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite, IgniteTxCacheWriteSynchronizationModesMultithreadedTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite, CachePutIfAbsentTest.class, ignoredTests);
 
-        suite.addTestSuite(CacheAtomicPrimarySyncBackPressureTest.class);
+        GridTestUtils.addTestIfNeeded(suite, CacheAtomicPrimarySyncBackPressureTest.class, ignoredTests);
 
-        suite.addTestSuite(IgniteTxConcurrentRemoveObjectsTest.class);
+        GridTestUtils.addTestIfNeeded(suite, IgniteTxConcurrentRemoveObjectsTest.class, ignoredTests);
 
-        suite.addTestSuite(TxDataConsistencyOnCommitFailureTest.class);
+        GridTestUtils.addTestIfNeeded(suite, TxDataConsistencyOnCommitFailureTest.class, ignoredTests);
 
-        suite.addTestSuite(CacheOperationsInterruptTest.class);
+        GridTestUtils.addTestIfNeeded(suite, CacheOperationsInterruptTest.class, ignoredTests);
 
         return suite;
     }
diff --git a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheWriteBehindTestSuite.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheWriteBehindTestSuite.java
index dff93ff..b4f6ae7 100644
--- a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheWriteBehindTestSuite.java
+++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheWriteBehindTestSuite.java
@@ -17,6 +17,7 @@
 
 package org.apache.ignite.testsuites;
 
+import java.util.Collection;
 import junit.framework.TestSuite;
 import org.apache.ignite.internal.processors.cache.GridCachePartitionedWritesTest;
 import org.apache.ignite.internal.processors.cache.store.GridCacheWriteBehindStoreLocalTest;
@@ -28,6 +29,7 @@
 import org.apache.ignite.internal.processors.cache.store.IgnteCacheClientWriteBehindStoreAtomicTest;
 import org.apache.ignite.internal.processors.cache.store.IgnteCacheClientWriteBehindStoreNonCoalescingTest;
 import org.apache.ignite.internal.processors.cache.store.IgnteCacheClientWriteBehindStoreTxTest;
+import org.apache.ignite.testframework.GridTestUtils;
 
 /**
  * Test suite that contains all tests for {@link org.apache.ignite.internal.processors.cache.store.GridCacheWriteBehindStore}.
@@ -35,22 +37,29 @@
 public class IgniteCacheWriteBehindTestSuite extends TestSuite {
     /**
      * @return Ignite Bamboo in-memory data grid test suite.
-     * @throws Exception Thrown in case of the failure.
      */
-    public static TestSuite suite() throws Exception {
+    public static TestSuite suite() {
+        return suite(null);
+    }
+
+    /**
+     * @param ignoredTests Ignored tests.
+     * @return IgniteCache test suite.
+     */
+    public static TestSuite suite(Collection<Class> ignoredTests) {
         TestSuite suite = new TestSuite("Write-Behind Store Test Suite");
 
         // Write-behind tests.
-        suite.addTest(new TestSuite(GridCacheWriteBehindStoreSelfTest.class));
-        suite.addTest(new TestSuite(GridCacheWriteBehindStoreMultithreadedSelfTest.class));
-        suite.addTest(new TestSuite(GridCacheWriteBehindStoreLocalTest.class));
-        suite.addTest(new TestSuite(GridCacheWriteBehindStoreReplicatedTest.class));
-        suite.addTest(new TestSuite(GridCacheWriteBehindStorePartitionedTest.class));
-        suite.addTest(new TestSuite(GridCacheWriteBehindStorePartitionedMultiNodeSelfTest.class));
-        suite.addTest(new TestSuite(GridCachePartitionedWritesTest.class));
-        suite.addTest(new TestSuite(IgnteCacheClientWriteBehindStoreAtomicTest.class));
-        suite.addTest(new TestSuite(IgnteCacheClientWriteBehindStoreTxTest.class));
-        suite.addTest(new TestSuite(IgnteCacheClientWriteBehindStoreNonCoalescingTest.class));
+        GridTestUtils.addTestIfNeeded(suite, GridCacheWriteBehindStoreSelfTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite, GridCacheWriteBehindStoreMultithreadedSelfTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite, GridCacheWriteBehindStoreLocalTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite, GridCacheWriteBehindStoreReplicatedTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite, GridCacheWriteBehindStorePartitionedTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite, GridCacheWriteBehindStorePartitionedMultiNodeSelfTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite, GridCachePartitionedWritesTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite, IgnteCacheClientWriteBehindStoreAtomicTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite, IgnteCacheClientWriteBehindStoreTxTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite, IgnteCacheClientWriteBehindStoreNonCoalescingTest.class, ignoredTests);
 
         return suite;
     }
diff --git a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteKernalSelfTestSuite.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteKernalSelfTestSuite.java
index ab2306e..7e0148d 100644
--- a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteKernalSelfTestSuite.java
+++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteKernalSelfTestSuite.java
@@ -42,6 +42,7 @@
 import org.apache.ignite.internal.LongJVMPauseDetectorTest;
 import org.apache.ignite.internal.managers.GridManagerStopSelfTest;
 import org.apache.ignite.internal.managers.communication.GridCommunicationSendMessageSelfTest;
+import org.apache.ignite.internal.managers.deployment.DeploymentRequestOfUnknownClassProcessingTest;
 import org.apache.ignite.internal.managers.deployment.GridDeploymentManagerStopSelfTest;
 import org.apache.ignite.internal.managers.discovery.GridDiscoveryManagerAliveCacheSelfTest;
 import org.apache.ignite.internal.managers.discovery.GridDiscoveryManagerAttributesSelfTest;
@@ -137,6 +138,7 @@
         suite.addTestSuite(IgniteConnectionConcurrentReserveAndRemoveTest.class);
         suite.addTestSuite(LongJVMPauseDetectorTest.class);
         suite.addTestSuite(ClusterMetricsSelfTest.class);
+        suite.addTestSuite(DeploymentRequestOfUnknownClassProcessingTest.class);
 
         // Managed Services.
         suite.addTestSuite(GridServiceProcessorSingleNodeSelfTest.class);
diff --git a/modules/core/src/test/java/org/apache/ignite/testsuites/IgnitePdsTestSuite4.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgnitePdsTestSuite4.java
index 027f341..d01f1ed 100644
--- a/modules/core/src/test/java/org/apache/ignite/testsuites/IgnitePdsTestSuite4.java
+++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgnitePdsTestSuite4.java
@@ -20,9 +20,12 @@
 import junit.framework.TestSuite;
 import org.apache.ignite.cache.ResetLostPartitionTest;
 import org.apache.ignite.internal.processors.cache.IgniteClusterActivateDeactivateTestWithPersistenceAndMemoryReuse;
+import org.apache.ignite.internal.processors.cache.distributed.CachePageWriteLockUnlockTest;
+import org.apache.ignite.internal.processors.cache.distributed.rebalancing.IgniteRebalanceOnCachesStoppingOrDestroyingTest;
 import org.apache.ignite.internal.processors.cache.persistence.IgnitePdsContinuousRestartTestWithSharedGroupAndIndexes;
 import org.apache.ignite.internal.processors.cache.persistence.IgnitePdsRecoveryAfterFileCorruptionTest;
 import org.apache.ignite.internal.processors.cache.persistence.IgnitePdsTaskCancelingTest;
+import org.apache.ignite.internal.processors.cache.persistence.db.IgnitePdsCacheWalDisabledOnRebalancingTest;
 import org.apache.ignite.internal.processors.cache.persistence.db.IgnitePdsPageEvictionDuringPartitionClearTest;
 import org.apache.ignite.internal.processors.cache.persistence.db.IgnitePdsPartitionPreloadTest;
 import org.apache.ignite.internal.processors.cache.persistence.db.IgnitePdsTransactionsHangTest;
@@ -50,6 +53,12 @@
 
         suite.addTestSuite(ResetLostPartitionTest.class);
 
+        suite.addTestSuite(IgniteRebalanceOnCachesStoppingOrDestroyingTest.class);
+
+        suite.addTestSuite(CachePageWriteLockUnlockTest.class);
+
+        suite.addTestSuite(IgnitePdsCacheWalDisabledOnRebalancingTest.class);
+
         return suite;
     }
 
diff --git a/modules/core/src/test/java/org/apache/ignite/util/GridCommandHandlerSslTest.java b/modules/core/src/test/java/org/apache/ignite/util/GridCommandHandlerSslTest.java
new file mode 100644
index 0000000..59155e5
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/util/GridCommandHandlerSslTest.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.util;
+
+import java.util.Arrays;
+import org.apache.ignite.Ignite;
+import org.apache.ignite.configuration.ConnectorConfiguration;
+import org.apache.ignite.configuration.DataStorageConfiguration;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.internal.commandline.CommandHandler;
+import org.apache.ignite.testframework.GridTestUtils;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+
+import static org.apache.ignite.internal.commandline.CommandHandler.EXIT_CODE_CONNECTION_FAILED;
+import static org.apache.ignite.internal.commandline.CommandHandler.EXIT_CODE_OK;
+
+/**
+ * Command line handler test.
+ */
+public class GridCommandHandlerSslTest extends GridCommonAbstractTest {
+    /** {@inheritDoc} */
+    @Override protected void beforeTest() throws Exception {
+        cleanPersistenceDir();
+
+        stopAllGrids();
+
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void afterTest() throws Exception {
+        stopAllGrids();
+
+        cleanPersistenceDir();
+
+    }
+
+    /** {@inheritDoc} */
+    @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception {
+        IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName);
+
+        cfg.setDataStorageConfiguration(new DataStorageConfiguration());
+        cfg.getDataStorageConfiguration().getDefaultDataRegionConfiguration().setMaxSize(100 * 1024 * 1024);
+        cfg.getDataStorageConfiguration().getDefaultDataRegionConfiguration().setPersistenceEnabled(true);
+
+        cfg.setConnectorConfiguration(new ConnectorConfiguration());
+        cfg.getConnectorConfiguration().setSslEnabled(true);
+        cfg.setSslContextFactory(GridTestUtils.sslFactory());
+
+        return cfg;
+    }
+
+    /**
+     * Test activation works via control.sh
+     *
+     * @throws Exception If failed.
+     */
+    public void testActivate() throws Exception {
+        Ignite ignite = startGrids(1);
+
+        assertFalse(ignite.cluster().active());
+
+        final CommandHandler cmd = new CommandHandler();
+        assertEquals(EXIT_CODE_OK, cmd.execute(Arrays.asList(
+            "--activate",
+            "--keystore", GridTestUtils.keyStorePath("node01"),
+            "--keystore-password", GridTestUtils.keyStorePassword())));
+
+        assertTrue(ignite.cluster().active());
+
+        assertEquals(EXIT_CODE_CONNECTION_FAILED, cmd.execute(Arrays.asList("--deactivate", "--yes")));
+    }
+
+}
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 6edde59..f5fa887 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
@@ -19,6 +19,7 @@
 
 import java.io.ByteArrayOutputStream;
 import java.io.File;
+import java.io.IOException;
 import java.io.PrintStream;
 import java.nio.file.DirectoryStream;
 import java.nio.file.Files;
@@ -48,12 +49,15 @@
 import org.apache.ignite.IgniteCheckedException;
 import org.apache.ignite.cache.affinity.rendezvous.RendezvousAffinityFunction;
 import org.apache.ignite.cluster.ClusterNode;
+import org.apache.ignite.configuration.AtomicConfiguration;
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.ConnectorConfiguration;
 import org.apache.ignite.configuration.DataRegionConfiguration;
 import org.apache.ignite.configuration.DataStorageConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.configuration.WALMode;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.IgniteEx;
 import org.apache.ignite.internal.IgniteInternalFuture;
 import org.apache.ignite.internal.TestRecordingCommunicationSpi;
@@ -62,6 +66,7 @@
 import org.apache.ignite.internal.commandline.cache.CacheCommand;
 import org.apache.ignite.internal.managers.communication.GridIoMessage;
 import org.apache.ignite.internal.pagemem.wal.record.DataEntry;
+import org.apache.ignite.internal.processors.cache.CacheGroupContext;
 import org.apache.ignite.internal.processors.cache.CacheObjectImpl;
 import org.apache.ignite.internal.processors.cache.GridCacheContext;
 import org.apache.ignite.internal.processors.cache.GridCacheEntryEx;
@@ -77,15 +82,18 @@
 import org.apache.ignite.internal.processors.cache.transactions.IgniteTxEntry;
 import org.apache.ignite.internal.processors.cache.transactions.TransactionProxyImpl;
 import org.apache.ignite.internal.processors.cache.version.GridCacheVersion;
+import org.apache.ignite.internal.processors.datastructures.GridCacheInternalKeyImpl;
 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.X;
+import org.apache.ignite.internal.util.typedef.internal.CU;
 import org.apache.ignite.internal.util.typedef.internal.SB;
 import org.apache.ignite.internal.util.typedef.internal.U;
 import org.apache.ignite.internal.visor.tx.VisorTxInfo;
 import org.apache.ignite.internal.visor.tx.VisorTxTaskResult;
+import org.apache.ignite.internal.visor.verify.CacheFilterEnum;
 import org.apache.ignite.lang.IgniteBiPredicate;
 import org.apache.ignite.lang.IgniteInClosure;
 import org.apache.ignite.lang.IgnitePredicate;
@@ -124,6 +132,12 @@
     /** Option is used for auto confirmation. */
     private static final String CMD_AUTO_CONFIRMATION = "--yes";
 
+    /** Atomic configuration. */
+    private AtomicConfiguration atomicConfiguration;
+
+    /** Additional data region configuration. */
+    private DataRegionConfiguration dataRegionConfiguration;
+
     /**
      * @return Folder in work directory.
      * @throws IgniteCheckedException If failed to resolve folder name.
@@ -184,12 +198,19 @@
     @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception {
         IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName);
 
+        if (atomicConfiguration != null)
+            cfg.setAtomicConfiguration(atomicConfiguration);
+
         cfg.setCommunicationSpi(new TestRecordingCommunicationSpi());
 
         cfg.setConnectorConfiguration(new ConnectorConfiguration());
 
-        DataStorageConfiguration memCfg = new DataStorageConfiguration().setDefaultDataRegionConfiguration(
-            new DataRegionConfiguration().setMaxSize(50L * 1024 * 1024));
+        DataStorageConfiguration memCfg = new DataStorageConfiguration()
+            .setDefaultDataRegionConfiguration(new DataRegionConfiguration()
+                .setMaxSize(50L * 1024 * 1024));
+
+        if (dataRegionConfiguration != null)
+            memCfg.setDataRegionConfigurations(dataRegionConfiguration);
 
         cfg.setDataStorageConfiguration(memCfg);
 
@@ -204,6 +225,11 @@
         return cfg;
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * Test activation works via control.sh
      *
@@ -1048,18 +1074,26 @@
             .setBackups(1)
             .setName(DEFAULT_CACHE_NAME));
 
-        injectTestSystemOut();
-
         for (int i = 0; i < 100; i++)
             cache.put(i, i);
 
+        corruptingAndCheckDefaultCache(ignite, parts, CacheFilterEnum.ALL);
+    }
+
+    /**
+     * @param ignite Ignite.
+     * @param parts Parts.
+     */
+    private void corruptingAndCheckDefaultCache(IgniteEx ignite, int parts, CacheFilterEnum cacheFilterEnum) throws IOException {
+        injectTestSystemOut();
+
         GridCacheContext<Object, Object> cacheCtx = ignite.cachex(DEFAULT_CACHE_NAME).context();
 
         corruptDataEntry(cacheCtx, 0, true, false);
 
-        corruptDataEntry(cacheCtx, 0 + parts / 2, false, true);
+        corruptDataEntry(cacheCtx, parts / 2, false, true);
 
-        assertEquals(EXIT_CODE_OK, execute("--cache", "idle_verify", "--dump"));
+        assertEquals(EXIT_CODE_OK, execute("--cache", "idle_verify", "--dump", "--cacheFilter", cacheFilterEnum.toString()));
 
         Matcher fileNameMatcher = dumpFileNameMatcher();
 
@@ -1073,6 +1107,144 @@
     }
 
     /**
+     * Tests that idle verify print partitions info over system caches.
+     *
+     * @throws Exception If failed.
+     */
+    public void testCacheIdleVerifyDumpForCorruptedDataOnSystemCache() throws Exception {
+        int parts = 32;
+
+        atomicConfiguration = new AtomicConfiguration()
+            .setAffinity(new RendezvousAffinityFunction(false, parts))
+            .setBackups(2);
+
+        IgniteEx ignite = (IgniteEx)startGrids(3);
+
+        ignite.cluster().active(true);
+
+        injectTestSystemOut();
+
+        // Adding some assignments without deployments.
+        for (int i = 0; i < 100; i++) {
+            ignite.semaphore("s" + i, i, false, true);
+
+            ignite.atomicSequence("sq" + i, 0, true)
+                .incrementAndGet();
+        }
+
+        CacheGroupContext storedSysCacheCtx = ignite.context().cache().cacheGroup(CU.cacheId("default-ds-group"));
+
+        assertNotNull(storedSysCacheCtx);
+
+        corruptDataEntry(storedSysCacheCtx.caches().get(0), new GridCacheInternalKeyImpl("sq0",
+            "default-ds-group"), true, false);
+
+        corruptDataEntry(storedSysCacheCtx.caches().get(0), new GridCacheInternalKeyImpl("sq" + parts / 2,
+            "default-ds-group"), false, true);
+
+        CacheGroupContext memorySysCacheCtx = ignite.context().cache().cacheGroup(CU.cacheId("default-volatile-ds-group"));
+
+        assertNotNull(memorySysCacheCtx);
+
+        corruptDataEntry(memorySysCacheCtx.caches().get(0), new GridCacheInternalKeyImpl("s0",
+                "default-volatile-ds-group"), true, false);
+
+        corruptDataEntry(memorySysCacheCtx.caches().get(0), new GridCacheInternalKeyImpl("s" + parts / 2,
+            "default-volatile-ds-group"), false, true);
+
+        assertEquals(EXIT_CODE_OK, execute("--cache", "idle_verify", "--dump", "--cacheFilter", CacheFilterEnum.SYSTEM.toString()));
+
+        Matcher fileNameMatcher = dumpFileNameMatcher();
+
+        if (fileNameMatcher.find()) {
+            String dumpWithConflicts = new String(Files.readAllBytes(Paths.get(fileNameMatcher.group(1))));
+
+            assertTrue(dumpWithConflicts.contains("found 4 conflict partitions: [counterConflicts=2, " +
+                "hashConflicts=2]"));
+        }
+        else
+            fail("Should be found dump with conflicts");
+    }
+
+    /**
+     * Tests that idle verify print partitions info over persistence client caches.
+     *
+     * @throws Exception If failed.
+     */
+    public void testCacheIdleVerifyDumpForCorruptedDataOnPersistenceClientCache() throws Exception {
+        int parts = 32;
+
+        dataRegionConfiguration = new DataRegionConfiguration()
+            .setName("persistence-region")
+            .setMaxSize(100L * 1024 * 1024)
+            .setPersistenceEnabled(true);
+
+        IgniteEx ignite = (IgniteEx)startGrids(3);
+
+        ignite.cluster().active(true);
+
+        IgniteCache<Object, Object> cache = ignite.createCache(new CacheConfiguration<>()
+            .setAffinity(new RendezvousAffinityFunction(false, parts))
+            .setBackups(2)
+            .setName(DEFAULT_CACHE_NAME)
+            .setDataRegionName("persistence-region"));
+
+        // Adding some assignments without deployments.
+        for (int i = 0; i < 100; i++)
+            cache.put(i, i);
+
+        corruptingAndCheckDefaultCache(ignite, parts, CacheFilterEnum.PERSISTENT);
+    }
+
+    /**
+     * Tests that idle verify print partitions info over none-persistence client caches.
+     *
+     * @throws Exception If failed.
+     */
+    public void testCacheIdleVerifyDumpForCorruptedDataOnNonePersistenceClientCache() throws Exception {
+        int parts = 32;
+
+        dataRegionConfiguration = new DataRegionConfiguration()
+            .setName("none-persistence-region");
+
+        IgniteEx ignite = (IgniteEx)startGrids(3);
+
+        ignite.cluster().active(true);
+
+        IgniteCache<Object, Object> cache = ignite.createCache(new CacheConfiguration<>()
+            .setAffinity(new RendezvousAffinityFunction(false, parts))
+            .setBackups(2)
+            .setName(DEFAULT_CACHE_NAME)
+            .setDataRegionName("none-persistence-region"));
+
+        // Adding some assignments without deployments.
+        for (int i = 0; i < 100; i++)
+            cache.put(i, i);
+
+        injectTestSystemOut();
+
+        GridCacheContext<Object, Object> cacheCtx = ignite.cachex(DEFAULT_CACHE_NAME).context();
+
+        corruptDataEntry(cacheCtx, 0, true, false);
+
+        corruptDataEntry(cacheCtx, parts / 2, false, true);
+
+        assertEquals(EXIT_CODE_OK, execute("--cache", "idle_verify", "--dump", "--cacheFilter", CacheFilterEnum
+            .NOT_PERSISTENT.toString()));
+
+        Matcher fileNameMatcher = dumpFileNameMatcher();
+
+        if (fileNameMatcher.find()) {
+            String dumpWithConflicts = new String(Files.readAllBytes(Paths.get(fileNameMatcher.group(1))));
+
+            assertTrue(dumpWithConflicts.contains("found 1 conflict partitions: [counterConflicts=0, " +
+                "hashConflicts=1]"));
+        }
+        else
+            fail("Should be found dump with conflicts");
+    }
+
+    /**
      * @return Build matcher for dump file name.
      */
     @NotNull private Matcher dumpFileNameMatcher() {
@@ -1622,7 +1794,7 @@
      */
     private void corruptDataEntry(
         GridCacheContext<Object, Object> ctx,
-        int key,
+        Object key,
         boolean breakCntr,
         boolean breakData
     ) {
diff --git a/modules/core/src/test/java/org/apache/ignite/util/GridTopologyHeapSizeSelfTest.java b/modules/core/src/test/java/org/apache/ignite/util/GridTopologyHeapSizeSelfTest.java
index c8e4619..9efd6af 100644
--- a/modules/core/src/test/java/org/apache/ignite/util/GridTopologyHeapSizeSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/util/GridTopologyHeapSizeSelfTest.java
@@ -20,6 +20,8 @@
 import java.util.UUID;
 import org.apache.ignite.cluster.ClusterNode;
 import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.ClusterMetricsSnapshot;
 import org.apache.ignite.internal.util.typedef.F;
 import org.apache.ignite.internal.util.typedef.internal.U;
@@ -52,6 +54,11 @@
         return cfg;
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * @throws Exception If failed.
      */
diff --git a/modules/hadoop/src/test/java/org/apache/ignite/internal/processors/hadoop/impl/HadoopMapReduceErrorResilienceTest.java b/modules/hadoop/src/test/java/org/apache/ignite/internal/processors/hadoop/impl/HadoopMapReduceErrorResilienceTest.java
index afd6f26..c114351 100644
--- a/modules/hadoop/src/test/java/org/apache/ignite/internal/processors/hadoop/impl/HadoopMapReduceErrorResilienceTest.java
+++ b/modules/hadoop/src/test/java/org/apache/ignite/internal/processors/hadoop/impl/HadoopMapReduceErrorResilienceTest.java
@@ -17,6 +17,8 @@
 
 package org.apache.ignite.internal.processors.hadoop.impl;
 
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.igfs.IgfsPath;
 import org.apache.ignite.internal.processors.hadoop.impl.examples.HadoopWordCount2;
 
@@ -28,6 +30,11 @@
  *   x { phase where the error happens }.
  */
 public class HadoopMapReduceErrorResilienceTest extends HadoopAbstractMapReduceTest {
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * Tests recovery.
      *
diff --git a/modules/hadoop/src/test/java/org/apache/ignite/internal/processors/hadoop/impl/igfs/IgniteHadoopFileSystemAbstractSelfTest.java b/modules/hadoop/src/test/java/org/apache/ignite/internal/processors/hadoop/impl/igfs/IgniteHadoopFileSystemAbstractSelfTest.java
index a73367a..6eef598 100644
--- a/modules/hadoop/src/test/java/org/apache/ignite/internal/processors/hadoop/impl/igfs/IgniteHadoopFileSystemAbstractSelfTest.java
+++ b/modules/hadoop/src/test/java/org/apache/ignite/internal/processors/hadoop/impl/igfs/IgniteHadoopFileSystemAbstractSelfTest.java
@@ -61,6 +61,7 @@
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.FileSystemConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.failure.FailureHandler;
 import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.hadoop.fs.CachingHadoopFileSystemFactory;
 import org.apache.ignite.hadoop.fs.IgniteHadoopIgfsSecondaryFileSystem;
@@ -338,6 +339,11 @@
         U.closeQuiet(fs);
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * Get primary IPC endpoint configuration.
      *
diff --git a/modules/hadoop/src/test/java/org/apache/ignite/internal/processors/hadoop/impl/taskexecutor/HadoopExecutorServiceTest.java b/modules/hadoop/src/test/java/org/apache/ignite/internal/processors/hadoop/impl/taskexecutor/HadoopExecutorServiceTest.java
index cc6cbb3..171da85 100644
--- a/modules/hadoop/src/test/java/org/apache/ignite/internal/processors/hadoop/impl/taskexecutor/HadoopExecutorServiceTest.java
+++ b/modules/hadoop/src/test/java/org/apache/ignite/internal/processors/hadoop/impl/taskexecutor/HadoopExecutorServiceTest.java
@@ -17,6 +17,8 @@
 
 package org.apache.ignite.internal.processors.hadoop.impl.taskexecutor;
 
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.processors.hadoop.taskexecutor.HadoopExecutorService;
 import org.apache.ignite.internal.util.typedef.X;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
@@ -28,6 +30,11 @@
  *
  */
 public class HadoopExecutorServiceTest extends GridCommonAbstractTest {
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * @throws Exception If failed.
      */
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/DmlStatementsProcessor.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/DmlStatementsProcessor.java
index 9b31b02..1e32f57 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/DmlStatementsProcessor.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/DmlStatementsProcessor.java
@@ -1219,23 +1219,17 @@
         GridH2Table tbl = idx.dataTable(cmd.schemaName(), cmd.tableName());
 
         if (tbl == null) {
-            idx.kernalContext().cache().createMissingQueryCaches();
-
-            tbl = idx.dataTable(cmd.schemaName(), cmd.tableName());
-        }
-
-        if (tbl == null) {
             throw new IgniteSQLException("Table does not exist: " + cmd.tableName(),
                 IgniteQueryErrorCode.TABLE_NOT_FOUND);
         }
 
+        H2Utils.checkAndStartNotStartedCache(tbl);
+
         UpdatePlan plan = UpdatePlanBuilder.planForBulkLoad(cmd, tbl);
 
         IgniteClosureX<List<?>, IgniteBiTuple<?, ?>> dataConverter = new BulkLoadDataConverter(plan);
 
-        GridCacheContext cache = tbl.cache();
-
-        IgniteDataStreamer<Object, Object> streamer = cache.grid().dataStreamer(cache.name());
+        IgniteDataStreamer<Object, Object> streamer = idx.kernalContext().grid().dataStreamer(tbl.cacheName());
 
         BulkLoadCacheWriter outputWriter = new BulkLoadStreamerWriter(streamer);
 
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2RowCache.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2RowCache.java
index 06a3251..15f5501 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2RowCache.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2RowCache.java
@@ -17,19 +17,18 @@
 
 package org.apache.ignite.internal.processors.query.h2;
 
+import java.util.Iterator;
+import java.util.Map;
 import org.apache.ignite.IgniteCheckedException;
 import org.apache.ignite.internal.pagemem.PageIdUtils;
 import org.apache.ignite.internal.pagemem.PageMemory;
 import org.apache.ignite.internal.processors.cache.CacheGroupContext;
-import org.apache.ignite.internal.processors.cache.GridCacheContext;
+import org.apache.ignite.internal.processors.cache.GridCacheContextInfo;
 import org.apache.ignite.internal.processors.query.GridQueryRowCacheCleaner;
 import org.apache.ignite.internal.processors.query.h2.opt.GridH2KeyValueRowOnheap;
 import org.apache.ignite.internal.util.typedef.F;
 import org.jsr166.ConcurrentLinkedHashMap;
 
-import java.util.Iterator;
-import java.util.Map;
-
 import static org.jsr166.ConcurrentLinkedHashMap.DFLT_INIT_CAP;
 import static org.jsr166.ConcurrentLinkedHashMap.DFLT_LOAD_FACTOR;
 
@@ -100,13 +99,13 @@
     /**
      * Cache un-registration callback.
      *
-     * @param cctx Cache context.
+     * @param cacheInfo Cache context info.
      * @return {@code True} if there are no more usages for the given cache group.
      */
-    public boolean onCacheUnregistered(GridCacheContext cctx) {
+    public boolean onCacheUnregistered(GridCacheContextInfo cacheInfo) {
         boolean res = --usageCnt == 0;
 
-        clearForCache(cctx);
+        clearForCache(cacheInfo);
 
         return res;
     }
@@ -121,10 +120,10 @@
     /**
      * Clear entries belonging to the given cache.
      *
-     * @param cctx Cache context.
+     * @param cacheInfo Cache context info.
      */
-    private void clearForCache(GridCacheContext cctx) {
-        int cacheId = cctx.cacheId();
+    private void clearForCache(GridCacheContextInfo cacheInfo) {
+        int cacheId = cacheInfo.cacheId();
 
         Iterator<Map.Entry<Long, GridH2KeyValueRowOnheap>> iter = rows.entrySet().iterator();
 
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2RowCacheRegistry.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2RowCacheRegistry.java
index 39f3329b..ca135f1 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2RowCacheRegistry.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2RowCacheRegistry.java
@@ -17,12 +17,12 @@
 
 package org.apache.ignite.internal.processors.query.h2;
 
-import org.apache.ignite.internal.processors.cache.GridCacheContext;
-import org.apache.ignite.internal.processors.cache.IgniteCacheOffheapManager;
-import org.jetbrains.annotations.Nullable;
-
 import java.util.HashMap;
 import java.util.Map;
+import org.apache.ignite.internal.processors.cache.GridCacheContext;
+import org.apache.ignite.internal.processors.cache.GridCacheContextInfo;
+import org.apache.ignite.internal.processors.cache.IgniteCacheOffheapManager;
+import org.jetbrains.annotations.Nullable;
 
 /**
  * H2 row cache registry.
@@ -47,14 +47,14 @@
     /**
      * Callback invoked on cache registration within indexing.
      *
-     * @param cctx Cache context.
+     * @param cacheInfo Cache info context.
      */
-    public void onCacheRegistered(GridCacheContext cctx) {
-        if (!cctx.config().isSqlOnheapCacheEnabled())
+    public void onCacheRegistered(GridCacheContextInfo cacheInfo) {
+        if (!cacheInfo.config().isSqlOnheapCacheEnabled())
             return;
 
         synchronized (mux) {
-            int grpId = cctx.groupId();
+            int grpId = cacheInfo.groupId();
 
             if (caches != null) {
                 H2RowCache cache = caches.get(grpId);
@@ -68,31 +68,37 @@
 
             HashMap<Integer, H2RowCache> caches0 = copy();
 
-            H2RowCache rowCache = new H2RowCache(cctx.group(), cctx.config().getSqlOnheapCacheMaxSize());
+            if (cacheInfo.affinityNode()) {
+                GridCacheContext cacheCtx = cacheInfo.gridCacheContext();
 
-            caches0.put(grpId, rowCache);
+                assert cacheCtx != null;
 
-            caches = caches0;
+                H2RowCache rowCache = new H2RowCache(cacheCtx.group(), cacheInfo.config().getSqlOnheapCacheMaxSize());
 
-            // Inject row cache cleaner into store on cache creation.
-            // Used in case the cache with enabled SqlOnheapCache is created in exists cache group
-            // and SqlOnheapCache is disbaled for the caches have been created before.
-            for (IgniteCacheOffheapManager.CacheDataStore ds : cctx.offheap().cacheDataStores())
-                ds.setRowCacheCleaner(rowCache);
+                caches0.put(grpId, rowCache);
+
+                caches = caches0;
+
+                // Inject row cache cleaner into store on cache creation.
+                // Used in case the cache with enabled SqlOnheapCache is created in exists cache group
+                // and SqlOnheapCache is disbaled for the caches have been created before.
+                for (IgniteCacheOffheapManager.CacheDataStore ds : cacheCtx.offheap().cacheDataStores())
+                    ds.setRowCacheCleaner(rowCache);
+            }
         }
     }
 
     /**
      * Callback invoked when cache gets unregistered.
      *
-     * @param cctx Cache context.
+     * @param cacheInfo Cache context info.
      */
-    public void onCacheUnregistered(GridCacheContext cctx) {
-        if (!cctx.config().isSqlOnheapCacheEnabled())
+    public void onCacheUnregistered(GridCacheContextInfo cacheInfo) {
+        if (!cacheInfo.config().isSqlOnheapCacheEnabled())
             return;
 
         synchronized (mux) {
-            int grpId = cctx.groupId();
+            int grpId = cacheInfo.groupId();
 
             assert caches != null;
 
@@ -100,7 +106,7 @@
 
             assert cache != null;
 
-            if (cache.onCacheUnregistered(cctx)) {
+            if (cache.onCacheUnregistered(cacheInfo)) {
                 HashMap<Integer, H2RowCache> caches0 = copy();
 
                 caches0.remove(grpId);
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2Schema.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2Schema.java
index ab7cb4b..ed3a9c5 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2Schema.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2Schema.java
@@ -105,7 +105,7 @@
         if (tbls.putIfAbsent(tbl.tableName(), tbl) != null)
             throw new IllegalStateException("Table already registered: " + tbl.fullTableName());
 
-        if (typeToTbl.putIfAbsent(new H2TypeKey(tbl.cache().name(), tbl.typeName()), tbl) != null)
+        if (typeToTbl.putIfAbsent(new H2TypeKey(tbl.cacheName(), tbl.typeName()), tbl) != null)
             throw new IllegalStateException("Table already registered: " + tbl.fullTableName());
     }
 
@@ -115,7 +115,7 @@
     public void remove(H2TableDescriptor tbl) {
         tbls.remove(tbl.tableName());
 
-        typeToTbl.remove(new H2TypeKey(tbl.cache().name(), tbl.typeName()));
+        typeToTbl.remove(new H2TypeKey(tbl.cacheName(), tbl.typeName()));
     }
 
     /**
@@ -128,7 +128,7 @@
 
         tbls.remove(tbl.tableName());
 
-        typeToTbl.remove(new H2TypeKey(tbl.cache().name(), tbl.typeName()));
+        typeToTbl.remove(new H2TypeKey(tbl.cacheName(), tbl.typeName()));
     }
 
     /**
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2TableDescriptor.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2TableDescriptor.java
index 6c20727..920f03d 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2TableDescriptor.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2TableDescriptor.java
@@ -25,6 +25,7 @@
 import org.apache.ignite.IgniteException;
 import org.apache.ignite.cache.QueryIndexType;
 import org.apache.ignite.internal.processors.cache.GridCacheContext;
+import org.apache.ignite.internal.processors.cache.GridCacheContextInfo;
 import org.apache.ignite.internal.processors.query.GridQueryIndexDescriptor;
 import org.apache.ignite.internal.processors.query.GridQueryProperty;
 import org.apache.ignite.internal.processors.query.GridQueryTypeDescriptor;
@@ -71,8 +72,8 @@
     /** */
     private final H2Schema schema;
 
-    /** Cache context. */
-    private final GridCacheContext cctx;
+    /** Cache context info. */
+    private final GridCacheContextInfo cacheInfo;
 
     /** */
     private GridH2Table tbl;
@@ -92,15 +93,15 @@
      * @param idx Indexing.
      * @param schema Schema.
      * @param type Type descriptor.
-     * @param cctx Cache context.
+     * @param cacheInfo Cache context info.
      * @param isSql {@code true} in case table has been created from SQL.
      */
     public H2TableDescriptor(IgniteH2Indexing idx, H2Schema schema, GridQueryTypeDescriptor type,
-        GridCacheContext cctx, boolean isSql) {
+        GridCacheContextInfo cacheInfo, boolean isSql) {
         this.idx = idx;
         this.type = type;
         this.schema = schema;
-        this.cctx = cctx;
+        this.cacheInfo = cacheInfo;
         this.isSql = isSql;
 
         fullTblName = H2Utils.withQuotes(schema.schemaName()) + "." + H2Utils.withQuotes(type.tableName());
@@ -156,10 +157,24 @@
     }
 
     /**
+     * @return Cache name.
+     */
+    public String cacheName(){
+        return cacheInfo.name();
+    }
+
+    /**
+     * @return Cache context info.
+     */
+    public GridCacheContextInfo cacheInfo() {
+        return cacheInfo;
+    }
+
+    /**
      * @return Cache context.
      */
     public GridCacheContext cache() {
-        return cctx;
+        return cacheInfo.gridCacheContext();
     }
 
     /**
@@ -188,8 +203,8 @@
      * @return H2 row factory.
      */
     H2RowFactory rowFactory(GridH2RowDescriptor rowDesc) {
-        if (cctx.affinityNode())
-            return new H2RowFactory(rowDesc, cctx);
+        if (cacheInfo.affinityNode())
+            return new H2RowFactory(rowDesc, cacheInfo.gridCacheContext());
 
         return null;
     }
@@ -421,10 +436,10 @@
      * @return Index.
      */
     private Index createHashIndex(GridH2Table tbl, String idxName, List<IndexColumn> cols) {
-        if (cctx.affinityNode()) {
+        if (cacheInfo.affinityNode()) {
             assert pkHashIdx == null : pkHashIdx;
 
-            pkHashIdx = new H2PkHashIndex(cctx, tbl, idxName, cols);
+            pkHashIdx = new H2PkHashIndex(cacheInfo.gridCacheContext(), tbl, idxName, cols);
 
             return pkHashIdx;
         }
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2TableEngine.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2TableEngine.java
index c05aaf6..9e79fba 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2TableEngine.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2TableEngine.java
@@ -80,7 +80,7 @@
 
     /** {@inheritDoc} */
     @Override public TableBase createTable(CreateTableData createTblData) {
-        resTbl0 = new GridH2Table(createTblData, rowDesc0, rowFactory0, tblDesc0, tblDesc0.cache());
+        resTbl0 = new GridH2Table(createTblData, rowDesc0, rowFactory0, tblDesc0, tblDesc0.cacheInfo());
 
         return resTbl0;
     }
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2Utils.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2Utils.java
index 865754f..d45a60f 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2Utils.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2Utils.java
@@ -26,6 +26,7 @@
 import java.util.List;
 import org.apache.ignite.IgniteCheckedException;
 import org.apache.ignite.IgniteException;
+import org.apache.ignite.internal.GridKernalContext;
 import org.apache.ignite.internal.processors.cache.QueryCursorImpl;
 import org.apache.ignite.internal.processors.query.GridQueryFieldMetadata;
 import org.apache.ignite.internal.processors.query.h2.opt.GridH2IndexBase;
@@ -34,6 +35,7 @@
 import org.apache.ignite.internal.util.GridStringBuilder;
 import org.apache.ignite.internal.util.typedef.F;
 import org.apache.ignite.internal.util.typedef.internal.SB;
+import org.apache.ignite.internal.util.typedef.internal.U;
 import org.h2.engine.Session;
 import org.h2.jdbc.JdbcConnection;
 import org.h2.result.SortOrder;
@@ -298,4 +300,29 @@
                 dest.add(col);
         }
     }
+
+    /**
+     * Check that given table has not started cache and start it for such case.
+     *
+     * @param tbl Table to check on not started cache.
+     * @return {@code true} in case not started and has been started.
+     */
+    public static boolean checkAndStartNotStartedCache(GridH2Table tbl) {
+        if (tbl != null && tbl.isCacheLazy()) {
+            String cacheName = tbl.cacheInfo().config().getName();
+
+            GridKernalContext ctx = tbl.cacheInfo().context();
+
+            try {
+                Boolean res = ctx.cache().dynamicStartCache(null, cacheName, null, false, true, true).get();
+
+                return U.firstNotNull(res, Boolean.FALSE);
+            }
+            catch (IgniteCheckedException ex) {
+                throw U.convertException(ex);
+            }
+        }
+
+        return false;
+    }
 }
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 937363a..e42fc6a 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
@@ -58,10 +58,12 @@
 import org.apache.ignite.internal.GridKernalContext;
 import org.apache.ignite.internal.GridTopic;
 import org.apache.ignite.internal.IgniteInternalFuture;
+import org.apache.ignite.internal.pagemem.store.IgnitePageStoreManager;
 import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion;
 import org.apache.ignite.internal.processors.cache.CacheObjectValueContext;
 import org.apache.ignite.internal.processors.cache.DynamicCacheDescriptor;
 import org.apache.ignite.internal.processors.cache.GridCacheContext;
+import org.apache.ignite.internal.processors.cache.GridCacheContextInfo;
 import org.apache.ignite.internal.processors.cache.GridCacheSharedContext;
 import org.apache.ignite.internal.processors.cache.QueryCursorImpl;
 import org.apache.ignite.internal.processors.cache.distributed.dht.preloader.GridDhtPartitionsExchangeFuture;
@@ -74,7 +76,6 @@
 import org.apache.ignite.internal.processors.cache.persistence.CacheDataRow;
 import org.apache.ignite.internal.processors.cache.persistence.tree.io.PageIO;
 import org.apache.ignite.internal.processors.query.h2.affinity.PartitionInfo;
-import org.apache.ignite.internal.processors.cache.query.GridCacheQueryManager;
 import org.apache.ignite.internal.processors.cache.query.GridCacheQueryMarshallable;
 import org.apache.ignite.internal.processors.cache.query.GridCacheTwoStepQuery;
 import org.apache.ignite.internal.processors.cache.query.IgniteQueryErrorCode;
@@ -101,6 +102,7 @@
 import org.apache.ignite.internal.processors.query.SqlClientContext;
 import org.apache.ignite.internal.processors.query.UpdateSourceIterator;
 import org.apache.ignite.internal.processors.query.h2.database.H2RowFactory;
+import org.apache.ignite.internal.processors.query.h2.database.H2TreeClientIndex;
 import org.apache.ignite.internal.processors.query.h2.database.H2TreeIndex;
 import org.apache.ignite.internal.processors.query.h2.database.io.H2ExtrasInnerIO;
 import org.apache.ignite.internal.processors.query.h2.database.io.H2ExtrasLeafIO;
@@ -113,7 +115,6 @@
 import org.apache.ignite.internal.processors.query.h2.dml.UpdatePlan;
 import org.apache.ignite.internal.processors.query.h2.opt.GridH2IndexBase;
 import org.apache.ignite.internal.processors.query.h2.opt.GridH2QueryContext;
-import org.apache.ignite.internal.processors.query.h2.opt.GridH2Row;
 import org.apache.ignite.internal.processors.query.h2.opt.GridH2RowDescriptor;
 import org.apache.ignite.internal.processors.query.h2.opt.GridH2Table;
 import org.apache.ignite.internal.processors.query.h2.sql.GridSqlAlias;
@@ -164,6 +165,8 @@
 import org.apache.ignite.internal.util.typedef.internal.LT;
 import org.apache.ignite.internal.util.typedef.internal.SB;
 import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.internal.util.worker.GridWorker;
+import org.apache.ignite.internal.util.worker.GridWorkerFuture;
 import org.apache.ignite.lang.IgniteBiClosure;
 import org.apache.ignite.lang.IgniteBiTuple;
 import org.apache.ignite.lang.IgniteFuture;
@@ -642,15 +645,7 @@
             // Populate index with existing cache data.
             final GridH2RowDescriptor rowDesc = h2Tbl.rowDescriptor();
 
-            SchemaIndexCacheVisitorClosure clo = new SchemaIndexCacheVisitorClosure() {
-                @Override public void apply(CacheDataRow row) throws IgniteCheckedException {
-                    GridH2Row h2Row = rowDesc.createRow(row);
-
-                    h2Idx.putx(h2Row);
-                }
-            };
-
-            cacheVisitor.visit(clo);
+            cacheVisitor.visit(new IndexBuildClosure(rowDesc, h2Idx));
 
             // At this point index is in consistent state, promote it through H2 SQL statement, so that cached
             // prepared statements are re-built.
@@ -751,16 +746,20 @@
     GridH2IndexBase createSortedIndex(String name, GridH2Table tbl, boolean pk, boolean affinityKey,
         List<IndexColumn> unwrappedCols, List<IndexColumn> wrappedCols, int inlineSize) {
         try {
-            GridCacheContext cctx = tbl.cache();
+            GridCacheContextInfo cacheInfo = tbl.cacheInfo();
 
             if (log.isDebugEnabled())
-                log.debug("Creating cache index [cacheId=" + cctx.cacheId() + ", idxName=" + name + ']');
+                log.debug("Creating cache index [cacheId=" + cacheInfo.cacheId() + ", idxName=" + name + ']');
 
-            final int segments = tbl.rowDescriptor().context().config().getQueryParallelism();
+            if (cacheInfo.affinityNode()) {
+                final int segments = tbl.rowDescriptor().context().config().getQueryParallelism();
 
-            H2RowCache cache = rowCache.forGroup(cctx.groupId());
+                H2RowCache cache = rowCache.forGroup(cacheInfo.groupId());
 
-            return new H2TreeIndex(cctx, cache, tbl, name, pk, affinityKey, unwrappedCols, wrappedCols, inlineSize, segments);
+                return new H2TreeIndex(cacheInfo.gridCacheContext(), cache, tbl, name, pk, affinityKey, unwrappedCols, wrappedCols, inlineSize, segments);
+            }
+            else
+                return new H2TreeClientIndex(tbl, name, pk, unwrappedCols);
         }
         catch (IgniteCheckedException e) {
             throw new IgniteException(e);
@@ -1379,7 +1378,7 @@
             if (o instanceof GridSqlAlias)
                 o = GridSqlAlias.unwrap((GridSqlAst) o);
             if (o instanceof GridSqlTable && ((GridSqlTable) o).dataTable() != null) {
-                GridCacheContext cctx = ((GridSqlTable) o).dataTable().cache();
+                GridCacheContext cctx = ((GridSqlTable)o).dataTable().cacheContext();
 
                 if (mvccEnabled == null) {
                     mvccEnabled = cctx.mvccEnabled();
@@ -2335,31 +2334,12 @@
      * @return H2 prepared statement.
      */
     private PreparedStatement prepareStatementAndCaches(Connection c, String sqlQry) {
-        boolean cachesCreated = false;
-
-        while (true) {
-            try {
-                return prepareStatement(c, sqlQry, true);
-            }
-            catch (SQLException e) {
-                if (!cachesCreated && (
-                        e.getErrorCode() == ErrorCode.SCHEMA_NOT_FOUND_1 ||
-                            e.getErrorCode() == ErrorCode.TABLE_OR_VIEW_NOT_FOUND_1 ||
-                            e.getErrorCode() == ErrorCode.INDEX_NOT_FOUND_1)
-                        ) {
-                    try {
-                        ctx.cache().createMissingQueryCaches();
-                    }
-                    catch (IgniteCheckedException ignored) {
-                        throw new CacheException("Failed to create missing caches.", e);
-                    }
-
-                    cachesCreated = true;
-                }
-                else
-                    throw new IgniteSQLException("Failed to parse query. " + e.getMessage(),
-                        IgniteQueryErrorCode.PARSING, e);
-            }
+        try {
+            return prepareStatement(c, sqlQry, true);
+        }
+        catch (SQLException e) {
+            throw new IgniteSQLException("Failed to parse query. " + e.getMessage(),
+                IgniteQueryErrorCode.PARSING, e);
         }
     }
 
@@ -2445,19 +2425,20 @@
      *
      * This implementation doesn't support type reregistration.
      *
+     * @param cacheInfo Cache context info.
      * @param type Type description.
      * @param isSql {@code true} in case table has been created from SQL.
      * @throws IgniteCheckedException In case of error.
      */
-    @Override public boolean registerType(GridCacheContext cctx, GridQueryTypeDescriptor type, boolean isSql)
+    @Override public boolean registerType(GridCacheContextInfo cacheInfo, GridQueryTypeDescriptor type, boolean isSql)
         throws IgniteCheckedException {
         validateTypeDescriptor(type);
 
-        String schemaName = schema(cctx.name());
+        String schemaName = schema(cacheInfo.name());
 
         H2Schema schema = schemas.get(schemaName);
 
-        H2TableDescriptor tbl = new H2TableDescriptor(this, schema, type, cctx, isSql);
+        H2TableDescriptor tbl = new H2TableDescriptor(this, schema, type, cacheInfo, isSql);
 
         try {
             Connection conn = connMgr.connectionForThread(schemaName);
@@ -2596,6 +2577,16 @@
         dataTables.remove(h2Tbl.identifier(), h2Tbl);
     }
 
+    /** {@inheritDoc} */
+    public GridCacheContextInfo registeredCacheInfo(String cacheName) {
+        for (GridH2Table value : dataTables.values()) {
+            if (value.cacheName().equals(cacheName))
+                return value.cacheInfo();
+        }
+
+        return null;
+    }
+
     /**
      * Find table for index.
      *
@@ -2675,7 +2666,7 @@
         List<H2TableDescriptor> tbls = new ArrayList<>();
 
         for (H2TableDescriptor tbl : s.tables()) {
-            if (F.eq(tbl.cache().name(), cacheName))
+            if (F.eq(tbl.cacheName(), cacheName))
                 tbls.add(tbl);
         }
 
@@ -2694,33 +2685,97 @@
         return rowCache.forGroup(grpId);
     }
 
-    /**
-     * Rebuild indexes from hash index.
-     *
-     * @param cacheName Cache name.
-     * @throws IgniteCheckedException If failed.
-     */
-    @Override public void rebuildIndexesFromHash(String cacheName) throws IgniteCheckedException {
-        int cacheId = CU.cacheId(cacheName);
+    /** {@inheritDoc} */
+    @Override public IgniteInternalFuture<?> rebuildIndexesFromHash(GridCacheContext cctx) {
+        // No data in fresh in-memory cache.
+        if (!cctx.group().persistenceEnabled())
+            return null;
 
-        GridCacheContext cctx = ctx.cache().context().cacheContext(cacheId);
+        IgnitePageStoreManager pageStore = cctx.shared().pageStore();
 
-        final GridCacheQueryManager qryMgr = cctx.queries();
+        assert pageStore != null;
 
-        SchemaIndexCacheVisitor visitor = new SchemaIndexCacheVisitorImpl(cctx);
+        SchemaIndexCacheVisitorClosure clo;
 
-        visitor.visit(new RebuildIndexFromHashClosure(qryMgr, cctx.mvccEnabled()));
+        if (!pageStore.hasIndexStore(cctx.groupId())) {
+            // If there are no index store, rebuild all indexes.
+            clo = new IndexRebuildFullClosure(cctx.queries(), cctx.mvccEnabled());
+        }
+        else {
+            // Otherwise iterate over tables looking for missing indexes.
+            IndexRebuildPartialClosure clo0 = new IndexRebuildPartialClosure();
 
-        for (H2TableDescriptor tblDesc : tables(cacheName))
-            tblDesc.table().markRebuildFromHashInProgress(false);
+            for (H2TableDescriptor tblDesc : tables(cctx.name())) {
+                assert tblDesc.table() != null;
+
+                tblDesc.table().collectIndexesForPartialRebuild(clo0);
+            }
+
+            if (clo0.hasIndexes())
+                clo = clo0;
+            else
+                return null;
+        }
+
+        // Closure prepared, do rebuild.
+        final GridWorkerFuture<?> fut = new GridWorkerFuture<>();
+
+        markIndexRebuild(cctx.name(), true);
+
+        GridWorker worker = new GridWorker(ctx.igniteInstanceName(), "index-rebuild-worker-" + cctx.name(), log) {
+            @Override protected void body() {
+                try {
+                    rebuildIndexesFromHash0(cctx, clo);
+
+                    markIndexRebuild(cctx.name(), false);
+
+                    fut.onDone();
+                }
+                catch (Exception e) {
+                    fut.onDone(e);
+                }
+                catch (Throwable e) {
+                    U.error(log, "Failed to rebuild indexes for cache: " + cctx.name(), e);
+
+                    fut.onDone(e);
+
+                    throw e;
+                }
+            }
+        };
+
+        fut.setWorker(worker);
+
+        ctx.getExecutorService().execute(worker);
+
+        return fut;
     }
 
-    /** {@inheritDoc} */
-    @Override public void markForRebuildFromHash(String cacheName) {
+    /**
+     * Do index rebuild.
+     *
+     * @param cctx Cache context.
+     * @param clo Closure.
+     * @throws IgniteCheckedException If failed.
+     */
+    protected void rebuildIndexesFromHash0(GridCacheContext cctx, SchemaIndexCacheVisitorClosure clo)
+        throws IgniteCheckedException {
+        SchemaIndexCacheVisitor visitor = new SchemaIndexCacheVisitorImpl(cctx);
+
+        visitor.visit(clo);
+    }
+
+    /**
+     * Mark tables for index rebuild, so that their indexes are not used.
+     *
+     * @param cacheName Cache name.
+     * @param val Value.
+     */
+    private void markIndexRebuild(String cacheName, boolean val) {
         for (H2TableDescriptor tblDesc : tables(cacheName)) {
             assert tblDesc.table() != null;
 
-            tblDesc.table().markRebuildFromHashInProgress(true);
+            tblDesc.table().markRebuildFromHashInProgress(val);
         }
     }
 
@@ -3044,9 +3099,25 @@
     }
 
     /** {@inheritDoc} */
-    @Override public void registerCache(String cacheName, String schemaName, GridCacheContext<?, ?> cctx)
+    @Override public boolean initCacheContext(GridCacheContext cacheCtx) {
+        GridCacheContextInfo cacheInfo = registeredCacheInfo(cacheCtx.name());
+
+        if (cacheInfo != null) {
+            assert !cacheInfo.isCacheContextInited() : cacheInfo.name();
+            assert cacheInfo.name().equals(cacheCtx.name()) : cacheInfo.name() + " != " + cacheCtx.name();
+
+            cacheInfo.initCacheContext(cacheCtx);
+
+            return true;
+        }
+
+        return false;
+    }
+
+    /** {@inheritDoc} */
+    @Override public void registerCache(String cacheName, String schemaName, GridCacheContextInfo<?, ?> cacheInfo)
         throws IgniteCheckedException {
-        rowCache.onCacheRegistered(cctx);
+        rowCache.onCacheRegistered(cacheInfo);
 
         synchronized (schemaMux) {
             createSchemaIfNeeded(schemaName, false);
@@ -3054,14 +3125,14 @@
 
         cacheName2schema.put(cacheName, schemaName);
 
-        createSqlFunctions(schemaName, cctx.config().getSqlFunctionClasses());
+        createSqlFunctions(schemaName, cacheInfo.config().getSqlFunctionClasses());
     }
 
     /** {@inheritDoc} */
-    @Override public void unregisterCache(GridCacheContext cctx, boolean rmvIdx) {
-        rowCache.onCacheUnregistered(cctx);
+    @Override public void unregisterCache(GridCacheContextInfo cacheInfo, boolean rmvIdx) {
+        rowCache.onCacheUnregistered(cacheInfo);
 
-        String cacheName = cctx.name();
+        String cacheName = cacheInfo.name();
 
         String schemaName = schema(cacheName);
 
@@ -3078,7 +3149,7 @@
             Collection<H2TableDescriptor> rmvTbls = new HashSet<>();
 
             for (H2TableDescriptor tbl : schema.tables()) {
-                if (F.eq(tbl.cache().name(), cacheName)) {
+                if (F.eq(tbl.cacheName(), cacheName)) {
                     try {
                         tbl.table().setRemoveIndexOnDestroy(rmvIdx);
 
@@ -3297,6 +3368,8 @@
                 GridH2Table tbl = dataTable(tblKey);
 
                 if (tbl != null) {
+                    H2Utils.checkAndStartNotStartedCache(tbl);
+
                     int cacheId = tbl.cacheId();
 
                     caches0.add(cacheId);
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/RebuildIndexFromHashClosure.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IndexBuildClosure.java
similarity index 61%
copy from modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/RebuildIndexFromHashClosure.java
copy to modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IndexBuildClosure.java
index b635eac..8d1923f 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/RebuildIndexFromHashClosure.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IndexBuildClosure.java
@@ -19,29 +19,36 @@
 
 import org.apache.ignite.IgniteCheckedException;
 import org.apache.ignite.internal.processors.cache.persistence.CacheDataRow;
-import org.apache.ignite.internal.processors.cache.query.GridCacheQueryManager;
+import org.apache.ignite.internal.processors.query.h2.opt.GridH2IndexBase;
+import org.apache.ignite.internal.processors.query.h2.opt.GridH2Row;
+import org.apache.ignite.internal.processors.query.h2.opt.GridH2RowDescriptor;
 import org.apache.ignite.internal.processors.query.schema.SchemaIndexCacheVisitorClosure;
 
-/** */
-class RebuildIndexFromHashClosure implements SchemaIndexCacheVisitorClosure {
-    /** */
-    private final GridCacheQueryManager qryMgr;
+/**
+ * Index build closure.
+ */
+public class IndexBuildClosure implements SchemaIndexCacheVisitorClosure {
+    /** Row descriptor. */
+    private final GridH2RowDescriptor rowDesc;
 
-    /** MVCC status flag. */
-    private final boolean mvccEnabled;
+    /** Index. */
+    private final GridH2IndexBase idx;
 
     /**
-     * @param qryMgr Query manager.
-     * @param mvccEnabled MVCC status flag.
+     * Constructor.
+     *
+     * @param rowDesc Row descriptor.
+     * @param idx Target index.
      */
-    RebuildIndexFromHashClosure(GridCacheQueryManager qryMgr, boolean mvccEnabled) {
-        this.qryMgr = qryMgr;
-        this.mvccEnabled = mvccEnabled;
+    public IndexBuildClosure(GridH2RowDescriptor rowDesc, GridH2IndexBase idx) {
+        this.rowDesc = rowDesc;
+        this.idx = idx;
     }
 
     /** {@inheritDoc} */
     @Override public void apply(CacheDataRow row) throws IgniteCheckedException {
-        // prevRowAvailable is always true with MVCC on, and always false *on index rebuild* with MVCC off.
-        qryMgr.store(row, null, mvccEnabled);
+        GridH2Row row0 = rowDesc.createRow(row);
+
+        idx.putx(row0);
     }
 }
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/RebuildIndexFromHashClosure.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IndexRebuildFullClosure.java
similarity index 88%
rename from modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/RebuildIndexFromHashClosure.java
rename to modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IndexRebuildFullClosure.java
index b635eac..8018839 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/RebuildIndexFromHashClosure.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IndexRebuildFullClosure.java
@@ -22,8 +22,10 @@
 import org.apache.ignite.internal.processors.cache.query.GridCacheQueryManager;
 import org.apache.ignite.internal.processors.query.schema.SchemaIndexCacheVisitorClosure;
 
-/** */
-class RebuildIndexFromHashClosure implements SchemaIndexCacheVisitorClosure {
+/**
+ * Closure to rebuild all indexes.
+ */
+public class IndexRebuildFullClosure implements SchemaIndexCacheVisitorClosure {
     /** */
     private final GridCacheQueryManager qryMgr;
 
@@ -34,7 +36,7 @@
      * @param qryMgr Query manager.
      * @param mvccEnabled MVCC status flag.
      */
-    RebuildIndexFromHashClosure(GridCacheQueryManager qryMgr, boolean mvccEnabled) {
+    public IndexRebuildFullClosure(GridCacheQueryManager qryMgr, boolean mvccEnabled) {
         this.qryMgr = qryMgr;
         this.mvccEnabled = mvccEnabled;
     }
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IndexRebuildPartialClosure.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IndexRebuildPartialClosure.java
new file mode 100644
index 0000000..2672f06
--- /dev/null
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IndexRebuildPartialClosure.java
@@ -0,0 +1,76 @@
+/*
+ * 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.IgniteCheckedException;
+import org.apache.ignite.internal.processors.cache.persistence.CacheDataRow;
+import org.apache.ignite.internal.processors.query.h2.opt.GridH2IndexBase;
+import org.apache.ignite.internal.processors.query.h2.opt.GridH2Row;
+import org.apache.ignite.internal.processors.query.h2.opt.GridH2Table;
+import org.apache.ignite.internal.processors.query.schema.SchemaIndexCacheVisitorClosure;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.IdentityHashMap;
+import java.util.Map;
+
+/**
+ * Closure to rebuild some cache indexes.
+ */
+public class IndexRebuildPartialClosure implements SchemaIndexCacheVisitorClosure {
+    /** Indexes. */
+    private final Map<GridH2Table, Collection<GridH2IndexBase>> tblIdxs = new IdentityHashMap<>();
+
+    /** {@inheritDoc} */
+    @Override public void apply(CacheDataRow row) throws IgniteCheckedException {
+        assert hasIndexes();
+
+        for (Map.Entry<GridH2Table, Collection<GridH2IndexBase>> tblIdxEntry : tblIdxs.entrySet()) {
+            GridH2Table tbl = tblIdxEntry.getKey();
+
+            GridH2Row row0 = tbl.rowDescriptor().createRow(row);
+
+            for (GridH2IndexBase idx : tblIdxEntry.getValue())
+                idx.putx(row0);
+        }
+    }
+
+    /**
+     * @param idx Index to be rebuilt.
+     */
+    public void addIndex(GridH2Table tbl, GridH2IndexBase idx) {
+        Collection<GridH2IndexBase> idxs = tblIdxs.get(tbl);
+
+        if (idxs == null) {
+            idxs = Collections.newSetFromMap(new IdentityHashMap<>());
+
+            idxs.add(idx);
+
+            tblIdxs.put(tbl, idxs);
+        }
+
+        idxs.add(idx);
+    }
+
+    /**
+     * @return {@code True} if there is at least one index to rebuild.
+     */
+    public boolean hasIndexes() {
+        return !tblIdxs.isEmpty();
+    }
+}
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2Tree.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2Tree.java
index 71cea7e..f2a69bb 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2Tree.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2Tree.java
@@ -108,8 +108,12 @@
     /** */
     private final IgniteLogger log;
 
+    /** Whether PK is stored in unwrapped form. */
     private boolean unwrappedPk;
 
+    /** Whether index was created from scratch during owning node lifecycle. */
+    private final boolean created;
+
     /**
      * Constructor.
      *
@@ -200,6 +204,8 @@
         this.log = log;
 
         initTree(initNew, inlineSize);
+
+        this.created = initNew;
     }
 
     /**
@@ -556,6 +562,14 @@
      */
     public abstract int compareValues(Value v1, Value v2);
 
+    /**
+     * @return {@code True} if index was created during curren node's lifetime, {@code False} if it was restored from
+     * disk.
+     */
+    public boolean created() {
+        return created;
+    }
+
     /** {@inheritDoc} */
     @Override public String toString() {
         return S.toString(H2Tree.class, this, "super", super.toString());
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2TreeClientIndex.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2TreeClientIndex.java
new file mode 100644
index 0000000..a0bab43
--- /dev/null
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2TreeClientIndex.java
@@ -0,0 +1,114 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.processors.query.h2.database;
+
+import java.util.List;
+import org.apache.ignite.internal.processors.query.IgniteSQLException;
+import org.apache.ignite.internal.processors.query.h2.opt.GridH2Row;
+import org.apache.ignite.internal.processors.query.h2.opt.GridH2Table;
+import org.h2.engine.Session;
+import org.h2.index.Cursor;
+import org.h2.index.IndexType;
+import org.h2.result.SearchRow;
+import org.h2.table.IndexColumn;
+
+/**
+ * We need indexes on an not affinity nodes. The index shouldn't contains any data.
+ */
+public class H2TreeClientIndex extends H2TreeIndexBase {
+
+    /**
+     *
+     */
+    public static final IgniteSQLException SHOULDNT_BE_INVOKED_EXCEPTION = new IgniteSQLException("Shouldn't be invoked, due to it's not affinity node");
+
+    /**
+     * @param tbl Table.
+     * @param name Index name.
+     * @param pk Primary key.
+     * @param colsList Index columns.
+     */
+    public H2TreeClientIndex(
+        GridH2Table tbl,
+        String name,
+        boolean pk,
+        List<IndexColumn> colsList
+    ) {
+        IndexColumn[] cols = colsList.toArray(new IndexColumn[colsList.size()]);
+
+        IndexColumn.mapColumns(cols, tbl);
+
+        initBaseIndex(tbl, 0, name, cols,
+            pk ? IndexType.createPrimaryKey(false, false) : IndexType.createNonUnique(false, false, false));
+    }
+
+    /** {@inheritDoc} */
+    @Override public void refreshColumnIds() {
+        //do nothing.
+    }
+
+    /** {@inheritDoc} */
+    @Override public void destroy(boolean rmvIndex) {
+        //do nothing.
+    }
+
+    /** {@inheritDoc} */
+    @Override protected int segmentsCount() {
+        throw SHOULDNT_BE_INVOKED_EXCEPTION;
+    }
+
+    /** {@inheritDoc} */
+    @Override public Cursor find(Session ses, SearchRow lower, SearchRow upper) {
+        throw SHOULDNT_BE_INVOKED_EXCEPTION;
+    }
+
+    /** {@inheritDoc} */
+    @Override public GridH2Row put(GridH2Row row) {
+        throw SHOULDNT_BE_INVOKED_EXCEPTION;
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean putx(GridH2Row row) {
+        throw SHOULDNT_BE_INVOKED_EXCEPTION;
+    }
+
+    /** {@inheritDoc} */
+    @Override public GridH2Row remove(SearchRow row) {
+        throw SHOULDNT_BE_INVOKED_EXCEPTION;
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean removex(SearchRow row) {
+        throw SHOULDNT_BE_INVOKED_EXCEPTION;
+    }
+
+    /** {@inheritDoc} */
+    @Override public long getRowCount(Session ses) {
+        throw SHOULDNT_BE_INVOKED_EXCEPTION;
+    }
+
+    /** {@inheritDoc} */
+    @Override public Cursor findFirstOrLast(Session session, boolean b) {
+        throw SHOULDNT_BE_INVOKED_EXCEPTION;
+    }
+
+    /** {@inheritDoc} */
+    @Override protected H2Tree treeForRead(int segment) {
+        throw SHOULDNT_BE_INVOKED_EXCEPTION;
+    }
+}
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2TreeIndex.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2TreeIndex.java
index b7179b7..65be8d6 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2TreeIndex.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2TreeIndex.java
@@ -18,7 +18,6 @@
 package org.apache.ignite.internal.processors.query.h2.database;
 
 import java.util.ArrayList;
-import java.util.HashSet;
 import java.util.List;
 import java.util.concurrent.atomic.AtomicInteger;
 import org.apache.ignite.IgniteCheckedException;
@@ -35,7 +34,6 @@
 import org.apache.ignite.internal.processors.query.h2.H2Cursor;
 import org.apache.ignite.internal.processors.query.h2.H2RowCache;
 import org.apache.ignite.internal.processors.query.h2.opt.GridH2Cursor;
-import org.apache.ignite.internal.processors.query.h2.opt.GridH2IndexBase;
 import org.apache.ignite.internal.processors.query.h2.opt.GridH2QueryContext;
 import org.apache.ignite.internal.processors.query.h2.opt.GridH2Row;
 import org.apache.ignite.internal.processors.query.h2.opt.GridH2SearchRow;
@@ -52,10 +50,7 @@
 import org.h2.index.SingleRowCursor;
 import org.h2.message.DbException;
 import org.h2.result.SearchRow;
-import org.h2.result.SortOrder;
-import org.h2.table.Column;
 import org.h2.table.IndexColumn;
-import org.h2.table.TableFilter;
 import org.h2.value.Value;
 import org.jetbrains.annotations.Nullable;
 
@@ -63,7 +58,7 @@
  * H2 Index over {@link BPlusTree}.
  */
 @SuppressWarnings({"TypeMayBeWeakened", "unchecked"})
-public class H2TreeIndex extends GridH2IndexBase {
+public class H2TreeIndex extends H2TreeIndexBase {
     /** Default value for {@code IGNITE_MAX_INDEX_PAYLOAD_SIZE} */
     public static final int IGNITE_MAX_INDEX_PAYLOAD_SIZE_DEFAULT = 10;
 
@@ -88,6 +83,9 @@
     /** */
     private final String idxName;
 
+    /** Tree name. */
+    private final String treeName;
+
     /** */
     private final IgniteLogger log;
 
@@ -130,14 +128,11 @@
 
         this.table = tbl;
 
-
         GridQueryTypeDescriptor typeDesc = tbl.rowDescriptor().type();
 
         int typeId = cctx.binaryMarshaller() ? typeDesc.typeId() : typeDesc.valueClass().hashCode();
 
-        String treeName = (tbl.rowDescriptor() == null ? "" : typeId + "_") + idxName;
-
-        treeName = BPlusTree.treeName(treeName, "H2Tree");
+        treeName = BPlusTree.treeName((tbl.rowDescriptor() == null ? "" : typeId + "_") + idxName, "H2Tree");
 
         IndexColumnsInfo unwrappedColsInfo = new IndexColumnsInfo(unwrappedColsList, inlineSize);
 
@@ -145,66 +140,59 @@
 
         IndexColumn[] cols;
 
-        if (cctx.affinityNode()) {
-            segments = new H2Tree[segmentsCnt];
+        assert cctx.affinityNode();
 
-            IgniteCacheDatabaseSharedManager db = cctx.shared().database();
+        segments = new H2Tree[segmentsCnt];
 
-            AtomicInteger maxCalculatedInlineSize = new AtomicInteger();
+        IgniteCacheDatabaseSharedManager db = cctx.shared().database();
 
-            for (int i = 0; i < segments.length; i++) {
-                db.checkpointReadLock();
+        AtomicInteger maxCalculatedInlineSize = new AtomicInteger();
 
-                try {
-                    RootPage page = getMetaPage(treeName, i);
+        for (int i = 0; i < segments.length; i++) {
+            db.checkpointReadLock();
 
-                    segments[i] = new H2Tree(
-                        treeName,
-                        idxName,
-                        tblName,
-                        tbl.cacheName(),
-                        cctx.offheap().reuseListForIndex(treeName),
-                        cctx.groupId(),
-                        cctx.dataRegion().pageMemory(),
-                        cctx.shared().wal(),
-                        cctx.offheap().globalRemoveId(),
-                        tbl.rowFactory(),
-                        page.pageId().pageId(),
-                        page.isAllocated(),
-                        unwrappedColsInfo,
-                        wrappedColsInfo,
-                        maxCalculatedInlineSize,
-                        pk,
-                        affinityKey,
-                        cctx.mvccEnabled(),
-                        rowCache,
-                        cctx.kernalContext().failure(),
-                        log) {
-                        @Override public int compareValues(Value v1, Value v2) {
-                            return v1 == v2 ? 0 : table.compareTypeSafe(v1, v2);
-                        }
-                    };
-                }
-                finally {
-                    db.checkpointReadUnlock();
-                }
+            try {
+                RootPage page = getMetaPage(i);
+
+                segments[i] = new H2Tree(
+                    treeName,
+                    idxName,
+                    tblName,
+                    tbl.cacheName(),
+                    cctx.offheap().reuseListForIndex(treeName),
+                    cctx.groupId(),
+                    cctx.dataRegion().pageMemory(),
+                    cctx.shared().wal(),
+                    cctx.offheap().globalRemoveId(),
+                    tbl.rowFactory(),
+                    page.pageId().pageId(),
+                    page.isAllocated(),
+                    unwrappedColsInfo,
+                    wrappedColsInfo,
+                    maxCalculatedInlineSize,
+                    pk,
+                    affinityKey,
+                    cctx.mvccEnabled(),
+                    rowCache,
+                    cctx.kernalContext().failure(),
+                    log) {
+                    @Override public int compareValues(Value v1, Value v2) {
+                        return v1 == v2 ? 0 : table.compareTypeSafe(v1, v2);
+                    }
+                };
             }
-
-            boolean useUnwrappedCols = segments[0].unwrappedPk();
-
-            IndexColumnsInfo colsInfo = useUnwrappedCols ? unwrappedColsInfo : wrappedColsInfo;
-
-            cols = colsInfo.cols();
-
-            inlineIdxs = colsInfo.inlineIdx();
+            finally {
+                db.checkpointReadUnlock();
+            }
         }
-        else {
-            // We need indexes on the client node, but index will not contain any data.
-            segments = null;
-            inlineIdxs = null;
 
-            cols = unwrappedColsInfo.cols();
-        }
+        boolean useUnwrappedCols = segments[0].unwrappedPk();
+
+        IndexColumnsInfo colsInfo = useUnwrappedCols ? unwrappedColsInfo : wrappedColsInfo;
+
+        cols = colsInfo.cols();
+
+        inlineIdxs = colsInfo.inlineIdx();
 
         IndexColumn.mapColumns(cols, tbl);
 
@@ -215,6 +203,30 @@
     }
 
     /**
+     * Check if index exists in store.
+     *
+     * @return {@code True} if exists.
+     */
+    public boolean rebuildRequired() {
+        assert segments != null;
+
+        for (int i = 0; i < segments.length; i++) {
+            try {
+                H2Tree segment = segments[i];
+
+                if (segment.created())
+                    return true;
+            }
+            catch (Exception e) {
+                throw new IgniteException("Failed to check index tree root page existence [cacheName=" + cctx.name() +
+                    ", tblName=" + tblName + ", idxName=" + idxName + ", segment=" + i + ']');
+            }
+        }
+
+        return false;
+    }
+
+    /**
      * @param cols Columns array.
      * @return List of {@link InlineIndexHelper} objects.
      */
@@ -371,17 +383,6 @@
     }
 
     /** {@inheritDoc} */
-    @Override public double getCost(Session ses, int[] masks, TableFilter[] filters, int filter, SortOrder sortOrder, HashSet<Column> allColumnsSet) {
-        long rowCnt = getRowCountApproximation();
-
-        double baseCost = getCostRangeIndex(masks, rowCnt, filters, filter, sortOrder, false, allColumnsSet);
-
-        int mul = getDistributedMultiplier(ses, filters, filter);
-
-        return mul * baseCost;
-    }
-
-    /** {@inheritDoc} */
     @Override public long getRowCount(Session ses) {
         try {
             int seg = threadLocalSegment();
@@ -398,16 +399,6 @@
     }
 
     /** {@inheritDoc} */
-    @Override public long getRowCountApproximation() {
-        return 10_000; // TODO
-    }
-
-    /** {@inheritDoc} */
-    @Override public boolean canGetFirstOrLast() {
-        return true;
-    }
-
-    /** {@inheritDoc} */
     @Override public Cursor findFirstOrLast(Session session, boolean b) {
         try {
             H2Tree tree = treeForRead(threadLocalSegment());
@@ -431,7 +422,7 @@
 
                     tree.destroy();
 
-                    dropMetaPage(tree.getName(), i);
+                    dropMetaPage(i);
                 }
             }
         }
@@ -526,22 +517,20 @@
     }
 
     /**
-     * @param name Name.
      * @param segIdx Segment index.
      * @return RootPage for meta page.
      * @throws IgniteCheckedException If failed.
      */
-    private RootPage getMetaPage(String name, int segIdx) throws IgniteCheckedException {
-        return cctx.offheap().rootPageForIndex(cctx.cacheId(), name + "%" + segIdx);
+    private RootPage getMetaPage(int segIdx) throws IgniteCheckedException {
+        return cctx.offheap().rootPageForIndex(cctx.cacheId(), treeName, segIdx);
     }
 
     /**
-     * @param name Name.
      * @param segIdx Segment index.
      * @throws IgniteCheckedException If failed.
      */
-    private void dropMetaPage(String name, int segIdx) throws IgniteCheckedException {
-        cctx.offheap().dropRootPageForIndex(cctx.cacheId(), name + "%" + segIdx);
+    private void dropMetaPage(int segIdx) throws IgniteCheckedException {
+        cctx.offheap().dropRootPageForIndex(cctx.cacheId(), treeName, segIdx);
     }
 
     /** {@inheritDoc} */
@@ -575,7 +564,7 @@
          * @param cfgInlineSize Inline size from cache config.
          */
         public IndexColumnsInfo(List<IndexColumn> colsList, int cfgInlineSize) {
-            this.cols = colsList.toArray(new IndexColumn[colsList.size()]);
+            this.cols = colsList.toArray(new IndexColumn[0]);
 
             this.inlineIdx = getAvailableInlineColumns(cols);
 
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2TreeIndexBase.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2TreeIndexBase.java
new file mode 100644
index 0000000..e6dda14
--- /dev/null
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2TreeIndexBase.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.ignite.internal.processors.query.h2.database;
+
+import java.util.HashSet;
+import org.apache.ignite.internal.processors.query.h2.opt.GridH2IndexBase;
+import org.h2.engine.Session;
+import org.h2.result.SortOrder;
+import org.h2.table.Column;
+import org.h2.table.TableFilter;
+
+/**
+ * H2 tree index base.
+ */
+public abstract class H2TreeIndexBase extends GridH2IndexBase {
+    /** {@inheritDoc} */
+    @Override public double getCost(Session ses, int[] masks, TableFilter[] filters, int filter, SortOrder sortOrder,
+        HashSet<Column> allColumnsSet) {
+        long rowCnt = getRowCountApproximation();
+
+        double baseCost = getCostRangeIndex(masks, rowCnt, filters, filter, sortOrder, false, allColumnsSet);
+
+        int mul = getDistributedMultiplier(ses, filters, filter);
+
+        return mul * baseCost;
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean canGetFirstOrLast() {
+        return true;
+    }
+
+    /** {@inheritDoc} */
+    @Override public long getRowCountApproximation() {
+        return 10_000; // TODO
+    }
+}
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/ddl/DdlStatementsProcessor.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/ddl/DdlStatementsProcessor.java
index b99d7dc..6308eab 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/ddl/DdlStatementsProcessor.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/ddl/DdlStatementsProcessor.java
@@ -129,7 +129,7 @@
             if (cmd instanceof SqlCreateIndexCommand) {
                 SqlCreateIndexCommand cmd0 = (SqlCreateIndexCommand)cmd;
 
-                GridH2Table tbl = dataTableWithRetry(cmd0.schemaName(), cmd0.tableName());
+                GridH2Table tbl = idx.dataTable(cmd0.schemaName(), cmd0.tableName());
 
                 if (tbl == null)
                     throw new SchemaOperationException(SchemaOperationException.CODE_TABLE_NOT_FOUND, cmd0.tableName());
@@ -167,7 +167,7 @@
             else if (cmd instanceof SqlDropIndexCommand) {
                 SqlDropIndexCommand cmd0 = (SqlDropIndexCommand)cmd;
 
-                GridH2Table tbl = dataTableForIndexWithRetry(cmd0.schemaName(), cmd0.indexName());
+                GridH2Table tbl = idx.dataTableForIndex(cmd0.schemaName(), cmd0.indexName());
 
                 if (tbl != null) {
                     isDdlSupported(tbl);
@@ -186,7 +186,7 @@
             else if (cmd instanceof SqlAlterTableCommand) {
                 SqlAlterTableCommand cmd0 = (SqlAlterTableCommand)cmd;
 
-                GridH2Table tbl = dataTableWithRetry(cmd0.schemaName(), cmd0.tableName());
+                GridH2Table tbl = idx.dataTable(cmd0.schemaName(), cmd0.tableName());
 
                 if (tbl == null) {
                     throw new SchemaOperationException(SchemaOperationException.CODE_TABLE_NOT_FOUND,
@@ -270,7 +270,7 @@
 
                 isDdlOnSchemaSupported(cmd.schemaName());
 
-                GridH2Table tbl = dataTableWithRetry(cmd.schemaName(), cmd.tableName());
+                GridH2Table tbl = idx.dataTable(cmd.schemaName(), cmd.tableName());
 
                 if (tbl == null)
                     throw new SchemaOperationException(SchemaOperationException.CODE_TABLE_NOT_FOUND, cmd.tableName());
@@ -309,7 +309,7 @@
 
                 isDdlOnSchemaSupported(cmd.schemaName());
 
-                GridH2Table tbl = dataTableForIndexWithRetry(cmd.schemaName(), cmd.indexName());
+                GridH2Table tbl = idx.dataTableForIndex(cmd.schemaName(), cmd.indexName());
 
                 if (tbl != null) {
                     isDdlSupported(tbl);
@@ -332,7 +332,7 @@
 
                 isDdlOnSchemaSupported(cmd.schemaName());
 
-                GridH2Table tbl = dataTableWithRetry(cmd.schemaName(), cmd.tableName());
+                GridH2Table tbl = idx.dataTable(cmd.schemaName(), cmd.tableName());
 
                 if (tbl != null) {
                     if (!cmd.ifNotExists())
@@ -365,7 +365,7 @@
 
                 isDdlOnSchemaSupported(cmd.schemaName());
 
-                GridH2Table tbl = dataTableWithRetry(cmd.schemaName(), cmd.tableName());
+                GridH2Table tbl = idx.dataTable(cmd.schemaName(), cmd.tableName());
 
                 if (tbl == null) {
                     if (!cmd.ifExists())
@@ -380,7 +380,7 @@
 
                 isDdlOnSchemaSupported(cmd.schemaName());
 
-                GridH2Table tbl = dataTableWithRetry(cmd.schemaName(), cmd.tableName());
+                GridH2Table tbl = idx.dataTable(cmd.schemaName(), cmd.tableName());
 
                 if (tbl == null) {
                     if (!cmd.ifTableExists())
@@ -423,7 +423,7 @@
                         assert tbl.rowDescriptor() != null;
 
                         if (!allFieldsNullable)
-                            QueryUtils.checkNotNullAllowed(tbl.cache().config());
+                            QueryUtils.checkNotNullAllowed(tbl.cacheContext().config());
 
                         fut = ctx.query().dynamicColumnAdd(tbl.cacheName(), cmd.schemaName(),
                             tbl.rowDescriptor().type().tableName(), cols, cmd.ifTableExists(), cmd.ifNotExists());
@@ -435,7 +435,7 @@
 
                 isDdlOnSchemaSupported(cmd.schemaName());
 
-                GridH2Table tbl = dataTableWithRetry(cmd.schemaName(), cmd.tableName());
+                GridH2Table tbl = idx.dataTable(cmd.schemaName(), cmd.tableName());
 
                 if (tbl == null) {
                     if (!cmd.ifTableExists())
@@ -445,7 +445,7 @@
                 else {
                     assert tbl.rowDescriptor() != null;
 
-                    if (tbl.cache().mvccEnabled())
+                    if (tbl.cacheContext().mvccEnabled())
                         throw new IgniteSQLException("Cannot drop column(s) with enabled MVCC. " +
                             "Operation is unsupported at the moment.", IgniteQueryErrorCode.UNSUPPORTED_OPERATION);
 
@@ -511,46 +511,6 @@
     }
 
     /**
-     * Get table by name optionally creating missing query caches.
-     *
-     * @param schemaName Schema name.
-     * @param tableName Table name.
-     * @return Table or {@code null} if none found.
-     * @throws IgniteCheckedException If failed.
-     */
-    private GridH2Table dataTableWithRetry(String schemaName, String tableName) throws IgniteCheckedException {
-        GridH2Table tbl = idx.dataTable(schemaName, tableName);
-
-        if (tbl == null) {
-            ctx.cache().createMissingQueryCaches();
-
-            tbl = idx.dataTable(schemaName, tableName);
-        }
-
-        return tbl;
-    }
-
-    /**
-     * Get table by name optionally creating missing query caches.
-     *
-     * @param schemaName Schema name.
-     * @param indexName Index name.
-     * @return Table or {@code null} if none found.
-     * @throws IgniteCheckedException If failed.
-     */
-    private GridH2Table dataTableForIndexWithRetry(String schemaName, String indexName) throws IgniteCheckedException {
-        GridH2Table tbl = idx.dataTableForIndex(schemaName, indexName);
-
-        if (tbl == null) {
-            ctx.cache().createMissingQueryCaches();
-
-            tbl = idx.dataTableForIndex(schemaName, indexName);
-        }
-
-        return tbl;
-    }
-
-    /**
      * Check if schema supports DDL statement.
      *
      * @param schemaName Schema name.
@@ -567,7 +527,7 @@
      * @param tbl Table.
      */
     private static void isDdlSupported(GridH2Table tbl) {
-        GridCacheContext cctx = tbl.cache();
+        GridCacheContext cctx = tbl.cacheContext();
 
         assert cctx != null;
 
@@ -683,11 +643,10 @@
                 scale.put(e.getKey(), col.getScale());
             }
 
-            if (col.getType() == Value.STRING || 
-                col.getType() == Value.STRING_FIXED || 
-                col.getType() == Value.STRING_IGNORECASE) {
+            if (col.getType() == Value.STRING ||
+                col.getType() == Value.STRING_FIXED ||
+                col.getType() == Value.STRING_IGNORECASE)
                 precision.put(e.getKey(), (int)col.getPrecision());
-            }
         }
 
         if (!F.isEmpty(dfltValues))
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 0f8b6d8..fc3514b 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
@@ -535,7 +535,7 @@
      * @return Cache context.
      */
     public GridCacheContext cacheContext() {
-        return tbl.cache();
+        return tbl.cacheContext();
     }
 
     /**
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 477f22a..f1826a1 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
@@ -22,6 +22,7 @@
 import java.sql.PreparedStatement;
 import java.sql.SQLException;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
@@ -39,6 +40,7 @@
 import org.apache.ignite.internal.processors.query.IgniteSQLException;
 import org.apache.ignite.internal.processors.query.QueryUtils;
 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.opt.GridH2RowDescriptor;
 import org.apache.ignite.internal.processors.query.h2.opt.GridH2Table;
@@ -93,6 +95,7 @@
      * @param fieldsQry Original query.
      * @return Update plan.
      */
+    @SuppressWarnings("ConstantConditions")
     public static UpdatePlan planForStatement(Prepared prepared, boolean loc, IgniteH2Indexing idx,
         @Nullable Connection conn, @Nullable SqlFieldsQuery fieldsQry, @Nullable Integer errKeysPos,
         boolean dmlInsideTxAllowed)
@@ -103,15 +106,60 @@
 
         GridSqlStatement stmt = parser.parse(prepared);
 
-        boolean mvccEnabled = false;
+
+        List<GridH2Table> tbls = extractTablesParticipateAtQuery(parser);
 
         GridCacheContext prevCctx = null;
+        boolean mvccEnabled = false;
 
-        for (Object o : parser.objectsMap().values()) {
-            if (o instanceof GridSqlInsert)
-                o = ((GridSqlInsert)o).into();
-            else if (o instanceof GridSqlMerge)
+        for (GridH2Table h2tbl : tbls) {
+            H2Utils.checkAndStartNotStartedCache(h2tbl);
+
+            if (prevCctx == null) {
+                prevCctx = h2tbl.cacheContext();
+
+                assert prevCctx != null : h2tbl.cacheName() + " is not initted";
+
+                mvccEnabled = prevCctx.mvccEnabled();
+
+                if (!mvccEnabled && !dmlInsideTxAllowed && prevCctx.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 " +
+                        "\"IGNITE_ALLOW_DML_INSIDE_TRANSACTION\" [cacheName=" + prevCctx.name() + ']');
+                }
+            }
+            else if (h2tbl.cacheContext().mvccEnabled() != mvccEnabled)
+                MvccUtils.throwAtomicityModesMismatchException(prevCctx, h2tbl.cacheContext());
+        }
+
+        if (stmt instanceof GridSqlMerge || stmt instanceof GridSqlInsert)
+            return planForInsert(stmt, loc, idx, mvccEnabled, conn, fieldsQry);
+        else if (stmt instanceof GridSqlUpdate || stmt instanceof GridSqlDelete)
+            return planForUpdate(stmt, loc, idx, mvccEnabled, conn, fieldsQry, errKeysPos);
+        else
+            throw new IgniteSQLException("Unsupported operation: " + prepared.getSQL(),
+                IgniteQueryErrorCode.UNSUPPORTED_OPERATION);
+    }
+
+    /**
+     * Extract all tables participate at query
+     *
+     * @param parser Parser related to the query.
+     * @return List of tables participate at query.
+     * @throws IgniteSQLException in case query contains virtual tables.
+     */
+    private static List<GridH2Table> extractTablesParticipateAtQuery(GridSqlQueryParser parser) throws IgniteSQLException {
+        Collection<?> parserObjects = parser.objectsMap().values();
+
+        List<GridH2Table> tbls = new ArrayList<>(parserObjects.size());
+
+        // check all involved caches
+        for (Object o : parserObjects) {
+            if (o instanceof GridSqlMerge)
                 o = ((GridSqlMerge)o).into();
+            else if (o instanceof GridSqlInsert)
+                o = ((GridSqlInsert)o).into();
             else if (o instanceof GridSqlUpdate)
                 o = ((GridSqlUpdate)o).target();
             else if (o instanceof GridSqlDelete)
@@ -121,39 +169,18 @@
                 o = GridSqlAlias.unwrap((GridSqlAst)o);
 
             if (o instanceof GridSqlTable) {
-                if (((GridSqlTable)o).dataTable() == null) { // Check for virtual tables.
+                GridH2Table h2tbl = ((GridSqlTable)o).dataTable();
+
+                if (h2tbl == null) { // Check for virtual tables.
                     throw new IgniteSQLException("Operation not supported for table '" +
                         ((GridSqlTable)o).tableName() + "'", IgniteQueryErrorCode.UNSUPPORTED_OPERATION);
                 }
 
-                if (prevCctx == null) {
-                    prevCctx = (((GridSqlTable)o).dataTable()).cache();
-
-                    mvccEnabled = prevCctx.mvccEnabled();
-
-                    if (!mvccEnabled && !dmlInsideTxAllowed && prevCctx.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 " +
-                            "\"IGNITE_ALLOW_DML_INSIDE_TRANSACTION\" [cacheName=" + prevCctx.name() + ']');
-                    }
-                }
-                else {
-                    GridCacheContext cctx = ((GridSqlTable)o).dataTable().cache();
-
-                    if (cctx.mvccEnabled() != mvccEnabled)
-                        MvccUtils.throwAtomicityModesMismatchException(prevCctx, cctx);
-                }
+                tbls.add(h2tbl);
             }
         }
 
-        if (stmt instanceof GridSqlMerge || stmt instanceof GridSqlInsert)
-            return planForInsert(stmt, loc, idx, mvccEnabled, conn, fieldsQry);
-        else if (stmt instanceof GridSqlUpdate || stmt instanceof GridSqlDelete)
-            return planForUpdate(stmt, loc, idx, mvccEnabled, conn, fieldsQry, errKeysPos);
-        else
-            throw new IgniteSQLException("Unsupported operation: " + prepared.getSQL(),
-                    IgniteQueryErrorCode.UNSUPPORTED_OPERATION);
+        return tbls;
     }
 
     /**
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2RowDescriptor.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2RowDescriptor.java
index 9c4941d..ddfc437 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2RowDescriptor.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2RowDescriptor.java
@@ -29,6 +29,7 @@
 import org.apache.ignite.IgniteCheckedException;
 import org.apache.ignite.internal.processors.cache.CacheObject;
 import org.apache.ignite.internal.processors.cache.GridCacheContext;
+import org.apache.ignite.internal.processors.cache.GridCacheContextInfo;
 import org.apache.ignite.internal.processors.cache.persistence.CacheDataRow;
 import org.apache.ignite.internal.processors.query.GridQueryProperty;
 import org.apache.ignite.internal.processors.query.GridQueryTypeDescriptor;
@@ -57,6 +58,7 @@
 import org.h2.value.ValueTime;
 import org.h2.value.ValueTimestamp;
 import org.h2.value.ValueUuid;
+import org.jetbrains.annotations.Nullable;
 
 import static org.apache.ignite.internal.processors.query.h2.opt.GridH2KeyValueRowOnheap.DEFAULT_COLUMNS_COUNT;
 import static org.apache.ignite.internal.processors.query.h2.opt.GridH2KeyValueRowOnheap.KEY_COL;
@@ -171,12 +173,22 @@
         return type;
     }
 
+
+    /**
+     * Gets cache context info for this row descriptor.
+     *
+     * @return Cache context info.
+     */
+    public GridCacheContextInfo<?, ?> cacheInfo() {
+        return tbl.cacheInfo();
+    }
+
     /**
      * Gets cache context for this row descriptor.
      *
      * @return Cache context.
      */
-    public GridCacheContext<?, ?> context() {
+    @Nullable public GridCacheContext<?, ?> context() {
         return tbl.cache();
     }
 
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2SystemIndexFactory.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2SystemIndexFactory.java
index f150b6a..fa1e5cb 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2SystemIndexFactory.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2SystemIndexFactory.java
@@ -17,19 +17,17 @@
 
 package org.apache.ignite.internal.processors.query.h2.opt;
 
-import org.apache.ignite.internal.processors.query.h2.database.H2TreeIndex;
-import org.h2.index.Index;
-
 import java.util.ArrayList;
+import org.apache.ignite.internal.processors.query.h2.database.H2TreeIndexBase;
+import org.h2.index.Index;
 
 /**
  * Factory for system table indexes.
  */
 public interface GridH2SystemIndexFactory {
     /**
-     * Create list of indexes. First must be primary key, after that all unique indexes and
-     * only then non-unique indexes.
-     * All indexes must be subtypes of {@link H2TreeIndex}.
+     * Create list of indexes. First must be primary key, after that all unique indexes and only then non-unique
+     * indexes. All indexes must be subtypes of {@link H2TreeIndexBase}.
      *
      * @param tbl Table to create indexes for.
      * @return List of indexes.
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2Table.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2Table.java
index b2da670..59597be 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2Table.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2Table.java
@@ -26,17 +26,19 @@
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.LongAdder;
 import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReadWriteLock;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
 import org.apache.ignite.IgniteCheckedException;
 import org.apache.ignite.IgniteInterruptedException;
 import org.apache.ignite.internal.processors.cache.GridCacheContext;
+import org.apache.ignite.internal.processors.cache.GridCacheContextInfo;
 import org.apache.ignite.internal.processors.cache.persistence.CacheDataRow;
 import org.apache.ignite.internal.processors.cache.query.QueryTable;
 import org.apache.ignite.internal.processors.query.IgniteSQLException;
 import org.apache.ignite.internal.processors.query.QueryField;
+import org.apache.ignite.internal.processors.query.h2.IndexRebuildPartialClosure;
 import org.apache.ignite.internal.processors.query.h2.database.H2RowFactory;
 import org.apache.ignite.internal.processors.query.h2.database.H2TreeIndex;
+import org.apache.ignite.internal.processors.query.h2.database.H2TreeIndexBase;
 import org.apache.ignite.internal.processors.query.h2.twostep.GridMapQueryExecutor;
 import org.apache.ignite.internal.util.typedef.F;
 import org.h2.command.ddl.CreateTableData;
@@ -69,8 +71,8 @@
     /** Insert hack flag. */
     private static final ThreadLocal<Boolean> INSERT_HACK = new ThreadLocal<>();
 
-    /** Cache context. */
-    private final GridCacheContext cctx;
+    /** Cache context info. */
+    private final GridCacheContextInfo cacheInfo;
 
     /** */
     private final GridH2RowDescriptor desc;
@@ -88,7 +90,7 @@
     private final Map<String, GridH2IndexBase> tmpIdxs = new HashMap<>();
 
     /** */
-    private final ReadWriteLock lock;
+    private final ReentrantReadWriteLock lock;
 
     /** */
     private boolean destroyed;
@@ -124,16 +126,17 @@
      * @param desc Row descriptor.
      * @param rowFactory Row factory.
      * @param idxsFactory Indexes factory.
-     * @param cctx Cache context.
+     * @param cacheInfo Cache context info.
      */
+    @SuppressWarnings("ConstantConditions")
     public GridH2Table(CreateTableData createTblData, GridH2RowDescriptor desc, H2RowFactory rowFactory,
-        GridH2SystemIndexFactory idxsFactory, GridCacheContext cctx) {
+        GridH2SystemIndexFactory idxsFactory, GridCacheContextInfo cacheInfo) {
         super(createTblData);
 
         assert idxsFactory != null;
 
         this.desc = desc;
-        this.cctx = cctx;
+        this.cacheInfo = cacheInfo;
 
         if (desc.context() != null && !desc.context().customAffinityMapper()) {
             boolean affinityColExists = true;
@@ -174,11 +177,14 @@
         assert idxs != null;
 
         List<Index> clones = new ArrayList<>(idxs.size());
+
         for (Index index : idxs) {
             Index clone = createDuplicateIndexIfNeeded(index);
+
             if (clone != null)
                 clones.add(clone);
         }
+
         idxs.addAll(clones);
 
         boolean hasHashIndex = idxs.size() >= 2 && index(0).getIndexType().isHash();
@@ -200,7 +206,7 @@
      * @return {@code true} If this is a partitioned table.
      */
     public boolean isPartitioned() {
-        return desc != null && desc.context().config().getCacheMode() == PARTITIONED;
+        return desc != null && desc.cacheInfo().config().getCacheMode() == PARTITIONED;
     }
 
     /**
@@ -226,21 +232,35 @@
      * @return Cache name.
      */
     public String cacheName() {
-        return cctx.name();
+        return cacheInfo.name();
     }
 
     /**
      * @return Cache ID.
      */
     public int cacheId() {
-        return cctx.cacheId();
+        return cacheInfo.cacheId();
+    }
+
+    /**
+     * @return Cache context info.
+     */
+    public GridCacheContextInfo cacheInfo() {
+        return cacheInfo;
+    }
+
+    /**
+     * @return {@code true} If Cache is lazy (not full inited).
+     */
+    public boolean isCacheLazy() {
+        return cacheInfo.gridCacheContext() == null;
     }
 
     /**
      * @return Cache context.
      */
-    public GridCacheContext cache() {
-        return cctx;
+    @Nullable public GridCacheContext cacheContext() {
+        return cacheInfo.gridCacheContext();
     }
 
     /** {@inheritDoc} */
@@ -550,12 +570,39 @@
     }
 
     /**
+     * Collect indexes for rebuild.
      *
+     * @param clo Closure.
+     */
+    public void collectIndexesForPartialRebuild(IndexRebuildPartialClosure clo) {
+        for (int i = sysIdxsCnt; i < idxs.size(); i++) {
+            Index idx = idxs.get(i);
+
+            if (idx instanceof H2TreeIndex) {
+                H2TreeIndex idx0 = (H2TreeIndex)idx;
+
+                if (idx0.rebuildRequired())
+                    clo.addIndex(this, idx0);
+            }
+        }
+    }
+
+    /**
+     * Mark or unmark index rebuild state.
      */
     public void markRebuildFromHashInProgress(boolean value) {
         assert !value || (idxs.size() >= 2 && index(1).getIndexType().isHash()) : "Table has no hash index.";
 
         rebuildFromHashInProgress = value;
+
+        lock.writeLock().lock();
+
+        try {
+            incrementModificationCounter();
+        }
+        finally {
+            lock.writeLock().unlock();
+        }
     }
 
     /**
@@ -636,7 +683,7 @@
             if (cloneIdx != null)
                 database.addSchemaObject(ses, cloneIdx);
 
-            setModified();
+            incrementModificationCounter();
 
             return idx;
         }
@@ -854,7 +901,7 @@
      * @return Proxy index.
      */
     private Index createDuplicateIndexIfNeeded(Index target) {
-        if (!(target instanceof H2TreeIndex) && !(target instanceof SpatialIndex))
+        if (!(target instanceof H2TreeIndexBase) && !(target instanceof SpatialIndex))
             return null;
 
         IndexColumn[] cols = target.getIndexColumns();
@@ -940,7 +987,7 @@
 
             desc.refreshMetadataFromTypeDescriptor();
 
-            setModified();
+            incrementModificationCounter();
         }
         finally {
             unlock(true);
@@ -948,9 +995,10 @@
     }
 
     /**
+     * Drop columns.
      *
-     * @param cols
-     * @param ifExists
+     * @param cols Columns.
+     * @param ifExists If EXISTS flag.
      */
     public void dropColumns(List<String> cols, boolean ifExists) {
         assert !ifExists || cols.size() == 1;
@@ -1002,7 +1050,7 @@
                     ((GridH2IndexBase)idx).refreshColumnIds();
             }
 
-            setModified();
+            incrementModificationCounter();
         }
         finally {
             unlock(true);
@@ -1031,6 +1079,15 @@
     }
 
     /**
+     * Increment modification counter to force recompilation of existing prepared statements.
+     */
+    private void incrementModificationCounter() {
+        assert lock.isWriteLockedByCurrentThread();
+
+        setModified();
+    }
+
+    /**
      * Set insert hack flag.
      *
      * @param val Value.
@@ -1064,4 +1121,4 @@
 
         return true;
     }
-}
\ No newline at end of file
+}
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQueryParser.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQueryParser.java
index 122a9f7..34e223c 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQueryParser.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQueryParser.java
@@ -1728,7 +1728,11 @@
                 GridH2Table tbl = ((GridSqlTable)o).dataTable();
 
                 if (tbl != null) {
-                    GridCacheContext cctx = tbl.cache();
+                    //It's not affinity cache. Can't be local.
+                    if (tbl.cacheContext() == null)
+                        return false;
+
+                    GridCacheContext cctx = tbl.cacheContext();
 
                     if (cctx.mvccEnabled())
                         return false;
@@ -1759,8 +1763,8 @@
             if (o instanceof GridSqlTable) {
                 GridH2Table tbl = ((GridSqlTable)o).dataTable();
 
-                if (tbl != null && tbl.cache().isPartitioned())
-                    return tbl.cache();
+                if (tbl != null && tbl.cacheContext().isPartitioned())
+                    return tbl.cacheContext();
             }
         }
 
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/GridReduceQueryExecutor.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/GridReduceQueryExecutor.java
index 36287b3..905a4a3 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/GridReduceQueryExecutor.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/GridReduceQueryExecutor.java
@@ -22,16 +22,12 @@
 import java.sql.SQLException;
 import java.sql.Statement;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
 import java.util.Iterator;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.Set;
 import java.util.UUID;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
@@ -47,7 +43,6 @@
 import org.apache.ignite.IgniteException;
 import org.apache.ignite.IgniteLogger;
 import org.apache.ignite.IgniteSystemProperties;
-import org.apache.ignite.cache.PartitionLossPolicy;
 import org.apache.ignite.cache.query.QueryCancelledException;
 import org.apache.ignite.cluster.ClusterNode;
 import org.apache.ignite.events.DiscoveryEvent;
@@ -61,7 +56,6 @@
 import org.apache.ignite.internal.managers.eventstorage.GridLocalEventListener;
 import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion;
 import org.apache.ignite.internal.processors.cache.GridCacheContext;
-import org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridDhtPartitionState;
 import org.apache.ignite.internal.processors.cache.distributed.near.GridNearTxLocal;
 import org.apache.ignite.internal.processors.cache.distributed.near.GridNearTxSelectForUpdateFuture;
 import org.apache.ignite.internal.processors.cache.distributed.near.TxTopologyVersionFuture;
@@ -89,8 +83,6 @@
 import org.apache.ignite.internal.processors.query.h2.twostep.msg.GridH2DmlResponse;
 import org.apache.ignite.internal.processors.query.h2.twostep.msg.GridH2QueryRequest;
 import org.apache.ignite.internal.processors.query.h2.twostep.msg.GridH2SelectForUpdateTxDetails;
-import org.apache.ignite.internal.util.GridIntIterator;
-import org.apache.ignite.internal.util.GridIntList;
 import org.apache.ignite.internal.util.GridSpinBusyLock;
 import org.apache.ignite.internal.util.typedef.C2;
 import org.apache.ignite.internal.util.typedef.CIX2;
@@ -113,9 +105,6 @@
 
 import static java.util.Collections.singletonList;
 import static org.apache.ignite.IgniteSystemProperties.IGNITE_SQL_RETRY_TIMEOUT;
-import static org.apache.ignite.cache.PartitionLossPolicy.READ_ONLY_SAFE;
-import static org.apache.ignite.cache.PartitionLossPolicy.READ_WRITE_SAFE;
-import static org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion.NONE;
 import static org.apache.ignite.internal.processors.cache.mvcc.MvccUtils.checkActive;
 import static org.apache.ignite.internal.processors.cache.mvcc.MvccUtils.mvccEnabled;
 import static org.apache.ignite.internal.processors.cache.mvcc.MvccUtils.tx;
@@ -138,9 +127,6 @@
     private static final String MERGE_INDEX_SORTED = "merge_sorted";
 
     /** */
-    private static final Set<ClusterNode> UNMAPPED_PARTS = Collections.emptySet();
-
-    /** */
     private GridKernalContext ctx;
 
     /** */
@@ -174,7 +160,12 @@
         }
     };
 
+    /** Partition mapper. */
+    private ReducePartitionMapper mapper;
+
     /**
+     * Constructor.
+     *
      * @param qryIdGen Query ID generator.
      * @param busyLock Busy lock.
      */
@@ -194,6 +185,8 @@
 
         log = ctx.log(GridReduceQueryExecutor.class);
 
+        mapper = new ReducePartitionMapper(ctx, log);
+
         ctx.io().addMessageListener(GridTopic.TOPIC_QUERY, new GridMessageListener() {
             @SuppressWarnings("deprecation")
             @Override public void onMessage(UUID nodeId, Object msg, byte plc) {
@@ -370,32 +363,6 @@
     }
 
     /**
-     * @param cacheIds Cache IDs.
-     * @return {@code true} If preloading is active.
-     */
-    private boolean isPreloadingActive(List<Integer> cacheIds) {
-        for (Integer cacheId : cacheIds) {
-            if (null == cacheContext(cacheId))
-                throw new CacheException(String.format("Cache not found on local node [cacheId=%d]", cacheId));
-
-            if (hasMovingPartitions(cacheContext(cacheId)))
-                return true;
-        }
-
-        return false;
-    }
-
-    /**
-     * @param cctx Cache context.
-     * @return {@code True} If cache has partitions in {@link GridDhtPartitionState#MOVING} state.
-     */
-    private boolean hasMovingPartitions(GridCacheContext<?, ?> cctx) {
-        assert cctx != null;
-
-        return !cctx.isLocal() && cctx.topology().hasMovingPartitions();
-    }
-
-    /**
      * @param cacheId Cache ID.
      * @return Cache context.
      */
@@ -404,154 +371,6 @@
     }
 
     /**
-     * @param topVer Topology version.
-     * @param cctx Cache context.
-     * @param parts Partitions.
-     */
-    private Map<ClusterNode, IntArray> stableDataNodesMap(AffinityTopologyVersion topVer,
-        final GridCacheContext<?, ?> cctx, @Nullable final int[] parts) {
-
-        Map<ClusterNode, IntArray> mapping = new HashMap<>();
-
-        // Explicit partitions mapping is not applicable to replicated cache.
-        if (cctx.isReplicated()) {
-            for (ClusterNode clusterNode : cctx.affinity().assignment(topVer).nodes())
-                mapping.put(clusterNode, null);
-
-            return mapping;
-        }
-
-        List<List<ClusterNode>> assignment = cctx.affinity().assignment(topVer).assignment();
-
-        boolean needPartsFilter = parts != null;
-
-        GridIntIterator iter = needPartsFilter ? new GridIntList(parts).iterator() :
-            U.forRange(0, cctx.affinity().partitions());
-
-        while(iter.hasNext()) {
-            int partId = iter.next();
-
-            List<ClusterNode> partNodes = assignment.get(partId);
-
-            if (!partNodes.isEmpty()) {
-                ClusterNode prim = partNodes.get(0);
-
-                if (!needPartsFilter) {
-                    mapping.put(prim, null);
-
-                    continue;
-                }
-
-                IntArray partIds = mapping.get(prim);
-
-                if (partIds == null) {
-                    partIds = new IntArray();
-
-                    mapping.put(prim, partIds);
-                }
-
-                partIds.add(partId);
-            }
-        }
-
-        return mapping;
-    }
-
-    /**
-     * Load failed partition reservation.
-     *
-     * @param msg Message.
-     */
-    private void logRetry(String msg) {
-        log.info(msg);
-    }
-
-    /**
-     * @param isReplicatedOnly If we must only have replicated caches.
-     * @param topVer Topology version.
-     * @param cacheIds Participating cache IDs.
-     * @param parts Partitions.
-     * @param qryId Query ID.
-     * @return Data nodes or {@code null} if repartitioning started and we need to retry.
-     */
-    private Map<ClusterNode, IntArray> stableDataNodes(boolean isReplicatedOnly, AffinityTopologyVersion topVer,
-        List<Integer> cacheIds, int[] parts, long qryId) {
-        GridCacheContext<?, ?> cctx = cacheContext(cacheIds.get(0));
-
-        // If the first cache is not partitioned, find it (if it's present) and move it to index 0.
-        if (!cctx.isPartitioned()) {
-            for (int cacheId = 1; cacheId < cacheIds.size(); cacheId++) {
-                GridCacheContext<?, ?> currCctx = cacheContext(cacheIds.get(cacheId));
-
-                if (currCctx.isPartitioned()) {
-                    Collections.swap(cacheIds, 0, cacheId);
-
-                    cctx = currCctx;
-
-                    break;
-                }
-            }
-        }
-
-        Map<ClusterNode, IntArray> map = stableDataNodesMap(topVer, cctx, parts);
-
-        Set<ClusterNode> nodes = map.keySet();
-
-        if (F.isEmpty(map))
-            throw new CacheException("Failed to find data nodes for cache: " + cctx.name());
-
-        for (int i = 1; i < cacheIds.size(); i++) {
-            GridCacheContext<?,?> extraCctx = cacheContext(cacheIds.get(i));
-
-            String extraCacheName = extraCctx.name();
-
-            if (extraCctx.isLocal())
-                continue; // No consistency guaranties for local caches.
-
-            if (isReplicatedOnly && !extraCctx.isReplicated())
-                throw new CacheException("Queries running on replicated cache should not contain JOINs " +
-                    "with partitioned tables [replicatedCache=" + cctx.name() +
-                    ", partitionedCache=" + extraCacheName + "]");
-
-            Set<ClusterNode> extraNodes = stableDataNodesMap(topVer, extraCctx, parts).keySet();
-
-            if (F.isEmpty(extraNodes))
-                throw new CacheException("Failed to find data nodes for cache: " + extraCacheName);
-
-            boolean disjoint;
-
-            if (extraCctx.isReplicated()) {
-                if (isReplicatedOnly) {
-                    nodes.retainAll(extraNodes);
-
-                    disjoint = map.isEmpty();
-                }
-                else
-                    disjoint = !extraNodes.containsAll(nodes);
-            }
-            else
-                disjoint = !extraNodes.equals(nodes);
-
-            if (disjoint) {
-                if (isPreloadingActive(cacheIds)) {
-                    logRetry("Failed to calculate nodes for SQL query (got disjoint node map during rebalance) " +
-                        "[qryId=" + qryId + ", affTopVer=" + topVer + ", cacheIds=" + cacheIds +
-                        ", parts=" + (parts == null ? "[]" : Arrays.toString(parts)) +
-                        ", replicatedOnly=" + isReplicatedOnly + ", lastCache=" + extraCctx.name() +
-                        ", lastCacheId=" + extraCctx.cacheId() + ']');
-
-                    return null; // Retry.
-                }
-                else
-                    throw new CacheException("Caches have distinct sets of data nodes [cache1=" + cctx.name() +
-                        ", cache2=" + extraCacheName + "]");
-            }
-        }
-
-        return map;
-    }
-
-    /**
      * @param schemaName Schema name.
      * @param qry Query.
      * @param keepBinary Keep binary.
@@ -686,8 +505,8 @@
             if (qry.isLocal())
                 nodes = singletonList(ctx.discovery().localNode());
             else {
-                NodesForPartitionsResult nodesParts =
-                    nodesForPartitions(cacheIds, topVer, parts, isReplicatedOnly, qryReqId);
+                ReducePartitionMapResult nodesParts =
+                    mapper.nodesForPartitions(cacheIds, topVer, parts, isReplicatedOnly, qryReqId);
 
                 nodes = nodesParts.nodes();
                 partsMap = nodesParts.partitionsMap();
@@ -843,7 +662,7 @@
                     req.mvccSnapshot(mvccTracker.snapshot());
 
                 final C2<ClusterNode, Message, Message> pspec =
-                    (parts == null ? null : new ExplicitPartitionsSpecializer(qryMap));
+                    (parts == null ? null : new ReducePartitionsSpecializer(qryMap));
 
                 final C2<ClusterNode, Message, Message> spec;
 
@@ -905,7 +724,7 @@
                 else // Send failed.
                     retry = true;
 
-                Iterator<List<?>> resIter = null;
+                Iterator<List<?>> resIter;
 
                 if (!retry) {
                     if (skipMergeTbl) {
@@ -1050,7 +869,8 @@
 
         final long reqId = qryIdGen.incrementAndGet();
 
-        NodesForPartitionsResult nodesParts = nodesForPartitions(cacheIds, topVer, parts, isReplicatedOnly, reqId);
+        ReducePartitionMapResult nodesParts =
+            mapper.nodesForPartitions(cacheIds, topVer, parts, isReplicatedOnly, reqId);
 
         final GridRunningQueryInfo qryInfo = new GridRunningQueryInfo(reqId, selectQry, GridCacheQueryType.SQL_FIELDS,
             schemaName, U.currentTimeMillis(), cancel, false);
@@ -1105,8 +925,8 @@
             Map<ClusterNode, IntArray> partsMap = (nodesParts.queryPartitionsMap() != null) ?
                 nodesParts.queryPartitionsMap() : nodesParts.partitionsMap();
 
-            ExplicitPartitionsSpecializer partsSpec = (parts == null) ? null :
-                new ExplicitPartitionsSpecializer(partsMap);
+            ReducePartitionsSpecializer partsSpec = (parts == null) ? null :
+                new ReducePartitionsSpecializer(partsMap);
 
             final Collection<ClusterNode> finalNodes = nodes;
 
@@ -1290,286 +1110,6 @@
     }
 
     /**
-     * Calculates data nodes for replicated caches on unstable topology.
-     *
-     * @param cacheIds Cache IDs.
-     * @param qryId Query ID.
-     * @return Collection of all data nodes owning all the caches or {@code null} for retry.
-     */
-    private Collection<ClusterNode> replicatedUnstableDataNodes(List<Integer> cacheIds, long qryId) {
-        int i = 0;
-
-        GridCacheContext<?, ?> cctx = cacheContext(cacheIds.get(i++));
-
-        // The main cache is allowed to be partitioned.
-        if (!cctx.isReplicated()) {
-            assert cacheIds.size() > 1: "no extra replicated caches with partitioned main cache";
-
-            // Just replace the main cache with the first one extra.
-            cctx = cacheContext(cacheIds.get(i++));
-
-            assert cctx.isReplicated(): "all the extra caches must be replicated here";
-        }
-
-        Set<ClusterNode> nodes = replicatedUnstableDataNodes(cctx, qryId);
-
-        if (F.isEmpty(nodes))
-            return null; // Retry.
-
-        for (;i < cacheIds.size(); i++) {
-            GridCacheContext<?, ?> extraCctx = cacheContext(cacheIds.get(i));
-
-            if (extraCctx.isLocal())
-                continue;
-
-            if (!extraCctx.isReplicated())
-                throw new CacheException("Queries running on replicated cache should not contain JOINs " +
-                    "with tables in partitioned caches [replicatedCache=" + cctx.name() + ", " +
-                    "partitionedCache=" + extraCctx.name() + "]");
-
-            Set<ClusterNode> extraOwners = replicatedUnstableDataNodes(extraCctx, qryId);
-
-            if (F.isEmpty(extraOwners))
-                return null; // Retry.
-
-            nodes.retainAll(extraOwners);
-
-            if (nodes.isEmpty()) {
-                logRetry("Failed to calculate nodes for SQL query (got disjoint node map for REPLICATED caches " +
-                    "during rebalance) [qryId=" + qryId + ", cacheIds=" + cacheIds +
-                    ", lastCache=" + extraCctx.name() + ", lastCacheId=" + extraCctx.cacheId() + ']');
-
-                return null; // Retry.
-            }
-        }
-
-        return nodes;
-    }
-
-    /**
-     * @param grpId Cache group ID.
-     * @param topVer Topology version.
-     * @return Collection of data nodes.
-     */
-    private Collection<ClusterNode> dataNodes(int grpId, AffinityTopologyVersion topVer) {
-        Collection<ClusterNode> res = ctx.discovery().cacheGroupAffinityNodes(grpId, topVer);
-
-        return res != null ? res : Collections.<ClusterNode>emptySet();
-    }
-
-    /**
-     * Collects all the nodes owning all the partitions for the given replicated cache.
-     *
-     * @param cctx Cache context.
-     * @param qryId Query ID.
-     * @return Owning nodes or {@code null} if we can't find owners for some partitions.
-     */
-    private Set<ClusterNode> replicatedUnstableDataNodes(GridCacheContext<?,?> cctx, long qryId) {
-        assert cctx.isReplicated() : cctx.name() + " must be replicated";
-
-        String cacheName = cctx.name();
-
-        Set<ClusterNode> dataNodes = new HashSet<>(dataNodes(cctx.groupId(), NONE));
-
-        if (dataNodes.isEmpty())
-            throw new CacheException("Failed to find data nodes for cache: " + cacheName);
-
-        // Find all the nodes owning all the partitions for replicated cache.
-        for (int p = 0, parts = cctx.affinity().partitions(); p < parts; p++) {
-            List<ClusterNode> owners = cctx.topology().owners(p);
-
-            if (F.isEmpty(owners)) {
-                logRetry("Failed to calculate nodes for SQL query (partition of a REPLICATED cache has no owners) [" +
-                    "qryId=" + qryId + ", cacheName=" + cctx.name() + ", cacheId=" + cctx.cacheId() +
-                    ", part=" + p + ']');
-
-                return null; // Retry.
-            }
-
-            dataNodes.retainAll(owners);
-
-            if (dataNodes.isEmpty()) {
-                logRetry("Failed to calculate nodes for SQL query (partitions of a REPLICATED has no common owners) [" +
-                    "qryId=" + qryId + ", cacheName=" + cctx.name() + ", cacheId=" + cctx.cacheId() +
-                    ", lastPart=" + p + ']');
-
-                return null; // Retry.
-            }
-        }
-
-        return dataNodes;
-    }
-
-    /**
-     * Calculates partition mapping for partitioned cache on unstable topology.
-     *
-     * @param cacheIds Cache IDs.
-     * @param qryId Query ID.
-     * @return Partition mapping or {@code null} if we can't calculate it due to repartitioning and we need to retry.
-     */
-    @SuppressWarnings("unchecked")
-    private Map<ClusterNode, IntArray> partitionedUnstableDataNodes(List<Integer> cacheIds, long qryId) {
-        // If the main cache is replicated, just replace it with the first partitioned.
-        GridCacheContext<?,?> cctx = findFirstPartitioned(cacheIds);
-
-        final int partsCnt = cctx.affinity().partitions();
-
-        if (cacheIds.size() > 1) { // Check correct number of partitions for partitioned caches.
-            for (Integer cacheId : cacheIds) {
-                GridCacheContext<?, ?> extraCctx = cacheContext(cacheId);
-
-                if (extraCctx.isReplicated() || extraCctx.isLocal())
-                    continue;
-
-                int parts = extraCctx.affinity().partitions();
-
-                if (parts != partsCnt)
-                    throw new CacheException("Number of partitions must be the same for correct collocation [cache1=" +
-                        cctx.name() + ", parts1=" + partsCnt + ", cache2=" + extraCctx.name() +
-                        ", parts2=" + parts + "]");
-            }
-        }
-
-        Set<ClusterNode>[] partLocs = new Set[partsCnt];
-
-        // Fill partition locations for main cache.
-        for (int p = 0; p < partsCnt; p++) {
-            List<ClusterNode> owners = cctx.topology().owners(p);
-
-            if (F.isEmpty(owners)) {
-                // Handle special case: no mapping is configured for a partition.
-                if (F.isEmpty(cctx.affinity().assignment(NONE).get(p))) {
-                    partLocs[p] = UNMAPPED_PARTS; // Mark unmapped partition.
-
-                    continue;
-                }
-                else if (!F.isEmpty(dataNodes(cctx.groupId(), NONE))) {
-                    logRetry("Failed to calculate nodes for SQL query (partition has no owners, but corresponding " +
-                        "cache group has data nodes) [qryId=" + qryId + ", cacheIds=" + cacheIds +
-                        ", cacheName=" + cctx.name() + ", cacheId=" + cctx.cacheId() + ", part=" + p +
-                        ", cacheGroupId=" + cctx.groupId() + ']');
-
-                    return null; // Retry.
-                }
-
-                throw new CacheException("Failed to find data nodes [cache=" + cctx.name() + ", part=" + p + "]");
-            }
-
-            partLocs[p] = new HashSet<>(owners);
-        }
-
-        if (cacheIds.size() > 1) {
-            // Find owner intersections for each participating partitioned cache partition.
-            // We need this for logical collocation between different partitioned caches with the same affinity.
-            for (Integer cacheId : cacheIds) {
-                GridCacheContext<?, ?> extraCctx = cacheContext(cacheId);
-
-                // This is possible if we have replaced a replicated cache with a partitioned one earlier.
-                if (cctx == extraCctx)
-                    continue;
-
-                if (extraCctx.isReplicated() || extraCctx.isLocal())
-                    continue;
-
-                for (int p = 0, parts = extraCctx.affinity().partitions(); p < parts; p++) {
-                    List<ClusterNode> owners = extraCctx.topology().owners(p);
-
-                    if (partLocs[p] == UNMAPPED_PARTS)
-                        continue; // Skip unmapped partitions.
-
-                    if (F.isEmpty(owners)) {
-                        if (!F.isEmpty(dataNodes(extraCctx.groupId(), NONE))) {
-                            logRetry("Failed to calculate nodes for SQL query (partition has no owners, but " +
-                                "corresponding cache group has data nodes) [qryId=" + qryId +
-                                ", cacheIds=" + cacheIds + ", cacheName=" + extraCctx.name() +
-                                ", cacheId=" + extraCctx.cacheId() + ", part=" + p +
-                                ", cacheGroupId=" + extraCctx.groupId() + ']');
-
-                            return null; // Retry.
-                        }
-
-                        throw new CacheException("Failed to find data nodes [cache=" + extraCctx.name() +
-                            ", part=" + p + "]");
-                    }
-
-                    if (partLocs[p] == null)
-                        partLocs[p] = new HashSet<>(owners);
-                    else {
-                        partLocs[p].retainAll(owners); // Intersection of owners.
-
-                        if (partLocs[p].isEmpty()) {
-                            logRetry("Failed to calculate nodes for SQL query (caches have no common data nodes for " +
-                                "partition) [qryId=" + qryId + ", cacheIds=" + cacheIds +
-                                ", lastCacheName=" + extraCctx.name() + ", lastCacheId=" + extraCctx.cacheId() +
-                                ", part=" + p + ']');
-
-                            return null; // Intersection is empty -> retry.
-                        }
-                    }
-                }
-            }
-
-            // Filter nodes where not all the replicated caches loaded.
-            for (Integer cacheId : cacheIds) {
-                GridCacheContext<?, ?> extraCctx = cacheContext(cacheId);
-
-                if (!extraCctx.isReplicated())
-                    continue;
-
-                Set<ClusterNode> dataNodes = replicatedUnstableDataNodes(extraCctx, qryId);
-
-                if (F.isEmpty(dataNodes))
-                    return null; // Retry.
-
-                int part = 0;
-
-                for (Set<ClusterNode> partLoc : partLocs) {
-                    if (partLoc == UNMAPPED_PARTS)
-                        continue; // Skip unmapped partition.
-
-                    partLoc.retainAll(dataNodes);
-
-                    if (partLoc.isEmpty()) {
-                        logRetry("Failed to calculate nodes for SQL query (caches have no common data nodes for " +
-                            "partition) [qryId=" + qryId + ", cacheIds=" + cacheIds +
-                            ", lastReplicatedCacheName=" + extraCctx.name() +
-                            ", lastReplicatedCacheId=" + extraCctx.cacheId() + ", part=" + part + ']');
-
-                        return null; // Retry.
-                    }
-
-                    part++;
-                }
-            }
-        }
-
-        // Collect the final partitions mapping.
-        Map<ClusterNode, IntArray> res = new HashMap<>();
-
-        // Here partitions in all IntArray's will be sorted in ascending order, this is important.
-        for (int p = 0; p < partLocs.length; p++) {
-            Set<ClusterNode> pl = partLocs[p];
-
-            // Skip unmapped partitions.
-            if (pl == UNMAPPED_PARTS)
-                continue;
-
-            assert !F.isEmpty(pl) : pl;
-
-            ClusterNode n = pl.size() == 1 ? F.first(pl) : F.rand(pl);
-
-            IntArray parts = res.get(n);
-
-            if (parts == null)
-                res.put(n, parts = new IntArray());
-
-            parts.add(p);
-        }
-
-        return res;
-    }
-
-    /**
      * @param c Connection.
      * @param qry Query.
      * @param params Query parameters.
@@ -1681,63 +1221,6 @@
     }
 
     /**
-     * Evaluates nodes and nodes to partitions map given a list of cache ids, topology version and partitions.
-     *
-     * @param cacheIds Cache ids.
-     * @param topVer Topology version.
-     * @param parts Partitions array.
-     * @param isReplicatedOnly Allow only replicated caches.
-     * @param qryId Query ID.
-     * @return Result.
-     */
-    private NodesForPartitionsResult nodesForPartitions(List<Integer> cacheIds, AffinityTopologyVersion topVer,
-        int[] parts, boolean isReplicatedOnly, long qryId) {
-        Collection<ClusterNode> nodes = null;
-        Map<ClusterNode, IntArray> partsMap = null;
-        Map<ClusterNode, IntArray> qryMap = null;
-
-        for (int cacheId : cacheIds) {
-            GridCacheContext<?, ?> cctx = cacheContext(cacheId);
-
-            PartitionLossPolicy plc = cctx.config().getPartitionLossPolicy();
-
-            if (plc != READ_ONLY_SAFE && plc != READ_WRITE_SAFE)
-                continue;
-
-            Collection<Integer> lostParts = cctx.topology().lostPartitions();
-
-            for (int part : lostParts) {
-                if (parts == null || Arrays.binarySearch(parts, part) >= 0) {
-                    throw new CacheException("Failed to execute query because cache partition has been " +
-                        "lost [cacheName=" + cctx.name() + ", part=" + part + ']');
-                }
-            }
-        }
-
-        if (isPreloadingActive(cacheIds)) {
-            if (isReplicatedOnly)
-                nodes = replicatedUnstableDataNodes(cacheIds, qryId);
-            else {
-                partsMap = partitionedUnstableDataNodes(cacheIds, qryId);
-
-                if (partsMap != null) {
-                    qryMap = narrowForQuery(partsMap, parts);
-
-                    nodes = qryMap == null ? null : qryMap.keySet();
-                }
-            }
-        }
-        else {
-            qryMap = stableDataNodes(isReplicatedOnly, topVer, cacheIds, parts, qryId);
-
-            if (qryMap != null)
-                nodes = qryMap.keySet();
-        }
-
-        return new NodesForPartitionsResult(nodes, partsMap, qryMap);
-    }
-
-    /**
      * @param conn Connection.
      * @param qry Query.
      * @param explain Explain.
@@ -1881,32 +1364,6 @@
         }
     }
 
-    /** */
-    private Map<ClusterNode, IntArray> narrowForQuery(Map<ClusterNode, IntArray> partsMap, int[] parts) {
-        if (parts == null)
-            return partsMap;
-
-        Map<ClusterNode, IntArray> cp = U.newHashMap(partsMap.size());
-
-        for (Map.Entry<ClusterNode, IntArray> entry : partsMap.entrySet()) {
-            IntArray filtered = new IntArray(parts.length);
-
-            IntArray orig = entry.getValue();
-
-            for (int i = 0; i < orig.size(); i++) {
-                int p = orig.get(i);
-
-                if (Arrays.binarySearch(parts, p) >= 0)
-                    filtered.add(p);
-            }
-
-            if (filtered.size() > 0)
-                cp.put(entry.getKey(), filtered);
-        }
-
-        return cp.isEmpty() ? null : cp;
-    }
-
     /**
      * @param qryTimeout Query timeout.
      * @return Query retry timeout.
@@ -1917,79 +1374,4 @@
 
         return IgniteSystemProperties.getLong(IGNITE_SQL_RETRY_TIMEOUT, DFLT_RETRY_TIMEOUT);
     }
-
-    /** */
-    private static class ExplicitPartitionsSpecializer implements C2<ClusterNode, Message, Message> {
-        /** Partitions map. */
-        private final Map<ClusterNode, IntArray> partsMap;
-
-        /**
-         * @param partsMap Partitions map.
-         */
-        public ExplicitPartitionsSpecializer(Map<ClusterNode, IntArray> partsMap) {
-            this.partsMap = partsMap;
-        }
-
-        /** {@inheritDoc} */
-        @Override public Message apply(ClusterNode node, Message msg) {
-            if (msg instanceof GridH2QueryRequest) {
-                GridH2QueryRequest rq = new GridH2QueryRequest((GridH2QueryRequest)msg);
-
-                rq.queryPartitions(toArray(partsMap.get(node)));
-
-                return rq;
-            } else if (msg instanceof GridH2DmlRequest) {
-                GridH2DmlRequest rq = new GridH2DmlRequest((GridH2DmlRequest)msg);
-
-                rq.queryPartitions(toArray(partsMap.get(node)));
-
-                return rq;
-            }
-
-            return msg;
-        }
-    }
-
-    /**
-     * Result of nodes to partitions mapping for a query or update.
-     */
-    static class NodesForPartitionsResult {
-        /** */
-        final Collection<ClusterNode> nodes;
-
-        /** */
-        final Map<ClusterNode, IntArray> partsMap;
-
-        /** */
-        final Map<ClusterNode, IntArray> qryMap;
-
-        /** */
-        NodesForPartitionsResult(Collection<ClusterNode> nodes, Map<ClusterNode, IntArray> partsMap,
-            Map<ClusterNode, IntArray> qryMap) {
-            this.nodes = nodes;
-            this.partsMap = partsMap;
-            this.qryMap = qryMap;
-        }
-
-        /**
-         * @return Collection of nodes a message shall be sent to.
-         */
-        Collection<ClusterNode> nodes() {
-            return nodes;
-        }
-
-        /**
-         * @return Maps a node to partition array.
-         */
-        Map<ClusterNode, IntArray> partitionsMap() {
-            return partsMap;
-        }
-
-        /**
-         * @return Maps a node to partition array.
-         */
-        Map<ClusterNode, IntArray> queryPartitionsMap() {
-            return qryMap;
-        }
-    }
 }
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/ReducePartitionMapResult.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/ReducePartitionMapResult.java
new file mode 100644
index 0000000..83bbf8e
--- /dev/null
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/ReducePartitionMapResult.java
@@ -0,0 +1,73 @@
+/*
+ * 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.twostep;
+
+import org.apache.ignite.cluster.ClusterNode;
+import org.h2.util.IntArray;
+
+import java.util.Collection;
+import java.util.Map;
+
+/**
+ * Result of nodes to partitions mapping for a query or update.
+ */
+public class ReducePartitionMapResult {
+    /** */
+    private final Collection<ClusterNode> nodes;
+
+    /** */
+    private final Map<ClusterNode, IntArray> partsMap;
+
+    /** */
+    private final Map<ClusterNode, IntArray> qryMap;
+
+    /**
+     * Constructor.
+     *
+     * @param nodes Nodes.
+     * @param partsMap Partitions map.
+     * @param qryMap Nodes map.
+     */
+    public ReducePartitionMapResult(Collection<ClusterNode> nodes, Map<ClusterNode, IntArray> partsMap,
+        Map<ClusterNode, IntArray> qryMap) {
+        this.nodes = nodes;
+        this.partsMap = partsMap;
+        this.qryMap = qryMap;
+    }
+
+    /**
+     * @return Collection of nodes a message shall be sent to.
+     */
+    public Collection<ClusterNode> nodes() {
+        return nodes;
+    }
+
+    /**
+     * @return Maps a node to partition array.
+     */
+    public Map<ClusterNode, IntArray> partitionsMap() {
+        return partsMap;
+    }
+
+    /**
+     * @return Maps a node to partition array.
+     */
+    public Map<ClusterNode, IntArray> queryPartitionsMap() {
+        return qryMap;
+    }
+}
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/ReducePartitionMapper.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/ReducePartitionMapper.java
new file mode 100644
index 0000000..1112d19
--- /dev/null
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/ReducePartitionMapper.java
@@ -0,0 +1,638 @@
+/*
+ * 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.twostep;
+
+import org.apache.ignite.IgniteLogger;
+import org.apache.ignite.cache.PartitionLossPolicy;
+import org.apache.ignite.cluster.ClusterNode;
+import org.apache.ignite.internal.GridKernalContext;
+import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion;
+import org.apache.ignite.internal.processors.cache.GridCacheContext;
+import org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridDhtPartitionState;
+import org.apache.ignite.internal.util.GridIntIterator;
+import org.apache.ignite.internal.util.GridIntList;
+import org.apache.ignite.internal.util.typedef.F;
+import org.apache.ignite.internal.util.typedef.internal.U;
+import org.h2.util.IntArray;
+import org.jetbrains.annotations.Nullable;
+
+import javax.cache.CacheException;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import static org.apache.ignite.cache.PartitionLossPolicy.READ_ONLY_SAFE;
+import static org.apache.ignite.cache.PartitionLossPolicy.READ_WRITE_SAFE;
+import static org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion.NONE;
+
+/**
+ * Reduce partition mapper.
+ */
+public class ReducePartitionMapper {
+    /** */
+    private static final Set<ClusterNode> UNMAPPED_PARTS = Collections.emptySet();
+
+    /** Kernal context. */
+    private final GridKernalContext ctx;
+
+    /** */
+    private final IgniteLogger log;
+
+    /**
+     * Constructor.
+     *
+     * @param ctx Kernal context.
+     */
+    public ReducePartitionMapper(GridKernalContext ctx, IgniteLogger log) {
+        this.ctx = ctx;
+        this.log = log;
+    }
+
+    /**
+     * Evaluates nodes and nodes to partitions map given a list of cache ids, topology version and partitions.
+     *
+     * @param cacheIds Cache ids.
+     * @param topVer Topology version.
+     * @param parts Partitions array.
+     * @param isReplicatedOnly Allow only replicated caches.
+     * @param qryId Query ID.
+     * @return Result.
+     */
+    public ReducePartitionMapResult nodesForPartitions(List<Integer> cacheIds, AffinityTopologyVersion topVer,
+        int[] parts, boolean isReplicatedOnly, long qryId) {
+        Collection<ClusterNode> nodes = null;
+        Map<ClusterNode, IntArray> partsMap = null;
+        Map<ClusterNode, IntArray> qryMap = null;
+
+        for (int cacheId : cacheIds) {
+            GridCacheContext<?, ?> cctx = cacheContext(cacheId);
+
+            PartitionLossPolicy plc = cctx.config().getPartitionLossPolicy();
+
+            if (plc != READ_ONLY_SAFE && plc != READ_WRITE_SAFE)
+                continue;
+
+            Collection<Integer> lostParts = cctx.topology().lostPartitions();
+
+            for (int part : lostParts) {
+                if (parts == null || Arrays.binarySearch(parts, part) >= 0) {
+                    throw new CacheException("Failed to execute query because cache partition has been " +
+                        "lost [cacheName=" + cctx.name() + ", part=" + part + ']');
+                }
+            }
+        }
+
+        if (isPreloadingActive(cacheIds)) {
+            if (isReplicatedOnly)
+                nodes = replicatedUnstableDataNodes(cacheIds, qryId);
+            else {
+                partsMap = partitionedUnstableDataNodes(cacheIds, qryId);
+
+                if (partsMap != null) {
+                    qryMap = narrowForQuery(partsMap, parts);
+
+                    nodes = qryMap == null ? null : qryMap.keySet();
+                }
+            }
+        }
+        else {
+            qryMap = stableDataNodes(isReplicatedOnly, topVer, cacheIds, parts, qryId);
+
+            if (qryMap != null)
+                nodes = qryMap.keySet();
+        }
+
+        return new ReducePartitionMapResult(nodes, partsMap, qryMap);
+    }
+
+    /**
+     * @param cacheId Cache ID.
+     * @return Cache context.
+     */
+    private GridCacheContext<?,?> cacheContext(Integer cacheId) {
+        return ctx.cache().context().cacheContext(cacheId);
+    }
+
+    /**
+     * @param cacheIds Cache IDs.
+     * @return {@code true} If preloading is active.
+     */
+    private boolean isPreloadingActive(List<Integer> cacheIds) {
+        for (Integer cacheId : cacheIds) {
+            if (null == cacheContext(cacheId))
+                throw new CacheException(String.format("Cache not found on local node [cacheId=%d]", cacheId));
+
+            if (hasMovingPartitions(cacheContext(cacheId)))
+                return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * @param cctx Cache context.
+     * @return {@code True} If cache has partitions in {@link GridDhtPartitionState#MOVING} state.
+     */
+    private static boolean hasMovingPartitions(GridCacheContext<?, ?> cctx) {
+        assert cctx != null;
+
+        return !cctx.isLocal() && cctx.topology().hasMovingPartitions();
+    }
+
+    /**
+     * @param isReplicatedOnly If we must only have replicated caches.
+     * @param topVer Topology version.
+     * @param cacheIds Participating cache IDs.
+     * @param parts Partitions.
+     * @param qryId Query ID.
+     * @return Data nodes or {@code null} if repartitioning started and we need to retry.
+     */
+    private Map<ClusterNode, IntArray> stableDataNodes(boolean isReplicatedOnly, AffinityTopologyVersion topVer,
+        List<Integer> cacheIds, int[] parts, long qryId) {
+        GridCacheContext<?, ?> cctx = cacheContext(cacheIds.get(0));
+
+        // If the first cache is not partitioned, find it (if it's present) and move it to index 0.
+        if (!cctx.isPartitioned()) {
+            for (int cacheId = 1; cacheId < cacheIds.size(); cacheId++) {
+                GridCacheContext<?, ?> currCctx = cacheContext(cacheIds.get(cacheId));
+
+                if (currCctx.isPartitioned()) {
+                    Collections.swap(cacheIds, 0, cacheId);
+
+                    cctx = currCctx;
+
+                    break;
+                }
+            }
+        }
+
+        Map<ClusterNode, IntArray> map = stableDataNodesMap(topVer, cctx, parts);
+
+        Set<ClusterNode> nodes = map.keySet();
+
+        if (F.isEmpty(map))
+            throw new CacheException("Failed to find data nodes for cache: " + cctx.name());
+
+        for (int i = 1; i < cacheIds.size(); i++) {
+            GridCacheContext<?,?> extraCctx = cacheContext(cacheIds.get(i));
+
+            String extraCacheName = extraCctx.name();
+
+            if (extraCctx.isLocal())
+                continue; // No consistency guaranties for local caches.
+
+            if (isReplicatedOnly && !extraCctx.isReplicated())
+                throw new CacheException("Queries running on replicated cache should not contain JOINs " +
+                    "with partitioned tables [replicatedCache=" + cctx.name() +
+                    ", partitionedCache=" + extraCacheName + "]");
+
+            Set<ClusterNode> extraNodes = stableDataNodesMap(topVer, extraCctx, parts).keySet();
+
+            if (F.isEmpty(extraNodes))
+                throw new CacheException("Failed to find data nodes for cache: " + extraCacheName);
+
+            boolean disjoint;
+
+            if (extraCctx.isReplicated()) {
+                if (isReplicatedOnly) {
+                    nodes.retainAll(extraNodes);
+
+                    disjoint = map.isEmpty();
+                }
+                else
+                    disjoint = !extraNodes.containsAll(nodes);
+            }
+            else
+                disjoint = !extraNodes.equals(nodes);
+
+            if (disjoint) {
+                if (isPreloadingActive(cacheIds)) {
+                    logRetry("Failed to calculate nodes for SQL query (got disjoint node map during rebalance) " +
+                        "[qryId=" + qryId + ", affTopVer=" + topVer + ", cacheIds=" + cacheIds +
+                        ", parts=" + (parts == null ? "[]" : Arrays.toString(parts)) +
+                        ", replicatedOnly=" + isReplicatedOnly + ", lastCache=" + extraCctx.name() +
+                        ", lastCacheId=" + extraCctx.cacheId() + ']');
+
+                    return null; // Retry.
+                }
+                else
+                    throw new CacheException("Caches have distinct sets of data nodes [cache1=" + cctx.name() +
+                        ", cache2=" + extraCacheName + "]");
+            }
+        }
+
+        return map;
+    }
+
+    /**
+     * @param topVer Topology version.
+     * @param cctx Cache context.
+     * @param parts Partitions.
+     */
+    private Map<ClusterNode, IntArray> stableDataNodesMap(AffinityTopologyVersion topVer,
+        final GridCacheContext<?, ?> cctx, @Nullable final int[] parts) {
+
+        Map<ClusterNode, IntArray> mapping = new HashMap<>();
+
+        // Explicit partitions mapping is not applicable to replicated cache.
+        if (cctx.isReplicated()) {
+            for (ClusterNode clusterNode : cctx.affinity().assignment(topVer).nodes())
+                mapping.put(clusterNode, null);
+
+            return mapping;
+        }
+
+        List<List<ClusterNode>> assignment = cctx.affinity().assignment(topVer).assignment();
+
+        boolean needPartsFilter = parts != null;
+
+        GridIntIterator iter = needPartsFilter ? new GridIntList(parts).iterator() :
+            U.forRange(0, cctx.affinity().partitions());
+
+        while(iter.hasNext()) {
+            int partId = iter.next();
+
+            List<ClusterNode> partNodes = assignment.get(partId);
+
+            if (!partNodes.isEmpty()) {
+                ClusterNode prim = partNodes.get(0);
+
+                if (!needPartsFilter) {
+                    mapping.put(prim, null);
+
+                    continue;
+                }
+
+                IntArray partIds = mapping.get(prim);
+
+                if (partIds == null) {
+                    partIds = new IntArray();
+
+                    mapping.put(prim, partIds);
+                }
+
+                partIds.add(partId);
+            }
+        }
+
+        return mapping;
+    }
+
+    /**
+     * Calculates partition mapping for partitioned cache on unstable topology.
+     *
+     * @param cacheIds Cache IDs.
+     * @param qryId Query ID.
+     * @return Partition mapping or {@code null} if we can't calculate it due to repartitioning and we need to retry.
+     */
+    @SuppressWarnings("unchecked")
+    private Map<ClusterNode, IntArray> partitionedUnstableDataNodes(List<Integer> cacheIds, long qryId) {
+        // If the main cache is replicated, just replace it with the first partitioned.
+        GridCacheContext<?,?> cctx = findFirstPartitioned(cacheIds);
+
+        final int partsCnt = cctx.affinity().partitions();
+
+        if (cacheIds.size() > 1) { // Check correct number of partitions for partitioned caches.
+            for (Integer cacheId : cacheIds) {
+                GridCacheContext<?, ?> extraCctx = cacheContext(cacheId);
+
+                if (extraCctx.isReplicated() || extraCctx.isLocal())
+                    continue;
+
+                int parts = extraCctx.affinity().partitions();
+
+                if (parts != partsCnt)
+                    throw new CacheException("Number of partitions must be the same for correct collocation [cache1=" +
+                        cctx.name() + ", parts1=" + partsCnt + ", cache2=" + extraCctx.name() +
+                        ", parts2=" + parts + "]");
+            }
+        }
+
+        Set<ClusterNode>[] partLocs = new Set[partsCnt];
+
+        // Fill partition locations for main cache.
+        for (int p = 0; p < partsCnt; p++) {
+            List<ClusterNode> owners = cctx.topology().owners(p);
+
+            if (F.isEmpty(owners)) {
+                // Handle special case: no mapping is configured for a partition.
+                if (F.isEmpty(cctx.affinity().assignment(NONE).get(p))) {
+                    partLocs[p] = UNMAPPED_PARTS; // Mark unmapped partition.
+
+                    continue;
+                }
+                else if (!F.isEmpty(dataNodes(cctx.groupId(), NONE))) {
+                    logRetry("Failed to calculate nodes for SQL query (partition has no owners, but corresponding " +
+                        "cache group has data nodes) [qryId=" + qryId + ", cacheIds=" + cacheIds +
+                        ", cacheName=" + cctx.name() + ", cacheId=" + cctx.cacheId() + ", part=" + p +
+                        ", cacheGroupId=" + cctx.groupId() + ']');
+
+                    return null; // Retry.
+                }
+
+                throw new CacheException("Failed to find data nodes [cache=" + cctx.name() + ", part=" + p + "]");
+            }
+
+            partLocs[p] = new HashSet<>(owners);
+        }
+
+        if (cacheIds.size() > 1) {
+            // Find owner intersections for each participating partitioned cache partition.
+            // We need this for logical collocation between different partitioned caches with the same affinity.
+            for (Integer cacheId : cacheIds) {
+                GridCacheContext<?, ?> extraCctx = cacheContext(cacheId);
+
+                // This is possible if we have replaced a replicated cache with a partitioned one earlier.
+                if (cctx == extraCctx)
+                    continue;
+
+                if (extraCctx.isReplicated() || extraCctx.isLocal())
+                    continue;
+
+                for (int p = 0, parts = extraCctx.affinity().partitions(); p < parts; p++) {
+                    List<ClusterNode> owners = extraCctx.topology().owners(p);
+
+                    if (partLocs[p] == UNMAPPED_PARTS)
+                        continue; // Skip unmapped partitions.
+
+                    if (F.isEmpty(owners)) {
+                        if (!F.isEmpty(dataNodes(extraCctx.groupId(), NONE))) {
+                            logRetry("Failed to calculate nodes for SQL query (partition has no owners, but " +
+                                "corresponding cache group has data nodes) [qryId=" + qryId +
+                                ", cacheIds=" + cacheIds + ", cacheName=" + extraCctx.name() +
+                                ", cacheId=" + extraCctx.cacheId() + ", part=" + p +
+                                ", cacheGroupId=" + extraCctx.groupId() + ']');
+
+                            return null; // Retry.
+                        }
+
+                        throw new CacheException("Failed to find data nodes [cache=" + extraCctx.name() +
+                            ", part=" + p + "]");
+                    }
+
+                    if (partLocs[p] == null)
+                        partLocs[p] = new HashSet<>(owners);
+                    else {
+                        partLocs[p].retainAll(owners); // Intersection of owners.
+
+                        if (partLocs[p].isEmpty()) {
+                            logRetry("Failed to calculate nodes for SQL query (caches have no common data nodes for " +
+                                "partition) [qryId=" + qryId + ", cacheIds=" + cacheIds +
+                                ", lastCacheName=" + extraCctx.name() + ", lastCacheId=" + extraCctx.cacheId() +
+                                ", part=" + p + ']');
+
+                            return null; // Intersection is empty -> retry.
+                        }
+                    }
+                }
+            }
+
+            // Filter nodes where not all the replicated caches loaded.
+            for (Integer cacheId : cacheIds) {
+                GridCacheContext<?, ?> extraCctx = cacheContext(cacheId);
+
+                if (!extraCctx.isReplicated())
+                    continue;
+
+                Set<ClusterNode> dataNodes = replicatedUnstableDataNodes(extraCctx, qryId);
+
+                if (F.isEmpty(dataNodes))
+                    return null; // Retry.
+
+                int part = 0;
+
+                for (Set<ClusterNode> partLoc : partLocs) {
+                    if (partLoc == UNMAPPED_PARTS)
+                        continue; // Skip unmapped partition.
+
+                    partLoc.retainAll(dataNodes);
+
+                    if (partLoc.isEmpty()) {
+                        logRetry("Failed to calculate nodes for SQL query (caches have no common data nodes for " +
+                            "partition) [qryId=" + qryId + ", cacheIds=" + cacheIds +
+                            ", lastReplicatedCacheName=" + extraCctx.name() +
+                            ", lastReplicatedCacheId=" + extraCctx.cacheId() + ", part=" + part + ']');
+
+                        return null; // Retry.
+                    }
+
+                    part++;
+                }
+            }
+        }
+
+        // Collect the final partitions mapping.
+        Map<ClusterNode, IntArray> res = new HashMap<>();
+
+        // Here partitions in all IntArray's will be sorted in ascending order, this is important.
+        for (int p = 0; p < partLocs.length; p++) {
+            Set<ClusterNode> pl = partLocs[p];
+
+            // Skip unmapped partitions.
+            if (pl == UNMAPPED_PARTS)
+                continue;
+
+            assert !F.isEmpty(pl) : pl;
+
+            ClusterNode n = pl.size() == 1 ? F.first(pl) : F.rand(pl);
+
+            IntArray parts = res.get(n);
+
+            if (parts == null)
+                res.put(n, parts = new IntArray());
+
+            parts.add(p);
+        }
+
+        return res;
+    }
+
+    /**
+     * Calculates data nodes for replicated caches on unstable topology.
+     *
+     * @param cacheIds Cache IDs.
+     * @param qryId Query ID.
+     * @return Collection of all data nodes owning all the caches or {@code null} for retry.
+     */
+    private Collection<ClusterNode> replicatedUnstableDataNodes(List<Integer> cacheIds, long qryId) {
+        int i = 0;
+
+        GridCacheContext<?, ?> cctx = cacheContext(cacheIds.get(i++));
+
+        // The main cache is allowed to be partitioned.
+        if (!cctx.isReplicated()) {
+            assert cacheIds.size() > 1: "no extra replicated caches with partitioned main cache";
+
+            // Just replace the main cache with the first one extra.
+            cctx = cacheContext(cacheIds.get(i++));
+
+            assert cctx.isReplicated(): "all the extra caches must be replicated here";
+        }
+
+        Set<ClusterNode> nodes = replicatedUnstableDataNodes(cctx, qryId);
+
+        if (F.isEmpty(nodes))
+            return null; // Retry.
+
+        for (;i < cacheIds.size(); i++) {
+            GridCacheContext<?, ?> extraCctx = cacheContext(cacheIds.get(i));
+
+            if (extraCctx.isLocal())
+                continue;
+
+            if (!extraCctx.isReplicated())
+                throw new CacheException("Queries running on replicated cache should not contain JOINs " +
+                    "with tables in partitioned caches [replicatedCache=" + cctx.name() + ", " +
+                    "partitionedCache=" + extraCctx.name() + "]");
+
+            Set<ClusterNode> extraOwners = replicatedUnstableDataNodes(extraCctx, qryId);
+
+            if (F.isEmpty(extraOwners))
+                return null; // Retry.
+
+            nodes.retainAll(extraOwners);
+
+            if (nodes.isEmpty()) {
+                logRetry("Failed to calculate nodes for SQL query (got disjoint node map for REPLICATED caches " +
+                    "during rebalance) [qryId=" + qryId + ", cacheIds=" + cacheIds +
+                    ", lastCache=" + extraCctx.name() + ", lastCacheId=" + extraCctx.cacheId() + ']');
+
+                return null; // Retry.
+            }
+        }
+
+        return nodes;
+    }
+
+    /**
+     * Collects all the nodes owning all the partitions for the given replicated cache.
+     *
+     * @param cctx Cache context.
+     * @param qryId Query ID.
+     * @return Owning nodes or {@code null} if we can't find owners for some partitions.
+     */
+    private Set<ClusterNode> replicatedUnstableDataNodes(GridCacheContext<?,?> cctx, long qryId) {
+        assert cctx.isReplicated() : cctx.name() + " must be replicated";
+
+        String cacheName = cctx.name();
+
+        Set<ClusterNode> dataNodes = new HashSet<>(dataNodes(cctx.groupId(), NONE));
+
+        if (dataNodes.isEmpty())
+            throw new CacheException("Failed to find data nodes for cache: " + cacheName);
+
+        // Find all the nodes owning all the partitions for replicated cache.
+        for (int p = 0, parts = cctx.affinity().partitions(); p < parts; p++) {
+            List<ClusterNode> owners = cctx.topology().owners(p);
+
+            if (F.isEmpty(owners)) {
+                logRetry("Failed to calculate nodes for SQL query (partition of a REPLICATED cache has no owners) [" +
+                    "qryId=" + qryId + ", cacheName=" + cctx.name() + ", cacheId=" + cctx.cacheId() +
+                    ", part=" + p + ']');
+
+                return null; // Retry.
+            }
+
+            dataNodes.retainAll(owners);
+
+            if (dataNodes.isEmpty()) {
+                logRetry("Failed to calculate nodes for SQL query (partitions of a REPLICATED has no common owners) [" +
+                    "qryId=" + qryId + ", cacheName=" + cctx.name() + ", cacheId=" + cctx.cacheId() +
+                    ", lastPart=" + p + ']');
+
+                return null; // Retry.
+            }
+        }
+
+        return dataNodes;
+    }
+
+    /**
+     * @param grpId Cache group ID.
+     * @param topVer Topology version.
+     * @return Collection of data nodes.
+     */
+    private Collection<ClusterNode> dataNodes(int grpId, AffinityTopologyVersion topVer) {
+        Collection<ClusterNode> res = ctx.discovery().cacheGroupAffinityNodes(grpId, topVer);
+
+        return res != null ? res : Collections.<ClusterNode>emptySet();
+    }
+
+    /**
+     *
+     * @param partsMap Partitions map.
+     * @param parts Partitions.
+     * @return Result.
+     */
+    private static Map<ClusterNode, IntArray> narrowForQuery(Map<ClusterNode, IntArray> partsMap, int[] parts) {
+        if (parts == null)
+            return partsMap;
+
+        Map<ClusterNode, IntArray> cp = U.newHashMap(partsMap.size());
+
+        for (Map.Entry<ClusterNode, IntArray> entry : partsMap.entrySet()) {
+            IntArray filtered = new IntArray(parts.length);
+
+            IntArray orig = entry.getValue();
+
+            for (int i = 0; i < orig.size(); i++) {
+                int p = orig.get(i);
+
+                if (Arrays.binarySearch(parts, p) >= 0)
+                    filtered.add(p);
+            }
+
+            if (filtered.size() > 0)
+                cp.put(entry.getKey(), filtered);
+        }
+
+        return cp.isEmpty() ? null : cp;
+    }
+
+    /**
+     * @param cacheIds Cache IDs.
+     * @return The first partitioned cache context.
+     */
+    private GridCacheContext<?,?> findFirstPartitioned(List<Integer> cacheIds) {
+        for (int i = 0; i < cacheIds.size(); i++) {
+            GridCacheContext<?, ?> cctx = cacheContext(cacheIds.get(i));
+
+            if (i == 0 && cctx.isLocal())
+                throw new CacheException("Cache is LOCAL: " + cctx.name());
+
+            if (!cctx.isReplicated() && !cctx.isLocal())
+                return cctx;
+        }
+
+        throw new IllegalStateException("Failed to find partitioned cache.");
+    }
+
+    /**
+     * Load failed partition reservation.
+     *
+     * @param msg Message.
+     */
+    private void logRetry(String msg) {
+        log.info(msg);
+    }
+}
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/ReducePartitionsSpecializer.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/ReducePartitionsSpecializer.java
new file mode 100644
index 0000000..592efee
--- /dev/null
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/ReducePartitionsSpecializer.java
@@ -0,0 +1,61 @@
+/*
+ * 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.twostep;
+
+import org.apache.ignite.cluster.ClusterNode;
+import org.apache.ignite.internal.processors.query.h2.twostep.msg.GridH2DmlRequest;
+import org.apache.ignite.internal.processors.query.h2.twostep.msg.GridH2QueryRequest;
+import org.apache.ignite.internal.util.typedef.C2;
+import org.apache.ignite.plugin.extensions.communication.Message;
+import org.h2.util.IntArray;
+
+import java.util.Map;
+
+/**
+ * Reducer partitions specializer.
+ */
+public class ReducePartitionsSpecializer implements C2<ClusterNode, Message, Message> {
+    /** Partitions map. */
+    private final Map<ClusterNode, IntArray> partsMap;
+
+    /**
+     * @param partsMap Partitions map.
+     */
+    public ReducePartitionsSpecializer(Map<ClusterNode, IntArray> partsMap) {
+        this.partsMap = partsMap;
+    }
+
+    /** {@inheritDoc} */
+    @Override public Message apply(ClusterNode node, Message msg) {
+        if (msg instanceof GridH2QueryRequest) {
+            GridH2QueryRequest rq = new GridH2QueryRequest((GridH2QueryRequest)msg);
+
+            rq.queryPartitions(GridReduceQueryExecutor.toArray(partsMap.get(node)));
+
+            return rq;
+        } else if (msg instanceof GridH2DmlRequest) {
+            GridH2DmlRequest rq = new GridH2DmlRequest((GridH2DmlRequest)msg);
+
+            rq.queryPartitions(GridReduceQueryExecutor.toArray(partsMap.get(node)));
+
+            return rq;
+        }
+
+        return msg;
+    }
+}
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/visor/verify/ValidateIndexesClosure.java b/modules/indexing/src/main/java/org/apache/ignite/internal/visor/verify/ValidateIndexesClosure.java
index b6909e3..6e27ca2 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/visor/verify/ValidateIndexesClosure.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/visor/verify/ValidateIndexesClosure.java
@@ -61,7 +61,7 @@
 import org.apache.ignite.internal.processors.query.GridQueryTypeDescriptor;
 import org.apache.ignite.internal.processors.query.QueryTypeDescriptorImpl;
 import org.apache.ignite.internal.processors.query.h2.IgniteH2Indexing;
-import org.apache.ignite.internal.processors.query.h2.database.H2TreeIndex;
+import org.apache.ignite.internal.processors.query.h2.database.H2TreeIndexBase;
 import org.apache.ignite.internal.processors.query.h2.opt.GridH2Row;
 import org.apache.ignite.internal.processors.query.h2.opt.GridH2RowDescriptor;
 import org.apache.ignite.internal.processors.query.h2.opt.GridH2Table;
@@ -229,7 +229,7 @@
                         ArrayList<Index> indexes = gridH2Tbl.getIndexes();
 
                         for (Index idx : indexes)
-                            if (idx instanceof H2TreeIndex)
+                            if (idx instanceof H2TreeIndexBase)
                                 idxArgs.add(new T2<>(ctx, idx));
                     }
                 }
@@ -517,7 +517,7 @@
                     ArrayList<Index> indexes = gridH2Tbl.getIndexes();
 
                     for (Index idx : indexes) {
-                        if (!(idx instanceof H2TreeIndex))
+                        if (!(idx instanceof H2TreeIndexBase))
                             continue;
 
                         try {
diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/ClientReconnectAfterClusterRestartTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/ClientReconnectAfterClusterRestartTest.java
index 9012161..02e6238 100644
--- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/ClientReconnectAfterClusterRestartTest.java
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/ClientReconnectAfterClusterRestartTest.java
@@ -35,6 +35,8 @@
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.events.Event;
 import org.apache.ignite.events.EventType;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.binary.BinaryMarshaller;
 import org.apache.ignite.lang.IgnitePredicate;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
@@ -112,6 +114,11 @@
         return ccfg;
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /** */
     public void testReconnectClient() throws Exception {
         try {
diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheDynamicLoadOnClientPersistentTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheDynamicLoadOnClientPersistentTest.java
new file mode 100644
index 0000000..ab93a4c
--- /dev/null
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheDynamicLoadOnClientPersistentTest.java
@@ -0,0 +1,44 @@
+/*
+ * 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.cache;
+
+import org.apache.ignite.configuration.DataRegionConfiguration;
+import org.apache.ignite.configuration.DataStorageConfiguration;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.configuration.WALMode;
+
+/**
+ * Test lazy cache start on client nodes with persistence cache.
+ */
+public class GridCacheDynamicLoadOnClientPersistentTest extends GridCacheDynamicLoadOnClientTest {
+
+    /** {@inheritDoc} */
+    @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception {
+        IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName);
+
+        DataStorageConfiguration dsCfg = new DataStorageConfiguration()
+            .setDefaultDataRegionConfiguration(
+                new DataRegionConfiguration().setMaxSize(200 * 1024 * 1024).setPersistenceEnabled(true))
+            .setWalMode(WALMode.LOG_ONLY);
+
+        cfg.setDataStorageConfiguration(dsCfg);
+
+        return cfg;
+    }
+}
diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheDynamicLoadOnClientTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheDynamicLoadOnClientTest.java
new file mode 100644
index 0000000..5cc559e
--- /dev/null
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheDynamicLoadOnClientTest.java
@@ -0,0 +1,304 @@
+/*
+ * 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.cache;
+
+import java.io.Serializable;
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.Collection;
+import org.apache.ignite.cache.CacheMode;
+import org.apache.ignite.cache.QueryEntity;
+import org.apache.ignite.cache.QueryIndex;
+import org.apache.ignite.cache.query.SqlFieldsQuery;
+import org.apache.ignite.cache.query.SqlQuery;
+import org.apache.ignite.cache.query.annotations.QuerySqlField;
+import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.internal.IgniteEx;
+import org.apache.ignite.internal.processors.odbc.ClientListenerProcessor;
+import org.apache.ignite.internal.processors.port.GridPortRecord;
+import org.apache.ignite.internal.util.typedef.F;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+import org.junit.Assert;
+
+/**
+ * Test lazy cache start on client nodes with inmemory cache.
+ */
+public class GridCacheDynamicLoadOnClientTest extends GridCommonAbstractTest {
+    /** Cache name. */
+    private static final String PERSON_CACHE = "Person";
+
+    /** SQL schema name. */
+    private static final String PERSON_SCHEMA = "test";
+
+    /** Number of element to add into cache. */
+    private static final int CACHE_ELEMENT_COUNT = 10;
+
+    /** Full table name. */
+    private static final String FULL_TABLE_NAME = PERSON_SCHEMA + "." + PERSON_CACHE;
+
+    /** Number of nodes. */
+    private static final int NODES = 2;
+
+    /** Client or server mode for configuration. */
+    protected boolean client;
+
+    /** Instance of client node. */
+    private static IgniteEx clientNode;
+
+    /** {@inheritDoc} */
+    @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception {
+        return super.getConfiguration(igniteInstanceName).setClientMode(client);
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void beforeTestsStarted() throws Exception {
+        super.beforeTestsStarted();
+
+        client = false;
+
+        startGridsMultiThreaded(NODES - 1);
+
+        client = true;
+
+        clientNode = startGrid(NODES - 1);
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void beforeTest() throws Exception {
+        super.beforeTest();
+
+        clientNode.destroyCache(PERSON_CACHE);
+
+        createAndFillServerCache();
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void afterTestsStopped() throws Exception {
+        super.afterTestsStopped();
+
+        stopAllGrids();
+    }
+
+    /**
+     * Test from client node batch merge through JDBC.
+     *
+     * @throws Exception If failure.
+     */
+    public void testBatchMerge() throws Exception {
+        final int BATCH_SIZE = 7;
+
+        try (Connection con = connect(clientNode);
+             Statement stmt = con.createStatement()) {
+            for (int idx = 0, i = 0; i < BATCH_SIZE; ++i, idx += i) {
+                stmt.addBatch("merge into " + FULL_TABLE_NAME + " (_key, name, orgId) values (" +
+                    (100 + idx) + "," +
+                    "'" + "batch-" + idx + "'" + "," +
+                    idx +
+                    ")");
+            }
+
+            int[] updCnts = stmt.executeBatch();
+
+            assertEquals("Invalid update counts size", BATCH_SIZE, updCnts.length);
+        }
+    }
+
+    /**
+     * Test from client node to delete cache elements through JDBC.
+     *
+     * @throws Exception If failure.
+     */
+    public void testClientJdbcDelete() throws Exception {
+        try (Connection con = connect(clientNode);
+             Statement stmt = con.createStatement()) {
+            int cnt = stmt.executeUpdate(("DELETE " + FULL_TABLE_NAME + " WHERE _key=1"));
+
+            Assert.assertEquals(1, cnt);
+        }
+
+        SqlFieldsQuery qry = new SqlFieldsQuery("SELECT * FROM " + FULL_TABLE_NAME);
+
+        Assert.assertEquals(CACHE_ELEMENT_COUNT - 1, clientNode.cache(PERSON_CACHE).query(qry).getAll().size());
+    }
+
+    /**
+     * Test from client node to insert into cache through JDBC.
+     *
+     * @throws Exception If failure.
+     */
+    public void testClientJdbcInsert() throws Exception {
+        try (Connection con = connect(clientNode);
+             Statement stmt = con.createStatement()) {
+            int cnt = stmt.executeUpdate(
+                "INSERT INTO " + FULL_TABLE_NAME + "(_key, name, orgId) VALUES(1000,'new_name', 10000)");
+
+            Assert.assertEquals(1, cnt);
+        }
+
+        SqlFieldsQuery qry = new SqlFieldsQuery("SELECT * FROM " + FULL_TABLE_NAME);
+
+        Assert.assertEquals(CACHE_ELEMENT_COUNT + 1, clientNode.cache(PERSON_CACHE).query(qry).getAll().size());
+    }
+
+    /**
+     * Test from client node to update cache elements through JDBC.
+     *
+     * @throws Exception If failure.
+     */
+    public void testClientJdbcUpdate() throws Exception {
+        try (Connection con = connect(clientNode);
+             Statement stmt = con.createStatement()) {
+            int cnt = stmt.executeUpdate(("UPDATE " + FULL_TABLE_NAME + " SET name = 'new_name'"));
+
+            Assert.assertEquals(CACHE_ELEMENT_COUNT, cnt);
+        }
+
+        SqlFieldsQuery qry = new SqlFieldsQuery("SELECT * FROM " + FULL_TABLE_NAME + " WHERE name = 'new_name'");
+
+        Assert.assertEquals(CACHE_ELEMENT_COUNT, clientNode.cache(PERSON_CACHE).query(qry).getAll().size());
+    }
+
+    /**
+     * Test from client node to get cache elements through JDBC.
+     *
+     * @throws Exception If failure.
+     */
+    public void testClientJdbc() throws Exception {
+        try (Connection con = connect(clientNode);
+             Statement st = con.createStatement()) {
+            ResultSet rs = st.executeQuery("SELECT count(*) FROM " + FULL_TABLE_NAME);
+
+            rs.next();
+
+            Assert.assertEquals(CACHE_ELEMENT_COUNT, rs.getInt(1));
+        }
+    }
+
+    /**
+     * Test from client node to put cache elements through cache API.
+     */
+    public void testClientPut() {
+        clientNode.cache(PERSON_CACHE).put(-100, new Person(-100, "name-"));
+
+        Assert.assertEquals(CACHE_ELEMENT_COUNT + 1, clientNode.cache(PERSON_CACHE).size());
+    }
+
+    /**
+     * Test from client node to get cache elements through cache API.
+     */
+    public void testClientSqlFieldsQuery() {
+        SqlFieldsQuery qry = new SqlFieldsQuery("SELECT * FROM " + FULL_TABLE_NAME);
+
+        Assert.assertEquals(CACHE_ELEMENT_COUNT, clientNode.cache(PERSON_CACHE).query(qry).getAll().size());
+    }
+
+    /**
+     * Test from client node to get cache elements through cache API.
+     */
+    public void testClientSqlQuery() {
+        SqlQuery<Integer, Person> qry = new SqlQuery<>(PERSON_CACHE, "FROM " + PERSON_CACHE);
+
+        Assert.assertEquals(CACHE_ELEMENT_COUNT,
+            clientNode.cache(PERSON_CACHE).query(qry).getAll().size());
+    }
+
+    /**
+     * Create cache at server node and put some values into the cache.
+     */
+    private void createAndFillServerCache() {
+        IgniteEx srvNode = grid(0);
+
+        srvNode.createCache(cacheConfiguration());
+
+        for (int i = 0; i < CACHE_ELEMENT_COUNT; i++)
+            srvNode.cache(PERSON_CACHE).put(i, new Person(i, "name-" + i));
+    }
+
+    /**
+     * @return Cache configuration.
+     */
+    private CacheConfiguration<?, ?> cacheConfiguration() {
+        CacheConfiguration ccfg = new CacheConfiguration(PERSON_CACHE);
+
+        ccfg.setSqlSchema(PERSON_SCHEMA);
+        ccfg.setCacheMode(CacheMode.PARTITIONED);
+
+        QueryEntity person = new QueryEntity();
+        person.setKeyType(Integer.class.getName());
+        person.setValueType(Person.class.getName());
+        person.addQueryField("orgId", Integer.class.getName(), null);
+        person.addQueryField("id", Integer.class.getName(), null);
+        person.addQueryField("name", String.class.getName(), null);
+        person.setIndexes(F.asList(new QueryIndex("orgId"), new QueryIndex("id"), new QueryIndex("name")));
+
+        ccfg.setQueryEntities(F.asList(person));
+
+        return ccfg;
+    }
+
+    /**
+     * Create SQL connection to node specified as argument
+     *
+     * @param node Node to connect.
+     * @return Connection.
+     * @throws SQLException In case of failure.
+     */
+    private static Connection connect(IgniteEx node) throws SQLException {
+        Collection<GridPortRecord> recs = node.context().ports().records();
+
+        GridPortRecord cliLsnrRec = null;
+
+        for (GridPortRecord rec : recs) {
+            if (rec.clazz() == ClientListenerProcessor.class) {
+                cliLsnrRec = rec;
+
+                break;
+            }
+        }
+
+        String connStr = "jdbc:ignite:thin://127.0.0.1:" + cliLsnrRec.port();
+
+        return DriverManager.getConnection(connStr);
+    }
+
+    /**
+     * Test object to keep in cache.
+     */
+    private static class Person implements Serializable {
+        /** */
+        @QuerySqlField
+        int orgId;
+
+        /** */
+        @QuerySqlField
+        String name;
+
+        /**
+         * @param orgId Organization ID.
+         * @param name Name.
+         */
+        public Person(int orgId, String name) {
+            this.orgId = orgId;
+            this.name = name;
+        }
+    }
+}
diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCrossCachesJoinsQueryTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCrossCachesJoinsQueryTest.java
index 17a8ed3..805924e 100644
--- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCrossCachesJoinsQueryTest.java
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCrossCachesJoinsQueryTest.java
@@ -43,6 +43,8 @@
 import org.apache.ignite.cache.query.annotations.QuerySqlField;
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.processors.query.h2.sql.AbstractH2CompareQueryTest;
 import org.apache.ignite.internal.util.tostring.GridToStringInclude;
 import org.apache.ignite.internal.util.typedef.F;
@@ -132,6 +134,11 @@
     }
 
     /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
+    /** {@inheritDoc} */
     @Override protected void initCacheAndDbData() throws SQLException {
         Statement st = conn.createStatement();
 
diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteDynamicSqlRestoreTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteDynamicSqlRestoreTest.java
index f7dc7b4..d009f33 100644
--- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteDynamicSqlRestoreTest.java
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteDynamicSqlRestoreTest.java
@@ -18,12 +18,20 @@
 package org.apache.ignite.internal.processors.cache;
 
 import java.io.Serializable;
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.Statement;
+import java.sql.Timestamp;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.LinkedHashMap;
 import org.apache.ignite.Ignite;
 import org.apache.ignite.IgniteCache;
+import org.apache.ignite.IgniteCheckedException;
 import org.apache.ignite.IgniteDataStreamer;
+import org.apache.ignite.Ignition;
 import org.apache.ignite.binary.BinaryObject;
 import org.apache.ignite.cache.QueryEntity;
 import org.apache.ignite.cache.query.SqlFieldsQuery;
@@ -33,8 +41,10 @@
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.configuration.WALMode;
 import org.apache.ignite.internal.IgniteEx;
+import org.apache.ignite.internal.util.typedef.PA;
 import org.apache.ignite.internal.util.typedef.X;
 import org.apache.ignite.spi.IgniteSpiException;
+import org.apache.ignite.testframework.GridTestUtils;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
 import org.jetbrains.annotations.NotNull;
 
@@ -44,6 +54,7 @@
 /**
  *
  */
+@SuppressWarnings("Duplicates")
 public class IgniteDynamicSqlRestoreTest extends GridCommonAbstractTest implements Serializable {
 
     public static final String TEST_CACHE_NAME = "test";
@@ -117,7 +128,7 @@
             //and: change data
             try (IgniteDataStreamer<Object, Object> s = ig.dataStreamer(TEST_CACHE_NAME)) {
                 s.allowOverwrite(true);
-                for (int i = 0; i < 5_000; i++)
+                for (int i = 0; i < 50; i++)
                     s.addData(i, null);
             }
 
@@ -134,7 +145,7 @@
             //then: everything is ok
             try (IgniteDataStreamer<Object, Object> s = ig1.dataStreamer(TEST_CACHE_NAME)) {
                 s.allowOverwrite(true);
-                for (int i = 0; i < 50_000; i++) {
+                for (int i = 0; i < 50; i++) {
                     BinaryObject bo = ig1.binary().builder(TEST_INDEX_OBJECT)
                         .setField("a", i, Object.class)
                         .setField("b", String.valueOf(i), Object.class)
@@ -147,12 +158,132 @@
 
             IgniteCache<Object, Object> cache = ig1.cache(TEST_CACHE_NAME);
 
-            assertThat(doExplainPlan(cache, "explain select * from TestIndexObject where a > 5"), containsString("myindexa"));
+            assertIndexUsed(cache, "explain select * from TestIndexObject where a > 5", "myindexa");
             assertFalse(cache.query(new SqlFieldsQuery("SELECT a,b,c FROM TestIndexObject limit 1")).getAll().isEmpty());
         }
     }
 
     /**
+     * @throws Exception If failed.
+     */
+    @SuppressWarnings("AssertWithSideEffects")
+    public void testIndexCreationWhenNodeStopped() throws Exception {
+        // Start topology.
+        startGrid(0);
+        Ignite srv2 = startGrid(1);
+        Ignite cli;
+
+        Ignition.setClientMode(true);
+
+        try {
+            cli = startGrid(2);
+        }
+        finally {
+            Ignition.setClientMode(false);
+        }
+
+        cli.cluster().active(true);
+
+        // Create table, add some data.
+        int entryCnt = 50;
+
+        try (Connection conn = DriverManager.getConnection("jdbc:ignite:thin://127.0.0.1:10802")) {
+            executeJdbc(conn,
+                " CREATE TABLE PERSON (\n" +
+                " FIRST_NAME VARCHAR,\n" +
+                " LAST_NAME VARCHAR,\n" +
+                " ADDRESS VARCHAR,\n" +
+                " LANG VARCHAR,\n" +
+                " BIRTH_DATE TIMESTAMP,\n" +
+                " CONSTRAINT PK_PESON PRIMARY KEY (FIRST_NAME,LAST_NAME,ADDRESS,LANG)\n" +
+                " ) WITH \"key_type=PersonKeyType, CACHE_NAME=PersonCache, value_type=PersonValueType, AFFINITY_KEY=FIRST_NAME,template=PARTITIONED,backups=1\"");
+
+            try (PreparedStatement stmt = conn.prepareStatement(
+                "insert into Person(LANG, FIRST_NAME, ADDRESS, LAST_NAME, BIRTH_DATE) values(?,?,?,?,?)")) {
+                for (int i = 0; i < entryCnt; i++) {
+                    String s = String.valueOf(i);
+
+                    stmt.setString(1, s);
+                    stmt.setString(2, s);
+                    stmt.setString(3, s);
+                    stmt.setString(4, s);
+                    stmt.setTimestamp(5, new Timestamp(System.currentTimeMillis()));
+
+                    stmt.executeUpdate();
+                }
+            }
+        }
+
+        // Stop second node.
+        srv2.close();
+
+        // Create an index on remaining node.
+        try (Connection conn = DriverManager.getConnection("jdbc:ignite:thin://127.0.0.1:10802")) {
+            executeJdbc(conn, "create index PERSON_FIRST_NAME_IDX on PERSON(FIRST_NAME)");
+        }
+
+        // Restart second node.
+        startGrid(1);
+
+        // Await for index rebuild on started node.
+        assert GridTestUtils.waitForCondition(new PA() {
+            @Override public boolean apply() {
+                try (Connection conn = DriverManager.getConnection("jdbc:ignite:thin://127.0.0.1:10801")) {
+                    try (PreparedStatement stmt = conn.prepareStatement(
+                        "EXPLAIN SELECT * FROM Person USE INDEX(PERSON_FIRST_NAME_IDX) WHERE FIRST_NAME=?")) {
+                        stmt.setString(1, String.valueOf(1));
+
+                        StringBuilder fullPlan = new StringBuilder();
+
+                        try (ResultSet rs = stmt.executeQuery()) {
+                            while (rs.next())
+                                fullPlan.append(rs.getString(1)).append("; ");
+                        }
+
+                        System.out.println("PLAN: " + fullPlan);
+
+                        return fullPlan.toString().contains("PUBLIC.PERSON_FIRST_NAME_IDX");
+                    }
+                }
+                catch (Exception e) {
+                    throw new RuntimeException("Query failed.", e);
+                }
+            }
+        }, 5_000);
+
+        // Make sure that data could be queried.
+        try (Connection conn = DriverManager.getConnection("jdbc:ignite:thin://127.0.0.1:10802")) {
+            try (PreparedStatement stmt = conn.prepareStatement(
+                "SELECT COUNT(*) FROM Person USE INDEX(PERSON_FIRST_NAME_IDX) WHERE FIRST_NAME=?")) {
+                for (int i = 0; i < entryCnt; i ++) {
+                    stmt.setString(1, String.valueOf(i));
+
+                    try (ResultSet rs = stmt.executeQuery()) {
+                        rs.next();
+
+                        long cnt = rs.getLong(1);
+
+                        assertEquals(1L, cnt);
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Execute a statement through JDBC connection.
+     *
+     * @param conn Connection.
+     * @param sql Statement.
+     * @throws Exception If failed.
+     */
+    private static void executeJdbc(Connection conn, String sql) throws Exception {
+        try (Statement stmt = conn.createStatement()) {
+            stmt.execute(sql);
+        }
+    }
+
+    /**
      * @throws Exception if failed.
      */
     public void testTakeConfigFromJoiningNodeOnInactiveGrid() throws Exception {
@@ -186,7 +317,7 @@
             //then: config for cache was applying successful
             IgniteCache<Object, Object> cache = ig.cache(TEST_CACHE_NAME);
 
-            assertThat(doExplainPlan(cache, "explain select * from TestIndexObject where a > 5"), containsString("myindexa"));
+            assertIndexUsed(cache, "explain select * from TestIndexObject where a > 5", "myindexa");
             assertFalse(cache.query(new SqlFieldsQuery("SELECT a,b,c FROM TestIndexObject limit 1")).getAll().isEmpty());
         }
     }
@@ -233,7 +364,7 @@
 
             IgniteCache<Object, Object> cache = ig.cache(TEST_CACHE_NAME);
 
-            assertThat(doExplainPlan(cache, "explain select * from TestIndexObject where a > 5"), containsString("myindexa"));
+            assertIndexUsed(cache, "explain select * from TestIndexObject where a > 5", "myindexa");
             assertFalse(cache.query(new SqlFieldsQuery("SELECT a,b,c FROM TestIndexObject limit 1")).getAll().isEmpty());
         }
     }
@@ -241,6 +372,7 @@
     /**
      * @throws Exception if failed.
      */
+    @SuppressWarnings("ArraysAsListWithZeroOrOneArgument")
     public void testMergeChangedConfigOnInactiveGrid() throws Exception {
         {
             //given: two started nodes with test table
@@ -288,7 +420,7 @@
             //then: config should be merged
             try (IgniteDataStreamer<Object, Object> s = ig1.dataStreamer(TEST_CACHE_NAME)) {
                 s.allowOverwrite(true);
-                for (int i = 0; i < 5_000; i++) {
+                for (int i = 0; i < 50; i++) {
                     BinaryObject bo = ig1.binary().builder("TestIndexObject")
                         .setField("a", i, Object.class)
                         .setField("b", String.valueOf(i), Object.class)
@@ -300,13 +432,32 @@
             IgniteCache<Object, Object> cache = ig1.cache(TEST_CACHE_NAME);
 
             //then: index "myindexa" and column "b" restored from node "1"
-            assertThat(doExplainPlan(cache, "explain select * from TestIndexObject where a > 5"), containsString("myindexa"));
-            assertThat(doExplainPlan(cache, "explain select * from TestIndexObject where b > 5"), containsString("myindexb"));
+            assertIndexUsed(cache, "explain select * from TestIndexObject where a > 5", "myindexa");
+            assertIndexUsed(cache, "explain select * from TestIndexObject where b > 5", "myindexb");
             assertFalse(cache.query(new SqlFieldsQuery("SELECT a,b FROM TestIndexObject limit 1")).getAll().isEmpty());
         }
     }
 
     /**
+     * Make sure that index is used for the given statement.
+     *
+     * @param cache Cache.
+     * @param sql Statement.
+     * @param idx Index.
+     * @throws IgniteCheckedException If failed.
+     */
+    private void assertIndexUsed(IgniteCache<Object, Object> cache, String sql, String idx)
+        throws IgniteCheckedException {
+        assert GridTestUtils.waitForCondition(new PA() {
+            @Override public boolean apply() {
+                String plan = doExplainPlan(cache, sql);
+
+                return plan.contains(idx);
+            }
+        }, 10_000);
+    }
+
+    /**
      * @throws Exception if failed.
      */
     public void testTakeChangedConfigOnActiveGrid() throws Exception {
@@ -341,7 +492,7 @@
             //then: config should be merged
             try (IgniteDataStreamer<Object, Object> s = ig.dataStreamer(TEST_CACHE_NAME)) {
                 s.allowOverwrite(true);
-                for (int i = 0; i < 5_000; i++) {
+                for (int i = 0; i < 50; i++) {
                     BinaryObject bo = ig.binary().builder("TestIndexObject")
                         .setField("a", i, Object.class)
                         .setField("b", String.valueOf(i), Object.class)
@@ -355,7 +506,7 @@
 
             cache.indexReadyFuture().get();
 
-            assertThat(doExplainPlan(cache, "explain select * from TestIndexObject where a > 5"), containsString("myindexa"));
+            assertIndexUsed(cache, "explain select * from TestIndexObject where a > 5", "myindexa");
             assertFalse(cache.query(new SqlFieldsQuery("SELECT a,b,c FROM TestIndexObject limit 1")).getAll().isEmpty());
         }
     }
@@ -363,6 +514,7 @@
     /**
      * @throws Exception if failed.
      */
+    @SuppressWarnings("ConstantConditions")
     public void testFailJoiningNodeBecauseDifferentSql() throws Exception {
         {
             //given: two started nodes with test table
@@ -407,6 +559,7 @@
     /**
      * @throws Exception if failed.
      */
+    @SuppressWarnings("ConstantConditions")
     public void testFailJoiningNodeBecauseFieldInlineSizeIsDifferent() throws Exception {
         {
             //given: two started nodes with test table
@@ -417,13 +570,13 @@
 
             IgniteCache cache = ig.getOrCreateCache(getTestTableConfiguration());
 
-            cache.query(new SqlFieldsQuery("create index myindexa on TestIndexObject(a) INLINE_SIZE 1000")).getAll();
+            cache.query(new SqlFieldsQuery("create index myindexa on TestIndexObject(a) INLINE_SIZE 100")).getAll();
 
             //stop one node and create index on other node
             stopGrid(1);
 
             cache.query(new SqlFieldsQuery("drop index myindexa")).getAll();
-            cache.query(new SqlFieldsQuery("create index myindexa on TestIndexObject(a) INLINE_SIZE 2000")).getAll();
+            cache.query(new SqlFieldsQuery("create index myindexa on TestIndexObject(a) INLINE_SIZE 200")).getAll();
 
             //and: stopped all grid
             stopAllGrids();
@@ -447,6 +600,7 @@
     /**
      * @throws Exception if failed.
      */
+    @SuppressWarnings("ConstantConditions")
     public void testFailJoiningNodeBecauseNeedConfigUpdateOnActiveGrid() throws Exception {
         {
             startGrid(0);
@@ -497,7 +651,7 @@
      */
     private void fillTestData(Ignite ig) {
         try (IgniteDataStreamer<Object, Object> s = ig.dataStreamer(TEST_CACHE_NAME)) {
-            for (int i = 0; i < 50_000; i++) {
+            for (int i = 0; i < 500; i++) {
                 BinaryObject bo = ig.binary().builder("TestIndexObject")
                     .setField("a", i, Object.class)
                     .setField("b", String.valueOf(i), Object.class)
diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/QueryEntityCaseMismatchTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/QueryEntityCaseMismatchTest.java
index 93ffa18..77f41f9 100644
--- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/QueryEntityCaseMismatchTest.java
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/QueryEntityCaseMismatchTest.java
@@ -21,6 +21,8 @@
 import org.apache.ignite.cache.QueryEntity;
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.binary.BinaryMarshaller;
 import org.apache.ignite.internal.util.typedef.F;
 import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
@@ -89,6 +91,11 @@
         return cfg;
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * The cache must not initialize if QueryEntity.keyFields isn't subset of QueryEntity.fields
      *
diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/DynamicColumnsAbstractConcurrentSelfTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/DynamicColumnsAbstractConcurrentSelfTest.java
index e6fd321..fb1da72 100644
--- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/DynamicColumnsAbstractConcurrentSelfTest.java
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/DynamicColumnsAbstractConcurrentSelfTest.java
@@ -43,6 +43,8 @@
 import org.apache.ignite.cluster.ClusterNode;
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.IgniteClientReconnectAbstractTest;
 import org.apache.ignite.internal.IgniteEx;
 import org.apache.ignite.internal.IgniteInternalFuture;
@@ -98,6 +100,9 @@
     /** Atomicity mode. */
     private final CacheAtomicityMode atomicityMode;
 
+    /** No-Op failure handler. */
+    private boolean noOpFailureHnd;
+
     /**
      * Constructor.
      *
@@ -119,6 +124,8 @@
         super.beforeTest();
 
         GridQueryProcessor.idxCls = BlockingIndexing.class;
+
+        noOpFailureHnd = false;
     }
 
     /** {@inheritDoc} */
@@ -137,6 +144,14 @@
     }
 
     /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        if (noOpFailureHnd)
+            return new NoOpFailureHandler();
+
+        return super.getFailureHandler(igniteInstanceName);
+    }
+
+    /** {@inheritDoc} */
     @Override protected long getTestTimeout() {
         return 5 * 60 * 1000L;
     }
@@ -175,6 +190,8 @@
      * @throws Exception If failed.
      */
     public void checkCoordinatorChange(boolean addOrRemove) throws Exception {
+        noOpFailureHnd = true;
+
         CountDownLatch finishLatch = new CountDownLatch(2);
 
         // Start servers.
@@ -757,6 +774,8 @@
      * @throws Exception If failed.
      */
     private void checkClientReconnect(final boolean restartCache, boolean dynamicCache) throws Exception {
+        noOpFailureHnd = true;
+
         // Start complex topology.
         final IgniteEx srv = ignitionStart(serverConfiguration(1));
         ignitionStart(serverConfiguration(2));
@@ -843,6 +862,8 @@
      */
     @SuppressWarnings("StringConcatenationInLoop")
     public void testConcurrentOperationsAndNodeStartStopMultithreaded() throws Exception {
+        noOpFailureHnd = true;
+
         // Start several stable nodes.
         ignitionStart(serverConfiguration(1));
         ignitionStart(serverConfiguration(2));
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 07c0ede..5634748 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
@@ -725,6 +725,28 @@
     }
 
     /**
+     * Test that {@code DROP TABLE} executed at client node actually removes specified cache and type descriptor on all nodes.
+     * @throws Exception if failed.
+     */
+    public void testDropTableFromClient() throws Exception {
+        execute(grid(0),"CREATE TABLE IF NOT EXISTS \"Person\" (\"id\" int, \"city\" varchar," +
+            " \"name\" varchar, \"surname\" varchar, \"age\" int, PRIMARY KEY (\"id\", \"city\")) WITH " +
+            "\"template=cache\"");
+
+        execute(client(), "DROP TABLE \"Person\"");
+
+        for (int i = 0; i < 4; i++) {
+            IgniteEx node = grid(i);
+
+            assertNull(node.cache("Person"));
+
+            QueryTypeDescriptorImpl desc = type(node, "Person", "Person");
+
+            assertNull(desc);
+        }
+    }
+
+    /**
      * Test that {@code DROP TABLE} actually removes specified cache and type descriptor on all nodes.
      * @throws Exception if failed.
      */
diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/SchemaExchangeSelfTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/SchemaExchangeSelfTest.java
index c7709f2..bd2b578 100644
--- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/SchemaExchangeSelfTest.java
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/SchemaExchangeSelfTest.java
@@ -17,6 +17,9 @@
 
 package org.apache.ignite.internal.processors.cache.index;
 
+import java.util.Collections;
+import java.util.Map;
+import junit.framework.AssertionFailedError;
 import org.apache.ignite.IgniteClientDisconnectedException;
 import org.apache.ignite.IgniteException;
 import org.apache.ignite.Ignition;
@@ -26,18 +29,18 @@
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.internal.IgniteEx;
+import org.apache.ignite.internal.processors.cache.GridCacheAdapter;
+import org.apache.ignite.internal.processors.cache.GridCacheContext;
 import org.apache.ignite.internal.processors.query.QueryTypeDescriptorImpl;
 import org.apache.ignite.internal.processors.query.QueryUtils;
 import org.apache.ignite.internal.util.lang.GridAbsPredicate;
 import org.apache.ignite.internal.util.typedef.F;
+import org.apache.ignite.internal.util.typedef.internal.CU;
 import org.apache.ignite.lang.IgniteFuture;
 import org.apache.ignite.lang.IgnitePredicate;
 import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
 import org.apache.ignite.testframework.GridTestUtils;
 
-import java.util.Collections;
-import java.util.Map;
-
 import static org.apache.ignite.internal.IgniteClientReconnectAbstractTest.TestTcpDiscoverySpi;
 import static org.apache.ignite.internal.IgniteClientReconnectAbstractTest.reconnectClientNode;
 
@@ -171,11 +174,13 @@
 
         assertTypes(node1, ValueClass.class);
         assertTypes(node2, ValueClass.class);
+        assertCacheStarted(CACHE_NAME, node1, node2);
 
-        assertTypes(node3);
+        assertTypes(node3, ValueClass.class);
+        assertCacheNotStarted(CACHE_NAME, node3);
 
         node3.cache(CACHE_NAME);
-        assertTypes(node3, ValueClass.class);
+        assertCacheStarted(CACHE_NAME, node3);
 
         // Check restarts from the first node.
         destroySqlCache(node1);
@@ -193,11 +198,14 @@
 
         assertTypes(node1, ValueClass.class, ValueClass2.class);
         assertTypes(node2, ValueClass.class, ValueClass2.class);
+        assertTypes(node3, ValueClass.class, ValueClass2.class);
 
-        assertTypes(node3);
+        assertCacheStarted(CACHE_NAME, node1, node2);
+
+        assertCacheNotStarted(CACHE_NAME, node3);
 
         node3.cache(CACHE_NAME);
-        assertTypes(node3, ValueClass.class, ValueClass2.class);
+        assertCacheStarted(CACHE_NAME, node3);
 
         // Check restarts from the second node.
         node2.destroyCache(CACHE_NAME);
@@ -215,16 +223,20 @@
 
         assertTypes(node1, ValueClass.class, ValueClass2.class);
         assertTypes(node2, ValueClass.class, ValueClass2.class);
+        assertTypes(node3, ValueClass.class, ValueClass2.class);
+        assertTypes(node4, ValueClass.class, ValueClass2.class);
 
-        assertTypes(node3);
+        assertCacheStarted(CACHE_NAME, node1, node2);
+
+        assertCacheNotStarted(CACHE_NAME, node3);
 
         node3.cache(CACHE_NAME);
-        assertTypes(node3, ValueClass.class, ValueClass2.class);
+        assertCacheStarted(CACHE_NAME, node3);
 
-        assertTypes(node4);
+        assertCacheNotStarted(CACHE_NAME, node4);
 
         node4.cache(CACHE_NAME);
-        assertTypes(node4, ValueClass.class, ValueClass2.class);
+        assertCacheStarted(CACHE_NAME, node4);
 
         // Make sure that joining node observes correct state.
         assertTypes(start(5), ValueClass.class, ValueClass2.class);
@@ -234,10 +246,13 @@
 
         IgniteEx node8 = startClientNoCache(8);
 
-        assertTypes(node8);
+        assertTypes(node8, ValueClass.class, ValueClass2.class);
+
+        assertCacheNotStarted(CACHE_NAME, node8);
 
         node8.cache(CACHE_NAME);
-        assertTypes(node8, ValueClass.class, ValueClass2.class);
+
+        assertCacheStarted(CACHE_NAME, node8);
     }
 
     /**
@@ -292,10 +307,15 @@
         assertTypes(node2, ValueClass.class);
         assertTypes(node3, ValueClass.class);
 
-        assertTypes(node4);
+        assertTypes(node4, ValueClass.class);
+
+        assertCacheStarted(CACHE_NAME, node1, node2, node3);
+
+        assertCacheNotStarted(CACHE_NAME, node4);
 
         node4.cache(CACHE_NAME);
-        assertTypes(node4, ValueClass.class);
+
+        assertCacheStarted(CACHE_NAME, node4);
     }
 
     /**
@@ -345,40 +365,31 @@
         IgniteEx node7 = startClient(7,  KeyClass.class, ValueClass.class, KeyClass2.class, ValueClass2.class);
         IgniteEx node8 = startClientNoCache(8);
 
-        assertTypes(node1, ValueClass.class);
-        assertTypes(node2, ValueClass.class);
-        assertTypes(node3, ValueClass.class);
-        assertTypes(node4, ValueClass.class);
-        assertTypes(node5, ValueClass.class);
-        assertTypes(node6, ValueClass.class);
-        assertTypes(node7, ValueClass.class);
-
-        assertTypes(node8);
-        node8.cache(CACHE_NAME);
+        assertCacheStarted(CACHE_NAME, node1, node2, node3, node4, node5, node6, node7);
+        assertCacheNotStarted(CACHE_NAME, node8);
         assertTypes(node8, ValueClass.class);
 
+        node8.cache(CACHE_NAME);
+
+        assertCacheStarted(CACHE_NAME, node8);
+
         destroySqlCache(node2);
 
         node2.getOrCreateCache(
             cacheConfiguration(KeyClass.class, ValueClass.class, KeyClass2.class, ValueClass2.class));
 
-        assertTypes(node1, ValueClass.class, ValueClass2.class);
-        assertTypes(node2, ValueClass.class, ValueClass2.class);
-        assertTypes(node3, ValueClass.class, ValueClass2.class);
-        assertTypes(node4, ValueClass.class, ValueClass2.class);
-        assertTypes(node5, ValueClass.class, ValueClass2.class);
+        assertCacheStarted(CACHE_NAME, node1, node2, node3, node4, node5);
+        assertCacheNotStarted(CACHE_NAME, node6, node7, node8);
 
-        assertTypes(node6);
-        assertTypes(node7);
-        assertTypes(node8);
+        assertTypes(node6, ValueClass.class, ValueClass2.class);
+        assertTypes(node7, ValueClass.class, ValueClass2.class);
+        assertTypes(node8, ValueClass.class, ValueClass2.class);
 
         node6.cache(CACHE_NAME);
         node7.cache(CACHE_NAME);
         node8.cache(CACHE_NAME);
 
-        assertTypes(node6, ValueClass.class, ValueClass2.class);
-        assertTypes(node7, ValueClass.class, ValueClass2.class);
-        assertTypes(node8, ValueClass.class, ValueClass2.class);
+        assertCacheStarted(CACHE_NAME, node6, node7, node8);
     }
 
     /**
@@ -399,11 +410,14 @@
         IgniteEx node3 = startNoCache(3);
         assertTypes(node1, ValueClass.class);
         assertTypes(node2, ValueClass.class);
+        assertTypes(node3, ValueClass.class);
 
-        assertTypes(node3);
+        assertCacheStarted(CACHE_NAME, node1, node2);
+
+        assertCacheNotStarted(CACHE_NAME, node3);
 
         node3.cache(CACHE_NAME);
-        assertTypes(node3, ValueClass.class);
+        assertCacheStarted(CACHE_NAME, node1, node3);
     }
 
     /**
@@ -416,7 +430,12 @@
         assertTypes(node1, ValueClass.class);
 
         IgniteEx node2 = startClientNoCache(2);
-        assertTypes(node2);
+
+        GridCacheContext<Object, Object> context0 = node2.context().cache().context().cacheContext(CU.cacheId(CACHE_NAME));
+        node2.cache(CACHE_NAME);
+        GridCacheContext<Object, Object> context = node2.context().cache().context().cacheContext(CU.cacheId(CACHE_NAME));
+        GridCacheAdapter<Object, Object> entries = node2.context().cache().internalCache(CACHE_NAME);
+        assertTrue(entries.active());
 
         node2.cache(CACHE_NAME);
         assertTypes(node2, ValueClass.class);
@@ -431,7 +450,7 @@
 
         IgniteFuture reconnFut = null;
 
-        try {   
+        try {
             node2.cache(CACHE_NAME);
 
             fail();
@@ -442,13 +461,17 @@
 
         node1 = start(1, KeyClass.class, ValueClass.class, KeyClass2.class, ValueClass2.class);
         assertTypes(node1, ValueClass.class, ValueClass2.class);
+        assertTypes(node2, ValueClass.class);
+
+        assertCacheStarted(CACHE_NAME, node1);
 
         reconnFut.get();
 
-        assertTypes(node2);
+        assertTypes(node2, ValueClass.class, ValueClass2.class);
+        assertCacheNotStarted(CACHE_NAME, node2);
 
         node2.cache(CACHE_NAME);
-        assertTypes(node2, ValueClass.class, ValueClass2.class);
+        assertCacheStarted(CACHE_NAME, node2);
     }
 
     /**
@@ -462,10 +485,11 @@
         assertTypes(node1, ValueClass.class);
 
         final IgniteEx node2 = startClientNoCache(2);
-        assertTypes(node2);
+        assertTypes(node2, ValueClass.class);
+        assertCacheNotStarted(CACHE_NAME, node2);
 
         node2.cache(CACHE_NAME);
-        assertTypes(node2, ValueClass.class);
+        assertCacheStarted(CACHE_NAME, node2);
 
         reconnectClientNode(log, node2, node1, new Runnable() {
             @Override public void run() {
@@ -489,6 +513,45 @@
     }
 
     /**
+     * Check is cache started on the given node or not.
+     *
+     * @param cacheName Cache name.
+     * @param node Node to check cache.
+     * @return {@code true} in case cache is started.
+     */
+    private boolean isCacheStarted(String cacheName, IgniteEx node) {
+        GridCacheContext cacheCtx = node.context().cache().context().cacheContext(CU.cacheId(cacheName));
+
+        return cacheCtx != null;
+    }
+
+    /**
+     * Check is cache started on the given nodes.
+     *
+     * @param nodes Node to check cache.
+     * @param cacheName Cache name.
+     * @throws AssertionFailedError If failed.
+     */
+    private void assertCacheStarted(String cacheName, IgniteEx... nodes) throws AssertionFailedError {
+        for (IgniteEx node : nodes) {
+            assertTrue(isCacheStarted(cacheName, node));
+        }
+    }
+
+    /**
+     * Check is cache not started on the given nodes.
+     *
+     * @param nodes Node to check cache.
+     * @param cacheName Cache name.
+     * @throws AssertionFailedError If failed.
+     */
+    private void assertCacheNotStarted(String cacheName, IgniteEx... nodes) throws AssertionFailedError {
+        for (IgniteEx node : nodes) {
+            assertFalse(isCacheStarted(cacheName, node));
+        }
+    }
+
+    /**
      * Ensure that only provided types exists for the given cache.
      *
      * @param node Node.
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 e0703a5..04e90d5 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
@@ -59,6 +59,8 @@
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.configuration.WALMode;
 import org.apache.ignite.internal.DiscoverySpiTestListener;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.IgniteEx;
 import org.apache.ignite.internal.IgniteInternalFuture;
 import org.apache.ignite.internal.IgniteInterruptedCheckedException;
@@ -235,6 +237,11 @@
         cleanPersistenceDir();
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * @throws Exception if failed.
      */
diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/IgniteSqlSplitterSelfTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/IgniteSqlSplitterSelfTest.java
index df226b2..1ce2b26 100644
--- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/IgniteSqlSplitterSelfTest.java
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/IgniteSqlSplitterSelfTest.java
@@ -160,7 +160,9 @@
 
     /**
      */
-    public void _testMergeJoin() {
+    public void testMergeJoin() {
+        fail("https://issues.apache.org/jira/browse/IGNITE-10199");
+
         IgniteCache<Integer, Org> c = ignite(CLIENT).getOrCreateCache(cacheConfig("org", true,
             Integer.class, Org.class));
 
diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/SqlIllegalSchemaSelfTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/SqlIllegalSchemaSelfTest.java
index a91311a..a75a365 100644
--- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/SqlIllegalSchemaSelfTest.java
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/SqlIllegalSchemaSelfTest.java
@@ -26,6 +26,8 @@
 import org.apache.ignite.Ignition;
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.util.typedef.F;
 import org.apache.ignite.testframework.GridTestUtils;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
@@ -41,6 +43,11 @@
         stopAllGrids();
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      * @throws Exception If failed.
      */
diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/GridIndexRebuildSelfTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/GridIndexRebuildSelfTest.java
index c5f1441..9afb749 100644
--- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/GridIndexRebuildSelfTest.java
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/GridIndexRebuildSelfTest.java
@@ -24,12 +24,14 @@
 import org.apache.ignite.IgniteCheckedException;
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.internal.IgniteEx;
+import org.apache.ignite.internal.processors.cache.GridCacheContext;
 import org.apache.ignite.internal.processors.cache.IgniteCacheOffheapManager;
 import org.apache.ignite.internal.processors.cache.IgniteInternalCache;
 import org.apache.ignite.internal.processors.cache.index.DynamicIndexAbstractSelfTest;
 import org.apache.ignite.internal.processors.cache.persistence.CacheDataRow;
 import org.apache.ignite.internal.processors.cache.persistence.file.FilePageStoreManager;
 import org.apache.ignite.internal.processors.query.GridQueryProcessor;
+import org.apache.ignite.internal.processors.query.schema.SchemaIndexCacheVisitorClosure;
 import org.apache.ignite.internal.util.lang.GridCursor;
 import org.apache.ignite.internal.util.typedef.internal.U;
 
@@ -38,7 +40,7 @@
  */
 public class GridIndexRebuildSelfTest extends DynamicIndexAbstractSelfTest {
     /** Data size. */
-    protected static final int AMOUNT = 300;
+    protected static final int AMOUNT = 50;
 
     /** Data size. */
     protected static final String CACHE_NAME = "T";
@@ -113,7 +115,7 @@
         IgniteEx srv = startServer();
 
         execute(srv, "CREATE TABLE T(k int primary key, v int) WITH \"cache_name=T,wrap_value=false," +
-            "atomicity=transactional_snapshot\"");
+            "atomicity=transactional\"");
 
         execute(srv, "CREATE INDEX IDX ON T(v)");
 
@@ -228,13 +230,14 @@
         private boolean firstRbld = true;
 
         /** {@inheritDoc} */
-        @Override public void rebuildIndexesFromHash(String cacheName) throws IgniteCheckedException {
+        @Override protected void rebuildIndexesFromHash0(GridCacheContext cctx, SchemaIndexCacheVisitorClosure clo)
+            throws IgniteCheckedException {
             if (!firstRbld)
                 U.await(INSTANCE.rebuildLatch);
             else
                 firstRbld = false;
 
-            super.rebuildIndexesFromHash(cacheName);
+            super.rebuildIndexesFromHash0(cctx, clo);
         }
     }
 }
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 25cb473..d96b445 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
@@ -43,6 +43,8 @@
 import org.apache.ignite.internal.processors.cache.CacheSqlQueryValueCopySelfTest;
 import org.apache.ignite.internal.processors.cache.DdlTransactionSelfTest;
 import org.apache.ignite.internal.processors.cache.GridCacheCrossCacheQuerySelfTest;
+import org.apache.ignite.internal.processors.cache.GridCacheDynamicLoadOnClientPersistentTest;
+import org.apache.ignite.internal.processors.cache.GridCacheDynamicLoadOnClientTest;
 import org.apache.ignite.internal.processors.cache.GridCacheFullTextQuerySelfTest;
 import org.apache.ignite.internal.processors.cache.GridCacheLazyQueryPartitionsReleaseTest;
 import org.apache.ignite.internal.processors.cache.GridCacheQueryIndexDisabledSelfTest;
@@ -533,6 +535,9 @@
         // Partition pruning.
         suite.addTestSuite(InOperationExtractPartitionSelfTest.class);
 
+        suite.addTestSuite(GridCacheDynamicLoadOnClientTest.class);
+        suite.addTestSuite(GridCacheDynamicLoadOnClientPersistentTest.class);
+
         return suite;
     }
 }
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/clustering/kmeans/KMeansTrainer.java b/modules/ml/src/main/java/org/apache/ignite/ml/clustering/kmeans/KMeansTrainer.java
index a20d5da..88ea9b9 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/clustering/kmeans/KMeansTrainer.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/clustering/kmeans/KMeansTrainer.java
@@ -32,6 +32,7 @@
 import org.apache.ignite.ml.dataset.DatasetBuilder;
 import org.apache.ignite.ml.dataset.PartitionDataBuilder;
 import org.apache.ignite.ml.dataset.primitive.context.EmptyContext;
+import org.apache.ignite.ml.environment.LearningEnvironmentBuilder;
 import org.apache.ignite.ml.math.distances.DistanceMeasure;
 import org.apache.ignite.ml.math.distances.EuclideanDistance;
 import org.apache.ignite.ml.math.functions.IgniteBiFunction;
@@ -78,6 +79,11 @@
     }
 
     /** {@inheritDoc} */
+    @Override public KMeansTrainer withEnvironmentBuilder(LearningEnvironmentBuilder envBuilder) {
+        return (KMeansTrainer)super.withEnvironmentBuilder(envBuilder);
+    }
+
+    /** {@inheritDoc} */
     @Override protected <K, V> KMeansModel updateModel(KMeansModel mdl, DatasetBuilder<K, V> datasetBuilder,
         IgniteBiFunction<K, V, Vector> featureExtractor, IgniteBiFunction<K, V, Double> lbExtractor) {
 
@@ -91,7 +97,8 @@
         Vector[] centers;
 
         try (Dataset<EmptyContext, LabeledVectorSet<Double, LabeledVector>> dataset = datasetBuilder.build(
-            (upstream, upstreamSize) -> new EmptyContext(),
+            envBuilder,
+            (env, upstream, upstreamSize) -> new EmptyContext(),
             partDataBuilder
         )) {
             final Integer cols = dataset.compute(org.apache.ignite.ml.structures.Dataset::colSize, (a, b) -> {
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/composition/boosting/GDBBinaryClassifierTrainer.java b/modules/ml/src/main/java/org/apache/ignite/ml/composition/boosting/GDBBinaryClassifierTrainer.java
index 8682a46..3acca14 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/composition/boosting/GDBBinaryClassifierTrainer.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/composition/boosting/GDBBinaryClassifierTrainer.java
@@ -25,12 +25,14 @@
 import org.apache.ignite.ml.composition.boosting.loss.Loss;
 import org.apache.ignite.ml.dataset.DatasetBuilder;
 import org.apache.ignite.ml.dataset.primitive.builder.context.EmptyContextBuilder;
+import org.apache.ignite.ml.environment.LearningEnvironmentBuilder;
 import org.apache.ignite.ml.math.functions.IgniteBiFunction;
 import org.apache.ignite.ml.math.functions.IgniteFunction;
 import org.apache.ignite.ml.math.primitives.vector.Vector;
 import org.apache.ignite.ml.structures.LabeledVector;
 import org.apache.ignite.ml.structures.LabeledVectorSet;
 import org.apache.ignite.ml.structures.partition.LabeledDatasetPartitionDataBuilderOnHeap;
+import org.apache.ignite.ml.tree.boosting.GDBBinaryClassifierOnTreesTrainer;
 
 /**
  * Trainer for binary classifier using Gradient Boosting. As preparing stage this algorithm learn labels in dataset and
@@ -69,7 +71,10 @@
         IgniteBiFunction<K, V, Vector> featureExtractor,
         IgniteBiFunction<K, V, Double> lExtractor) {
 
-        Set<Double> uniqLabels = builder.build(new EmptyContextBuilder<>(), new LabeledDatasetPartitionDataBuilderOnHeap<>(featureExtractor, lExtractor))
+        Set<Double> uniqLabels = builder.build(
+            envBuilder,
+            new EmptyContextBuilder<>(),
+            new LabeledDatasetPartitionDataBuilderOnHeap<>(featureExtractor, lExtractor))
             .compute((IgniteFunction<LabeledVectorSet<Double, LabeledVector>, Set<Double>>)x ->
                     Arrays.stream(x.labels()).boxed().collect(Collectors.toSet()), (a, b) -> {
                     if (a == null)
@@ -102,4 +107,9 @@
         double internalCls = sigma < 0.5 ? 0.0 : 1.0;
         return internalCls == 0.0 ? externalFirstCls : externalSecondCls;
     }
+
+    /** {@inheritDoc} */
+    @Override public GDBBinaryClassifierOnTreesTrainer withEnvironmentBuilder(LearningEnvironmentBuilder envBuilder) {
+        return (GDBBinaryClassifierOnTreesTrainer)super.withEnvironmentBuilder(envBuilder);
+    }
 }
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/composition/boosting/GDBLearningStrategy.java b/modules/ml/src/main/java/org/apache/ignite/ml/composition/boosting/GDBLearningStrategy.java
index e689b91..0b87748 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/composition/boosting/GDBLearningStrategy.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/composition/boosting/GDBLearningStrategy.java
@@ -29,6 +29,7 @@
 import org.apache.ignite.ml.composition.predictionsaggregator.WeightedPredictionsAggregator;
 import org.apache.ignite.ml.dataset.DatasetBuilder;
 import org.apache.ignite.ml.environment.LearningEnvironment;
+import org.apache.ignite.ml.environment.LearningEnvironmentBuilder;
 import org.apache.ignite.ml.environment.logging.MLLogger;
 import org.apache.ignite.ml.math.functions.IgniteBiFunction;
 import org.apache.ignite.ml.math.functions.IgniteFunction;
@@ -41,8 +42,11 @@
  * Learning strategy for gradient boosting.
  */
 public class GDBLearningStrategy {
-    /** Learning environment. */
-    protected LearningEnvironment environment;
+    /** Learning environment builder. */
+    protected LearningEnvironmentBuilder envBuilder;
+
+    /** Learning environment used for trainer. */
+    protected LearningEnvironment trainerEnvironment;
 
     /** Count of iterations. */
     protected int cntOfIterations;
@@ -101,6 +105,8 @@
     public <K,V> List<Model<Vector, Double>> update(GDBTrainer.GDBModel mdlToUpdate,
         DatasetBuilder<K, V> datasetBuilder, IgniteBiFunction<K, V, Vector> featureExtractor,
         IgniteBiFunction<K, V, Double> lbExtractor) {
+        if (trainerEnvironment == null)
+            throw new IllegalStateException("Learning environment builder is not set.");
 
         List<Model<Vector, Double>> models = initLearningState(mdlToUpdate);
 
@@ -113,7 +119,7 @@
 
             WeightedPredictionsAggregator aggregator = new WeightedPredictionsAggregator(weights, meanLbVal);
             ModelsComposition currComposition = new ModelsComposition(models, aggregator);
-            if (convCheck.isConverged(datasetBuilder, currComposition))
+            if (convCheck.isConverged(envBuilder, datasetBuilder, currComposition))
                 break;
 
             IgniteBiFunction<K, V, Double> lbExtractorWrap = (k, v) -> {
@@ -125,7 +131,7 @@
             long startTs = System.currentTimeMillis();
             models.add(trainer.fit(datasetBuilder, featureExtractor, lbExtractorWrap));
             double learningTime = (double)(System.currentTimeMillis() - startTs) / 1000.0;
-            environment.logger(getClass()).log(MLLogger.VerboseLevel.LOW, "One model training time was %.2fs", learningTime);
+            trainerEnvironment.logger(getClass()).log(MLLogger.VerboseLevel.LOW, "One model training time was %.2fs", learningTime);
         }
 
         return models;
@@ -157,10 +163,11 @@
     /**
      * Sets learning environment.
      *
-     * @param environment Learning Environment.
+     * @param envBuilder Learning Environment.
      */
-    public GDBLearningStrategy withEnvironment(LearningEnvironment environment) {
-        this.environment = environment;
+    public GDBLearningStrategy withEnvironmentBuilder(LearningEnvironmentBuilder envBuilder) {
+        this.envBuilder = envBuilder;
+        this.trainerEnvironment = envBuilder.buildForTrainer();
         return this;
     }
 
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/composition/boosting/GDBRegressionTrainer.java b/modules/ml/src/main/java/org/apache/ignite/ml/composition/boosting/GDBRegressionTrainer.java
index 8c1afd7..3dc95ee 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/composition/boosting/GDBRegressionTrainer.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/composition/boosting/GDBRegressionTrainer.java
@@ -19,6 +19,7 @@
 
 import org.apache.ignite.ml.composition.boosting.loss.SquaredError;
 import org.apache.ignite.ml.dataset.DatasetBuilder;
+import org.apache.ignite.ml.environment.LearningEnvironmentBuilder;
 import org.apache.ignite.ml.math.functions.IgniteBiFunction;
 import org.apache.ignite.ml.math.primitives.vector.Vector;
 
@@ -53,4 +54,9 @@
     @Override protected double internalLabelToExternal(double x) {
         return x;
     }
+
+    /** {@inheritDoc} */
+    @Override public GDBRegressionTrainer withEnvironmentBuilder(LearningEnvironmentBuilder envBuilder) {
+        return (GDBRegressionTrainer)super.withEnvironmentBuilder(envBuilder);
+    }
 }
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/composition/boosting/GDBTrainer.java b/modules/ml/src/main/java/org/apache/ignite/ml/composition/boosting/GDBTrainer.java
index 89cc6b1..03772ec 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/composition/boosting/GDBTrainer.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/composition/boosting/GDBTrainer.java
@@ -30,6 +30,7 @@
 import org.apache.ignite.ml.dataset.DatasetBuilder;
 import org.apache.ignite.ml.dataset.primitive.builder.context.EmptyContextBuilder;
 import org.apache.ignite.ml.dataset.primitive.context.EmptyContext;
+import org.apache.ignite.ml.environment.LearningEnvironmentBuilder;
 import org.apache.ignite.ml.environment.logging.MLLogger;
 import org.apache.ignite.ml.knn.regression.KNNRegressionTrainer;
 import org.apache.ignite.ml.math.functions.IgniteBiFunction;
@@ -99,7 +100,11 @@
         if (!learnLabels(datasetBuilder, featureExtractor, lbExtractor))
             return getLastTrainedModelOrThrowEmptyDatasetException(mdl);
 
-        IgniteBiTuple<Double, Long> initAndSampleSize = computeInitialValue(datasetBuilder, featureExtractor, lbExtractor);
+        IgniteBiTuple<Double, Long> initAndSampleSize = computeInitialValue(
+            envBuilder,
+            datasetBuilder,
+            featureExtractor,
+            lbExtractor);
         if(initAndSampleSize == null)
             return getLastTrainedModelOrThrowEmptyDatasetException(mdl);
 
@@ -112,7 +117,7 @@
             .withBaseModelTrainerBuilder(this::buildBaseModelTrainer)
             .withExternalLabelToInternal(this::externalLabelToInternal)
             .withCntOfIterations(cntOfIterations)
-            .withEnvironment(environment)
+            .withEnvironmentBuilder(envBuilder)
             .withLossGradient(loss)
             .withSampleSize(sampleSize)
             .withMeanLabelValue(mean)
@@ -140,6 +145,11 @@
         return mdl instanceof GDBModel;
     }
 
+    /** {@inheritDoc} */
+    @Override public GDBTrainer withEnvironmentBuilder(LearningEnvironmentBuilder envBuilder) {
+        return (GDBTrainer)super.withEnvironmentBuilder(envBuilder);
+    }
+
     /**
      * Defines unique labels in dataset if need (useful in case of classification).
      *
@@ -175,14 +185,18 @@
      * Compute mean value of label as first approximation.
      *
      * @param builder Dataset builder.
+     * @param envBuilder Learning environment builder.
      * @param featureExtractor Feature extractor.
      * @param lbExtractor Label extractor.
      */
-    protected <V, K> IgniteBiTuple<Double, Long> computeInitialValue(DatasetBuilder<K, V> builder,
+    protected <V, K> IgniteBiTuple<Double, Long> computeInitialValue(
+        LearningEnvironmentBuilder envBuilder,
+        DatasetBuilder<K, V> builder,
         IgniteBiFunction<K, V, Vector> featureExtractor,
         IgniteBiFunction<K, V, Double> lbExtractor) {
 
         try (Dataset<EmptyContext, DecisionTreeData> dataset = builder.build(
+            envBuilder,
             new EmptyContextBuilder<>(),
             new DecisionTreeDataBuilder<>(featureExtractor, lbExtractor, false)
         )) {
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/composition/boosting/convergence/ConvergenceChecker.java b/modules/ml/src/main/java/org/apache/ignite/ml/composition/boosting/convergence/ConvergenceChecker.java
index 88841e2..e383e39 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/composition/boosting/convergence/ConvergenceChecker.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/composition/boosting/convergence/ConvergenceChecker.java
@@ -26,6 +26,7 @@
 import org.apache.ignite.ml.dataset.primitive.FeatureMatrixWithLabelsOnHeapDataBuilder;
 import org.apache.ignite.ml.dataset.primitive.builder.context.EmptyContextBuilder;
 import org.apache.ignite.ml.dataset.primitive.context.EmptyContext;
+import org.apache.ignite.ml.environment.LearningEnvironmentBuilder;
 import org.apache.ignite.ml.math.functions.IgniteBiFunction;
 import org.apache.ignite.ml.math.functions.IgniteFunction;
 import org.apache.ignite.ml.math.primitives.vector.Vector;
@@ -88,11 +89,16 @@
     /**
      * Checks convergency on dataset.
      *
+     * @param envBuilder Learning environment builder.
      * @param currMdl Current model.
      * @return true if GDB is converged.
      */
-    public boolean isConverged(DatasetBuilder<K, V> datasetBuilder, ModelsComposition currMdl) {
+    public boolean isConverged(
+        LearningEnvironmentBuilder envBuilder,
+        DatasetBuilder<K, V> datasetBuilder,
+        ModelsComposition currMdl) {
         try (Dataset<EmptyContext, FeatureMatrixWithLabelsOnHeapData> dataset = datasetBuilder.build(
+            envBuilder,
             new EmptyContextBuilder<>(),
             new FeatureMatrixWithLabelsOnHeapDataBuilder<>(featureExtractor, lbExtractor)
         )) {
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/composition/boosting/convergence/simple/ConvergenceCheckerStub.java b/modules/ml/src/main/java/org/apache/ignite/ml/composition/boosting/convergence/simple/ConvergenceCheckerStub.java
index 98cfbe1..193afaf 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/composition/boosting/convergence/simple/ConvergenceCheckerStub.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/composition/boosting/convergence/simple/ConvergenceCheckerStub.java
@@ -24,6 +24,7 @@
 import org.apache.ignite.ml.dataset.DatasetBuilder;
 import org.apache.ignite.ml.dataset.primitive.FeatureMatrixWithLabelsOnHeapData;
 import org.apache.ignite.ml.dataset.primitive.context.EmptyContext;
+import org.apache.ignite.ml.environment.LearningEnvironmentBuilder;
 import org.apache.ignite.ml.math.functions.IgniteBiFunction;
 import org.apache.ignite.ml.math.functions.IgniteFunction;
 import org.apache.ignite.ml.math.primitives.vector.Vector;
@@ -60,7 +61,7 @@
     }
 
     /** {@inheritDoc} */
-    @Override public boolean isConverged(DatasetBuilder<K, V> datasetBuilder, ModelsComposition currMdl) {
+    @Override public boolean isConverged(LearningEnvironmentBuilder envBuilder, DatasetBuilder<K, V> datasetBuilder, ModelsComposition currMdl) {
         return false;
     }
 
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/dataset/Dataset.java b/modules/ml/src/main/java/org/apache/ignite/ml/dataset/Dataset.java
index 230a467..d821fe3 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/dataset/Dataset.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/dataset/Dataset.java
@@ -20,6 +20,7 @@
 import java.io.Serializable;
 import org.apache.ignite.ml.dataset.impl.cache.CacheBasedDataset;
 import org.apache.ignite.ml.dataset.impl.local.LocalDataset;
+import org.apache.ignite.ml.environment.LearningEnvironment;
 import org.apache.ignite.ml.math.functions.IgniteBiConsumer;
 import org.apache.ignite.ml.math.functions.IgniteBiFunction;
 import org.apache.ignite.ml.math.functions.IgniteBinaryOperator;
@@ -56,49 +57,50 @@
      * Applies the specified {@code map} function to every partition {@code data}, {@code context} and partition
      * index in the dataset and then reduces {@code map} results to final result by using the {@code reduce} function.
      *
-     * @param map Function applied to every partition {@code data}, {@code context} and partition index.
+     * @param map Function applied to every partition {@code data}, {@code context} and {@link LearningEnvironment}.
      * @param reduce Function applied to results of {@code map} to get final result.
      * @param identity Identity.
      * @param <R> Type of a result.
      * @return Final result.
      */
-    public <R> R computeWithCtx(IgniteTriFunction<C, D, Integer, R> map, IgniteBinaryOperator<R> reduce, R identity);
+    public <R> R computeWithCtx(IgniteTriFunction<C, D, LearningEnvironment, R> map, IgniteBinaryOperator<R> reduce, R identity);
 
     /**
-     * Applies the specified {@code map} function to every partition {@code data} and partition index in the dataset
-     * and then reduces {@code map} results to final result by using the {@code reduce} function.
+     * Applies the specified {@code map} function to every partition {@code data} and {@link LearningEnvironment}
+     * in the dataset and then reduces {@code map} results to final result by using the {@code reduce} function.
      *
-     * @param map Function applied to every partition {@code data} and partition index.
+     * @param map Function applied to every partition {@code data} and {@link LearningEnvironment}.
      * @param reduce Function applied to results of {@code map} to get final result.
      * @param identity Identity.
      * @param <R> Type of a result.
      * @return Final result.
      */
-    public <R> R compute(IgniteBiFunction<D, Integer, R> map, IgniteBinaryOperator<R> reduce, R identity);
+    public <R> R compute(IgniteBiFunction<D, LearningEnvironment, R> map, IgniteBinaryOperator<R> reduce, R identity);
 
     /**
-     * Applies the specified {@code map} function to every partition {@code data}, {@code context} and partition
-     * index in the dataset and then reduces {@code map} results to final result by using the {@code reduce} function.
+     * Applies the specified {@code map} function to every partition {@code data}, {@code context} and
+     * {@link LearningEnvironment} in the dataset and then reduces {@code map} results to final
+     * result by using the {@code reduce} function.
      *
-     * @param map Function applied to every partition {@code data}, {@code context} and partition index.
+     * @param map Function applied to every partition {@code data}, {@code context} and {@link LearningEnvironment}.
      * @param reduce Function applied to results of {@code map} to get final result.
      * @param <R> Type of a result.
      * @return Final result.
      */
-    public default <R> R computeWithCtx(IgniteTriFunction<C, D, Integer, R> map, IgniteBinaryOperator<R> reduce) {
+    public default <R> R computeWithCtx(IgniteTriFunction<C, D, LearningEnvironment, R> map, IgniteBinaryOperator<R> reduce) {
         return computeWithCtx(map, reduce, null);
     }
 
     /**
-     * Applies the specified {@code map} function to every partition {@code data} and partition index in the dataset
-     * and then reduces {@code map} results to final result by using the {@code reduce} function.
+     * Applies the specified {@code map} function to every partition {@code data} and {@link LearningEnvironment}
+     * in the dataset and then reduces {@code map} results to final result by using the {@code reduce} function.
      *
-     * @param map Function applied to every partition {@code data} and partition index.
+     * @param map Function applied to every partition {@code data} and {@link LearningEnvironment}.
      * @param reduce Function applied to results of {@code map} to get final result.
      * @param <R> Type of a result.
      * @return Final result.
      */
-    public default <R> R compute(IgniteBiFunction<D, Integer, R> map, IgniteBinaryOperator<R> reduce) {
+    public default <R> R compute(IgniteBiFunction<D, LearningEnvironment, R> map, IgniteBinaryOperator<R> reduce) {
         return compute(map, reduce, null);
     }
 
@@ -113,7 +115,7 @@
      * @return Final result.
      */
     public default <R> R computeWithCtx(IgniteBiFunction<C, D, R> map, IgniteBinaryOperator<R> reduce, R identity) {
-        return computeWithCtx((ctx, data, partIdx) -> map.apply(ctx, data), reduce, identity);
+        return computeWithCtx((ctx, data, env) -> map.apply(ctx, data), reduce, identity);
     }
 
     /**
@@ -127,7 +129,7 @@
      * @return Final result.
      */
     public default <R> R compute(IgniteFunction<D, R> map, IgniteBinaryOperator<R> reduce, R identity) {
-        return compute((data, partIdx) -> map.apply(data), reduce, identity);
+        return compute((data, env) -> map.apply(data), reduce, identity);
     }
 
     /**
@@ -140,7 +142,7 @@
      * @return Final result.
      */
     public default <R> R computeWithCtx(IgniteBiFunction<C, D, R> map, IgniteBinaryOperator<R> reduce) {
-        return computeWithCtx((ctx, data, partIdx) -> map.apply(ctx, data), reduce);
+        return computeWithCtx((ctx, data, env) -> map.apply(ctx, data), reduce);
     }
 
     /**
@@ -153,30 +155,31 @@
      * @return Final result.
      */
     public default <R> R compute(IgniteFunction<D, R> map, IgniteBinaryOperator<R> reduce) {
-        return compute((data, partIdx) -> map.apply(data), reduce);
+        return compute((data, env) -> map.apply(data), reduce);
     }
 
     /**
-     * Applies the specified {@code map} function to every partition {@code data}, {@code context} and partition
-     * index in the dataset.
+     * Applies the specified {@code map} function to every partition {@code data}, {@code context} and
+     * {@link LearningEnvironment} in the dataset.
      *
      * @param map Function applied to every partition {@code data}, {@code context} and partition index.
      */
-    public default void computeWithCtx(IgniteTriConsumer<C, D, Integer> map) {
-        computeWithCtx((ctx, data, partIdx) -> {
-            map.accept(ctx, data, partIdx);
+    public default void computeWithCtx(IgniteTriConsumer<C, D, LearningEnvironment> map) {
+        computeWithCtx((ctx, data, env) -> {
+            map.accept(ctx, data, env);
             return null;
         }, (a, b) -> null);
     }
 
     /**
-     * Applies the specified {@code map} function to every partition {@code data} in the dataset and partition index.
+     * Applies the specified {@code map} function to every partition {@code data} in the dataset and
+     * {@link LearningEnvironment}.
      *
      * @param map Function applied to every partition {@code data} and partition index.
      */
-    public default void compute(IgniteBiConsumer<D, Integer> map) {
-        compute((data, partIdx) -> {
-            map.accept(data, partIdx);
+    public default void compute(IgniteBiConsumer<D, LearningEnvironment> map) {
+        compute((data, env) -> {
+            map.accept(data, env);
             return null;
         }, (a, b) -> null);
     }
@@ -187,7 +190,7 @@
      * @param map Function applied to every partition {@code data} and {@code context}.
      */
     public default void computeWithCtx(IgniteBiConsumer<C, D> map) {
-        computeWithCtx((ctx, data, partIdx) -> map.accept(ctx, data));
+        computeWithCtx((ctx, data, env) -> map.accept(ctx, data));
     }
 
     /**
@@ -196,7 +199,7 @@
      * @param map Function applied to every partition {@code data}.
      */
     public default void compute(IgniteConsumer<D> map) {
-        compute((data, partIdx) -> map.accept(data));
+        compute((data, env) -> map.accept(data));
     }
 
     /**
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/dataset/DatasetBuilder.java b/modules/ml/src/main/java/org/apache/ignite/ml/dataset/DatasetBuilder.java
index 4dd0a96..9900659 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/dataset/DatasetBuilder.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/dataset/DatasetBuilder.java
@@ -21,6 +21,7 @@
 import org.apache.ignite.lang.IgniteBiPredicate;
 import org.apache.ignite.ml.dataset.impl.cache.CacheBasedDatasetBuilder;
 import org.apache.ignite.ml.dataset.impl.local.LocalDatasetBuilder;
+import org.apache.ignite.ml.environment.LearningEnvironmentBuilder;
 import org.apache.ignite.ml.trainers.transformers.BaggingUpstreamTransformer;
 
 /**
@@ -40,6 +41,7 @@
      * Constructs a new instance of {@link Dataset} that includes allocation required data structures and
      * initialization of {@code context} part of partitions.
      *
+     * @param envBuilder Learning environment builder.
      * @param partCtxBuilder Partition {@code context} builder.
      * @param partDataBuilder Partition {@code data} builder.
      * @param <C> Type of a partition {@code context}.
@@ -47,18 +49,25 @@
      * @return Dataset.
      */
     public <C extends Serializable, D extends AutoCloseable> Dataset<C, D> build(
-        PartitionContextBuilder<K, V, C> partCtxBuilder, PartitionDataBuilder<K, V, C, D> partDataBuilder);
+        LearningEnvironmentBuilder envBuilder,
+        PartitionContextBuilder<K, V, C> partCtxBuilder,
+        PartitionDataBuilder<K, V, C, D> partDataBuilder);
 
     /**
-     * Get upstream transformers chain. This chain is applied to upstream data before it is passed
+     * Returns new instance of {@link DatasetBuilder} with new {@link UpstreamTransformerBuilder} added
+     * to chain of upstream transformer builders. When needed, each builder in chain first transformed into
+     * {@link UpstreamTransformer}, those are in turn composed together one after another forming
+     * final {@link UpstreamTransformer}.
+     * This transformer is applied to upstream data before it is passed
      * to {@link PartitionDataBuilder} and {@link PartitionContextBuilder}. This is needed to allow
      * transformation to upstream data which are agnostic of any changes that happen after.
      * Such transformations may be used for deriving meta-algorithms such as bagging
      * (see {@link BaggingUpstreamTransformer}).
      *
-     * @return Upstream transformers chain.
+     * @return Returns new instance of {@link DatasetBuilder} with new {@link UpstreamTransformerBuilder} added
+     * to chain of upstream transformer builders.
      */
-    public UpstreamTransformerChain<K, V> upstreamTransformersChain();
+    public DatasetBuilder<K, V> withUpstreamTransformer(UpstreamTransformerBuilder<K, V> builder);
 
     /**
      * Returns new instance of DatasetBuilder using conjunction of internal filter and {@code filterToAdd}.
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/dataset/DatasetFactory.java b/modules/ml/src/main/java/org/apache/ignite/ml/dataset/DatasetFactory.java
index 1623a2b..ef8eb23 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/dataset/DatasetFactory.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/dataset/DatasetFactory.java
@@ -31,6 +31,7 @@
 import org.apache.ignite.ml.dataset.primitive.context.EmptyContext;
 import org.apache.ignite.ml.dataset.primitive.data.SimpleDatasetData;
 import org.apache.ignite.ml.dataset.primitive.data.SimpleLabeledDatasetData;
+import org.apache.ignite.ml.environment.LearningEnvironmentBuilder;
 import org.apache.ignite.ml.math.functions.IgniteBiFunction;
 import org.apache.ignite.ml.math.primitives.vector.Vector;
 
@@ -76,6 +77,7 @@
      * {@code partDataBuilder}. This is the generic methods that allows to create any Ignite Cache based datasets with
      * any desired partition {@code context} and {@code data}.
      *
+     * @param envBuilder Learning environment builder.
      * @param datasetBuilder Dataset builder.
      * @param partCtxBuilder Partition {@code context} builder.
      * @param partDataBuilder Partition {@code data} builder.
@@ -86,13 +88,71 @@
      * @return Dataset.
      */
     public static <K, V, C extends Serializable, D extends AutoCloseable> Dataset<C, D> create(
-        DatasetBuilder<K, V> datasetBuilder, PartitionContextBuilder<K, V, C> partCtxBuilder,
+        DatasetBuilder<K, V> datasetBuilder,
+        LearningEnvironmentBuilder envBuilder,
+        PartitionContextBuilder<K, V, C> partCtxBuilder,
         PartitionDataBuilder<K, V, C, D> partDataBuilder) {
         return datasetBuilder.build(
+            envBuilder,
             partCtxBuilder,
             partDataBuilder
         );
     }
+
+    /**
+     * Creates a new instance of distributed dataset using the specified {@code partCtxBuilder} and
+     * {@code partDataBuilder}. This is the generic methods that allows to create any Ignite Cache based datasets with
+     * any desired partition {@code context} and {@code data}.
+     *
+     * @param datasetBuilder Dataset builder.
+     * @param partCtxBuilder Partition {@code context} builder.
+     * @param partDataBuilder Partition {@code data} builder.
+     * @param <K> Type of a key in {@code upstream} data.
+     * @param <V> ype of a value in {@code upstream} data.
+     * @param <C> Type of a partition {@code context}.
+     * @param <D> Type of a partition {@code data}.
+     * @return Dataset.
+     */
+    public static <K, V, C extends Serializable, D extends AutoCloseable> Dataset<C, D> create(
+        DatasetBuilder<K, V> datasetBuilder,
+        PartitionContextBuilder<K, V, C> partCtxBuilder,
+        PartitionDataBuilder<K, V, C, D> partDataBuilder) {
+        return datasetBuilder.build(
+            LearningEnvironmentBuilder.defaultBuilder(),
+            partCtxBuilder,
+            partDataBuilder
+        );
+    }
+
+    /**
+     * Creates a new instance of distributed dataset using the specified {@code partCtxBuilder} and
+     * {@code partDataBuilder}. This is the generic methods that allows to create any Ignite Cache based datasets with
+     * any desired partition {@code context} and {@code data}.
+     *
+     * @param ignite Ignite instance.
+     * @param upstreamCache Ignite Cache with {@code upstream} data.
+     * @param envBuilder Learning environment builder.
+     * @param partCtxBuilder Partition {@code context} builder.
+     * @param partDataBuilder Partition {@code data} builder.
+     * @param <K> Type of a key in {@code upstream} data.
+     * @param <V> Type of a value in {@code upstream} data.
+     * @param <C> Type of a partition {@code context}.
+     * @param <D> Type of a partition {@code data}.
+     * @return Dataset.
+     */
+    public static <K, V, C extends Serializable, D extends AutoCloseable> Dataset<C, D> create(
+        Ignite ignite, IgniteCache<K, V> upstreamCache,
+        LearningEnvironmentBuilder envBuilder,
+        PartitionContextBuilder<K, V, C> partCtxBuilder,
+        PartitionDataBuilder<K, V, C, D> partDataBuilder) {
+        return create(
+            new CacheBasedDatasetBuilder<>(ignite, upstreamCache),
+            envBuilder,
+            partCtxBuilder,
+            partDataBuilder
+        );
+    }
+
     /**
      * Creates a new instance of distributed dataset using the specified {@code partCtxBuilder} and
      * {@code partDataBuilder}. This is the generic methods that allows to create any Ignite Cache based datasets with
@@ -109,7 +169,8 @@
      * @return Dataset.
      */
     public static <K, V, C extends Serializable, D extends AutoCloseable> Dataset<C, D> create(
-        Ignite ignite, IgniteCache<K, V> upstreamCache, PartitionContextBuilder<K, V, C> partCtxBuilder,
+        Ignite ignite, IgniteCache<K, V> upstreamCache,
+        PartitionContextBuilder<K, V, C> partCtxBuilder,
         PartitionDataBuilder<K, V, C, D> partDataBuilder) {
         return create(
             new CacheBasedDatasetBuilder<>(ignite, upstreamCache),
@@ -124,6 +185,7 @@
      * allows to use any desired type of partition {@code context}.
      *
      * @param datasetBuilder Dataset builder.
+     * @param envBuilder Learning environment builder.
      * @param partCtxBuilder Partition {@code context} builder.
      * @param featureExtractor Feature extractor used to extract features and build {@link SimpleDatasetData}.
      * @param <K> Type of a key in {@code upstream} data.
@@ -132,10 +194,13 @@
      * @return Dataset.
      */
     public static <K, V, C extends Serializable> SimpleDataset<C> createSimpleDataset(
-        DatasetBuilder<K, V> datasetBuilder, PartitionContextBuilder<K, V, C> partCtxBuilder,
+        DatasetBuilder<K, V> datasetBuilder,
+        LearningEnvironmentBuilder envBuilder,
+        PartitionContextBuilder<K, V, C> partCtxBuilder,
         IgniteBiFunction<K, V, Vector> featureExtractor) {
         return create(
             datasetBuilder,
+            envBuilder,
             partCtxBuilder,
             new SimpleDatasetDataBuilder<>(featureExtractor)
         ).wrap(SimpleDataset::new);
@@ -148,6 +213,7 @@
      *
      * @param ignite Ignite instance.
      * @param upstreamCache Ignite Cache with {@code upstream} data.
+     * @param envBuilder Learning environment builder.
      * @param partCtxBuilder Partition {@code context} builder.
      * @param featureExtractor Feature extractor used to extract features and build {@link SimpleDatasetData}.
      * @param <K> Type of a key in {@code upstream} data.
@@ -156,10 +222,13 @@
      * @return Dataset.
      */
     public static <K, V, C extends Serializable> SimpleDataset<C> createSimpleDataset(Ignite ignite,
-        IgniteCache<K, V> upstreamCache, PartitionContextBuilder<K, V, C> partCtxBuilder,
+        IgniteCache<K, V> upstreamCache,
+        LearningEnvironmentBuilder envBuilder,
+        PartitionContextBuilder<K, V, C> partCtxBuilder,
         IgniteBiFunction<K, V, Vector> featureExtractor) {
         return createSimpleDataset(
             new CacheBasedDatasetBuilder<>(ignite, upstreamCache),
+            envBuilder,
             partCtxBuilder,
             featureExtractor
         );
@@ -171,6 +240,7 @@
      * {@link SimpleLabeledDatasetData}, but allows to use any desired type of partition {@code context}.
      *
      * @param datasetBuilder Dataset builder.
+     * @param envBuilder Learning environment builder.
      * @param partCtxBuilder Partition {@code context} builder.
      * @param featureExtractor Feature extractor used to extract features and build {@link SimpleLabeledDatasetData}.
      * @param lbExtractor Label extractor used to extract labels and build {@link SimpleLabeledDatasetData}.
@@ -180,10 +250,14 @@
      * @return Dataset.
      */
     public static <K, V, C extends Serializable> SimpleLabeledDataset<C> createSimpleLabeledDataset(
-        DatasetBuilder<K, V> datasetBuilder, PartitionContextBuilder<K, V, C> partCtxBuilder,
-        IgniteBiFunction<K, V, Vector> featureExtractor, IgniteBiFunction<K, V, double[]> lbExtractor) {
+        DatasetBuilder<K, V> datasetBuilder,
+        LearningEnvironmentBuilder envBuilder,
+        PartitionContextBuilder<K, V, C> partCtxBuilder,
+        IgniteBiFunction<K, V, Vector> featureExtractor,
+        IgniteBiFunction<K, V, double[]> lbExtractor) {
         return create(
             datasetBuilder,
+            envBuilder,
             partCtxBuilder,
             new SimpleLabeledDatasetDataBuilder<>(featureExtractor, lbExtractor)
         ).wrap(SimpleLabeledDataset::new);
@@ -196,6 +270,7 @@
      *
      * @param ignite Ignite instance.
      * @param upstreamCache Ignite Cache with {@code upstream} data.
+     * @param envBuilder Learning environment builder.
      * @param partCtxBuilder Partition {@code context} builder.
      * @param featureExtractor Feature extractor used to extract features and build {@link SimpleLabeledDatasetData}.
      * @param lbExtractor Label extractor used to extract labels and build {@link SimpleLabeledDatasetData}.
@@ -204,11 +279,16 @@
      * @param <C> Type of a partition {@code context}.
      * @return Dataset.
      */
-    public static <K, V, C extends Serializable> SimpleLabeledDataset<C> createSimpleLabeledDataset(Ignite ignite,
-        IgniteCache<K, V> upstreamCache, PartitionContextBuilder<K, V, C> partCtxBuilder,
-        IgniteBiFunction<K, V, Vector> featureExtractor, IgniteBiFunction<K, V, double[]> lbExtractor) {
+    public static <K, V, C extends Serializable> SimpleLabeledDataset<C> createSimpleLabeledDataset(
+        Ignite ignite,
+        IgniteCache<K, V> upstreamCache,
+        LearningEnvironmentBuilder envBuilder,
+        PartitionContextBuilder<K, V, C> partCtxBuilder,
+        IgniteBiFunction<K, V, Vector> featureExtractor,
+        IgniteBiFunction<K, V, double[]> lbExtractor) {
         return createSimpleLabeledDataset(
             new CacheBasedDatasetBuilder<>(ignite, upstreamCache),
+            envBuilder,
             partCtxBuilder,
             featureExtractor,
             lbExtractor
@@ -221,15 +301,19 @@
      * {@link SimpleDatasetData}.
      *
      * @param datasetBuilder Dataset builder.
+     * @param envBuilder Learning environment builder.
      * @param featureExtractor Feature extractor used to extract features and build {@link SimpleDatasetData}.
      * @param <K> Type of a key in {@code upstream} data.
      * @param <V> Type of a value in {@code upstream} data.
      * @return Dataset.
      */
-    public static <K, V> SimpleDataset<EmptyContext> createSimpleDataset(DatasetBuilder<K, V> datasetBuilder,
+    public static <K, V> SimpleDataset<EmptyContext> createSimpleDataset(
+        DatasetBuilder<K, V> datasetBuilder,
+        LearningEnvironmentBuilder envBuilder,
         IgniteBiFunction<K, V, Vector> featureExtractor) {
         return createSimpleDataset(
             datasetBuilder,
+            envBuilder,
             new EmptyContextBuilder<>(),
             featureExtractor
         );
@@ -242,15 +326,43 @@
      *
      * @param ignite Ignite instance.
      * @param upstreamCache Ignite Cache with {@code upstream} data.
+     * @param envBuilder Learning environment builder.
+     * @param featureExtractor Feature extractor used to extract features and build {@link SimpleDatasetData}.
+     * @param <K> Type of a key in {@code upstream} data.
+     * @param <V> Type of a value in {@code upstream} data.
+     * @return Dataset.
+     */
+    public static <K, V> SimpleDataset<EmptyContext> createSimpleDataset(
+        Ignite ignite,
+        IgniteCache<K, V> upstreamCache,
+        LearningEnvironmentBuilder envBuilder,
+        IgniteBiFunction<K, V, Vector> featureExtractor) {
+        return createSimpleDataset(
+            new CacheBasedDatasetBuilder<>(ignite, upstreamCache),
+            envBuilder,
+            featureExtractor
+        );
+    }
+
+    /**
+     * Creates a new instance of distributed {@link SimpleDataset} using the specified {@code featureExtractor}. This
+     * methods determines partition {@code context} to be {@link EmptyContext} and partition {@code data} to be
+     * {@link SimpleDatasetData}.
+     *
+     * @param ignite Ignite instance.
+     * @param upstreamCache Ignite Cache with {@code upstream} data.
      * @param featureExtractor Feature extractor used to extract features and build {@link SimpleDatasetData}.
      * @param <K> Type of a key in {@code upstream} data.
      * @param <V> Type of a value in {@code upstream} data.
      * @return Dataset.
      */
-    public static <K, V> SimpleDataset<EmptyContext> createSimpleDataset(Ignite ignite, IgniteCache<K, V> upstreamCache,
+    public static <K, V> SimpleDataset<EmptyContext> createSimpleDataset(
+        Ignite ignite,
+        IgniteCache<K, V> upstreamCache,
         IgniteBiFunction<K, V, Vector> featureExtractor) {
         return createSimpleDataset(
             new CacheBasedDatasetBuilder<>(ignite, upstreamCache),
+            LearningEnvironmentBuilder.defaultBuilder(),
             featureExtractor
         );
     }
@@ -261,6 +373,7 @@
      * partition {@code data} to be {@link SimpleLabeledDatasetData}.
      *
      * @param datasetBuilder Dataset builder.
+     * @param envBuilder Learning environment builder.
      * @param featureExtractor Feature extractor used to extract features and build {@link SimpleLabeledDatasetData}.
      * @param lbExtractor Label extractor used to extract labels and build {@link SimpleLabeledDatasetData}.
      * @param <K> Type of a key in {@code upstream} data.
@@ -268,10 +381,13 @@
      * @return Dataset.
      */
     public static <K, V> SimpleLabeledDataset<EmptyContext> createSimpleLabeledDataset(
-        DatasetBuilder<K, V> datasetBuilder, IgniteBiFunction<K, V, Vector> featureExtractor,
+        DatasetBuilder<K, V> datasetBuilder,
+        LearningEnvironmentBuilder envBuilder,
+        IgniteBiFunction<K, V, Vector> featureExtractor,
         IgniteBiFunction<K, V, double[]> lbExtractor) {
         return createSimpleLabeledDataset(
             datasetBuilder,
+            envBuilder,
             new EmptyContextBuilder<>(),
             featureExtractor,
             lbExtractor
@@ -285,17 +401,21 @@
      *
      * @param ignite Ignite instance.
      * @param upstreamCache Ignite Cache with {@code upstream} data.
+     * @param envBuilder Learning environment builder.
      * @param featureExtractor Feature extractor used to extract features and build {@link SimpleLabeledDatasetData}.
      * @param lbExtractor Label extractor used to extract labels and build {@link SimpleLabeledDatasetData}.
      * @param <K> Type of a key in {@code upstream} data.
      * @param <V> Type of a value in {@code upstream} data.
      * @return Dataset.
      */
-    public static <K, V> SimpleLabeledDataset<EmptyContext> createSimpleLabeledDataset(Ignite ignite,
+    public static <K, V> SimpleLabeledDataset<EmptyContext> createSimpleLabeledDataset(
+        Ignite ignite,
+        LearningEnvironmentBuilder envBuilder,
         IgniteCache<K, V> upstreamCache, IgniteBiFunction<K, V, Vector> featureExtractor,
         IgniteBiFunction<K, V, double[]> lbExtractor) {
         return createSimpleLabeledDataset(
             new CacheBasedDatasetBuilder<>(ignite, upstreamCache),
+            envBuilder,
             featureExtractor,
             lbExtractor
         );
@@ -309,6 +429,7 @@
      * @param upstreamMap {@code Map} with {@code upstream} data.
      * @param partitions Number of partitions {@code upstream} {@code Map} will be divided on.
      * @param partCtxBuilder Partition {@code context} builder.
+     * @param envBuilder Learning environment builder.
      * @param partDataBuilder Partition {@code data} builder.
      * @param <K> Type of a key in {@code upstream} data.
      * @param <V> Type of a value in {@code upstream} data.
@@ -317,10 +438,13 @@
      * @return Dataset.
      */
     public static <K, V, C extends Serializable, D extends AutoCloseable> Dataset<C, D> create(
-        Map<K, V> upstreamMap, int partitions, PartitionContextBuilder<K, V, C> partCtxBuilder,
+        Map<K, V> upstreamMap,
+        LearningEnvironmentBuilder envBuilder,
+        int partitions, PartitionContextBuilder<K, V, C> partCtxBuilder,
         PartitionDataBuilder<K, V, C, D> partDataBuilder) {
         return create(
             new LocalDatasetBuilder<>(upstreamMap, partitions),
+            envBuilder,
             partCtxBuilder,
             partDataBuilder
         );
@@ -333,6 +457,7 @@
      *
      * @param upstreamMap {@code Map} with {@code upstream} data.
      * @param partitions Number of partitions {@code upstream} {@code Map} will be divided on.
+     * @param envBuilder Learning environment builder.
      * @param partCtxBuilder Partition {@code context} builder.
      * @param featureExtractor Feature extractor used to extract features and build {@link SimpleDatasetData}.
      * @param <K> Type of a key in {@code upstream} data.
@@ -340,11 +465,15 @@
      * @param <C> Type of a partition {@code context}.
      * @return Dataset.
      */
-    public static <K, V, C extends Serializable> SimpleDataset<C> createSimpleDataset(Map<K, V> upstreamMap,
-        int partitions, PartitionContextBuilder<K, V, C> partCtxBuilder,
+    public static <K, V, C extends Serializable> SimpleDataset<C> createSimpleDataset(
+        Map<K, V> upstreamMap,
+        int partitions,
+        LearningEnvironmentBuilder envBuilder,
+        PartitionContextBuilder<K, V, C> partCtxBuilder,
         IgniteBiFunction<K, V, Vector> featureExtractor) {
         return createSimpleDataset(
             new LocalDatasetBuilder<>(upstreamMap, partitions),
+            envBuilder,
             partCtxBuilder,
             featureExtractor
         );
@@ -357,6 +486,7 @@
      *
      * @param upstreamMap {@code Map} with {@code upstream} data.
      * @param partitions Number of partitions {@code upstream} {@code Map} will be divided on.
+     * @param envBuilder Learning environment builder.
      * @param partCtxBuilder Partition {@code context} builder.
      * @param featureExtractor Feature extractor used to extract features and build {@link SimpleLabeledDatasetData}.
      * @param lbExtractor Label extractor used to extract labels and build {@link SimpleLabeledDatasetData}.
@@ -366,10 +496,14 @@
      * @return Dataset.
      */
     public static <K, V, C extends Serializable> SimpleLabeledDataset<C> createSimpleLabeledDataset(
-        Map<K, V> upstreamMap, int partitions, PartitionContextBuilder<K, V, C> partCtxBuilder,
+        Map<K, V> upstreamMap,
+        int partitions,
+        LearningEnvironmentBuilder envBuilder,
+        PartitionContextBuilder<K, V, C> partCtxBuilder,
         IgniteBiFunction<K, V, Vector> featureExtractor, IgniteBiFunction<K, V, double[]> lbExtractor) {
         return createSimpleLabeledDataset(
             new LocalDatasetBuilder<>(upstreamMap, partitions),
+            envBuilder,
             partCtxBuilder,
             featureExtractor, lbExtractor
         );
@@ -382,15 +516,18 @@
      *
      * @param upstreamMap {@code Map} with {@code upstream} data.
      * @param partitions Number of partitions {@code upstream} {@code Map} will be divided on.
+     * @param envBuilder Learning environment builder.
      * @param featureExtractor Feature extractor used to extract features and build {@link SimpleDatasetData}.
      * @param <K> Type of a key in {@code upstream} data.
      * @param <V> Type of a value in {@code upstream} data.
      * @return Dataset.
      */
     public static <K, V> SimpleDataset<EmptyContext> createSimpleDataset(Map<K, V> upstreamMap, int partitions,
+        LearningEnvironmentBuilder envBuilder,
         IgniteBiFunction<K, V, Vector> featureExtractor) {
         return createSimpleDataset(
             new LocalDatasetBuilder<>(upstreamMap, partitions),
+            envBuilder,
             featureExtractor
         );
     }
@@ -402,6 +539,7 @@
      *
      * @param upstreamMap {@code Map} with {@code upstream} data.
      * @param partitions Number of partitions {@code upstream} {@code Map} will be divided on.
+     * @param envBuilder Learning environment builder.
      * @param featureExtractor Feature extractor used to extract features and build {@link SimpleLabeledDatasetData}.
      * @param lbExtractor Label extractor used to extract labels and build {@link SimpleLabeledDatasetData}.
      * @param <K> Type of a key in {@code upstream} data.
@@ -409,10 +547,12 @@
      * @return Dataset.
      */
     public static <K, V> SimpleLabeledDataset<EmptyContext> createSimpleLabeledDataset(Map<K, V> upstreamMap,
+        LearningEnvironmentBuilder envBuilder,
         int partitions, IgniteBiFunction<K, V, Vector> featureExtractor,
         IgniteBiFunction<K, V, double[]> lbExtractor) {
         return createSimpleLabeledDataset(
             new LocalDatasetBuilder<>(upstreamMap, partitions),
+            envBuilder,
             featureExtractor,
             lbExtractor
         );
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/dataset/PartitionContextBuilder.java b/modules/ml/src/main/java/org/apache/ignite/ml/dataset/PartitionContextBuilder.java
index 6e1fec3..c5eac88 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/dataset/PartitionContextBuilder.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/dataset/PartitionContextBuilder.java
@@ -21,6 +21,7 @@
 import java.util.Iterator;
 import java.util.stream.Stream;
 import org.apache.ignite.ml.dataset.primitive.builder.context.EmptyContextBuilder;
+import org.apache.ignite.ml.environment.LearningEnvironment;
 import org.apache.ignite.ml.math.functions.IgniteFunction;
 
 /**
@@ -43,11 +44,12 @@
      * constraint. This constraint is omitted to allow upstream data transformers in {@link DatasetBuilder} replicating
      * entries. For example it can be useful for bootstrapping.
      *
+     * @param env Learning environment.
      * @param upstreamData Partition {@code upstream} data.
      * @param upstreamDataSize Partition {@code upstream} data size.
      * @return Partition {@code context}.
      */
-    public C build(Iterator<UpstreamEntry<K, V>> upstreamData, long upstreamDataSize);
+    public C build(LearningEnvironment env, Iterator<UpstreamEntry<K, V>> upstreamData, long upstreamDataSize);
 
 
     /**
@@ -57,12 +59,13 @@
      * constraint. This constraint is omitted to allow upstream data transformers in {@link DatasetBuilder} replicating
      * entries. For example it can be useful for bootstrapping.
      *
+     * @param env Learning environment.
      * @param upstreamData Partition {@code upstream} data.
      * @param upstreamDataSize Partition {@code upstream} data size.
      * @return Partition {@code context}.
      */
-    public default C build(Stream<UpstreamEntry<K, V>> upstreamData, long upstreamDataSize) {
-        return build(upstreamData.iterator(), upstreamDataSize);
+    public default C build(LearningEnvironment env, Stream<UpstreamEntry<K, V>> upstreamData, long upstreamDataSize) {
+        return build(env, upstreamData.iterator(), upstreamDataSize);
     }
 
     /**
@@ -74,6 +77,6 @@
      * @return Composed partition {@code context} builder.
      */
     public default <C2 extends Serializable> PartitionContextBuilder<K, V, C2> andThen(IgniteFunction<C, C2> fun) {
-        return (upstreamData, upstreamDataSize) -> fun.apply(build(upstreamData, upstreamDataSize));
+        return (env, upstreamData, upstreamDataSize) -> fun.apply(build(env, upstreamData, upstreamDataSize));
     }
 }
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/dataset/PartitionDataBuilder.java b/modules/ml/src/main/java/org/apache/ignite/ml/dataset/PartitionDataBuilder.java
index 106084b..4a0e68e 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/dataset/PartitionDataBuilder.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/dataset/PartitionDataBuilder.java
@@ -22,6 +22,7 @@
 import java.util.stream.Stream;
 import org.apache.ignite.ml.dataset.primitive.builder.data.SimpleDatasetDataBuilder;
 import org.apache.ignite.ml.dataset.primitive.builder.data.SimpleLabeledDatasetDataBuilder;
+import org.apache.ignite.ml.environment.LearningEnvironment;
 import org.apache.ignite.ml.math.functions.IgniteBiFunction;
 
 /**
@@ -46,12 +47,13 @@
      * constraint. This constraint is omitted to allow upstream data transformers in {@link DatasetBuilder} replicating
      * entries. For example it can be useful for bootstrapping.
      *
+     * @param env Learning environment.
      * @param upstreamData Partition {@code upstream} data.
      * @param upstreamDataSize Partition {@code upstream} data size.
      * @param ctx Partition {@code context}.
      * @return Partition {@code data}.
      */
-    public D build(Iterator<UpstreamEntry<K, V>> upstreamData, long upstreamDataSize, C ctx);
+    public D build(LearningEnvironment env, Iterator<UpstreamEntry<K, V>> upstreamData, long upstreamDataSize, C ctx);
 
     /**
      * Builds a new partition {@code data} from a partition {@code upstream} data and partition {@code context}.
@@ -60,13 +62,14 @@
      * constraint. This constraint is omitted to allow upstream data transformers in {@link DatasetBuilder} replicating
      * entries. For example it can be useful for bootstrapping.
      *
+     * @param env Learning environment.
      * @param upstreamData Partition {@code upstream} data.
      * @param upstreamDataSize Partition {@code upstream} data size.
      * @param ctx Partition {@code context}.
      * @return Partition {@code data}.
      */
-    public default D build(Stream<UpstreamEntry<K, V>> upstreamData, long upstreamDataSize, C ctx) {
-        return build(upstreamData.iterator(), upstreamDataSize, ctx);
+    public default D build(LearningEnvironment env, Stream<UpstreamEntry<K, V>> upstreamData, long upstreamDataSize, C ctx) {
+        return build(env, upstreamData.iterator(), upstreamDataSize, ctx);
     }
 
     /**
@@ -79,6 +82,7 @@
      */
     public default <D2 extends AutoCloseable> PartitionDataBuilder<K, V, C, D2> andThen(
         IgniteBiFunction<D, C, D2> fun) {
-        return (upstreamData, upstreamDataSize, ctx) -> fun.apply(build(upstreamData, upstreamDataSize, ctx), ctx);
+        return (env, upstreamData, upstreamDataSize, ctx) ->
+            fun.apply(build(env, upstreamData, upstreamDataSize, ctx), ctx);
     }
 }
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/dataset/UpstreamTransformer.java b/modules/ml/src/main/java/org/apache/ignite/ml/dataset/UpstreamTransformer.java
index ba70e2e..11b250b 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/dataset/UpstreamTransformer.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/dataset/UpstreamTransformer.java
@@ -18,7 +18,6 @@
 package org.apache.ignite.ml.dataset;
 
 import java.io.Serializable;
-import java.util.Random;
 import java.util.stream.Stream;
 
 /**
@@ -27,16 +26,25 @@
  * @param <K> Type of keys in the upstream.
  * @param <V> Type of values in the upstream.
  */
+// TODO: IGNITE-10297: Investigate possibility of API change.
 @FunctionalInterface
 public interface UpstreamTransformer<K, V> extends Serializable {
     /**
-     * Perform transformation of upstream.
+     * Transform upstream.
      *
-     * @param rnd Random numbers generator.
-     * @param upstream Upstream.
+     * @param upstream Upstream to transform.
      * @return Transformed upstream.
      */
-    // TODO: IGNITE-10296: Inject capabilities of randomization through learning environment.
-    // TODO: IGNITE-10297: Investigate possibility of API change.
-    public Stream<UpstreamEntry<K, V>> transform(Random rnd, Stream<UpstreamEntry<K, V>> upstream);
+    public Stream<UpstreamEntry<K, V>> transform(Stream<UpstreamEntry<K, V>> upstream);
+
+    /**
+     * Get composition of this transformer and other transformer which is
+     * itself is {@link UpstreamTransformer} applying this transformer and then other transformer.
+     *
+     * @param other Other transformer.
+     * @return Composition of this and other transformer.
+     */
+    default UpstreamTransformer<K, V> andThen(UpstreamTransformer<K, V> other) {
+        return upstream -> other.transform(transform(upstream));
+    }
 }
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/dataset/UpstreamTransformerBuilder.java b/modules/ml/src/main/java/org/apache/ignite/ml/dataset/UpstreamTransformerBuilder.java
new file mode 100644
index 0000000..9adfab5
--- /dev/null
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/dataset/UpstreamTransformerBuilder.java
@@ -0,0 +1,72 @@
+/*
+ * 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.ml.dataset;
+
+import java.io.Serializable;
+import org.apache.ignite.ml.environment.LearningEnvironment;
+
+/**
+ * Builder of {@link UpstreamTransformerBuilder}.
+ * @param <K> Type of keys in upstream.
+ * @param <V> Type of values in upstream.
+ */
+@FunctionalInterface
+public interface UpstreamTransformerBuilder<K, V> extends Serializable {
+    /**
+     * Create {@link UpstreamTransformer} based on learning environment.
+     *
+     * @param env Learning environment.
+     * @return Upstream transformer.
+     */
+    public UpstreamTransformer<K, V> build(LearningEnvironment env);
+
+    /**
+     * Combunes two builders (this and other respectfully)
+     * <pre>
+     * env -> transformer1
+     * env -> transformer2
+     * </pre>
+     * into
+     * <pre>
+     * env -> transformer2 . transformer1
+     * </pre>
+     *
+     * @param other Builder to combine with.
+     * @return Compositional builder.
+     */
+    public default UpstreamTransformerBuilder<K, V> andThen(UpstreamTransformerBuilder<K, V> other) {
+        UpstreamTransformerBuilder<K, V> self = this;
+        return env -> {
+            UpstreamTransformer<K, V> transformer1 = self.build(env);
+            UpstreamTransformer<K, V> transformer2 = other.build(env);
+
+            return upstream -> transformer2.transform(transformer1.transform(upstream));
+        };
+    }
+
+    /**
+     * Returns identity upstream transformer.
+     *
+     * @param <K> Type of keys in upstream.
+     * @param <V> Type of values in upstream.
+     * @return Identity upstream transformer.
+     */
+    public static <K, V> UpstreamTransformerBuilder<K, V> identity() {
+        return env -> upstream -> upstream;
+    }
+}
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/dataset/UpstreamTransformerChain.java b/modules/ml/src/main/java/org/apache/ignite/ml/dataset/UpstreamTransformerChain.java
deleted file mode 100644
index 3ad6446..0000000
--- a/modules/ml/src/main/java/org/apache/ignite/ml/dataset/UpstreamTransformerChain.java
+++ /dev/null
@@ -1,153 +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.ml.dataset;
-
-import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Random;
-import java.util.stream.Stream;
-import org.apache.ignite.ml.math.functions.IgniteFunction;
-
-/**
- * Class representing chain of transformers applied to upstream.
- *
- * @param <K> Type of upstream keys.
- * @param <V> Type of upstream values.
- */
-public class UpstreamTransformerChain<K, V> implements Serializable {
-    /** Seed used for transformations. */
-    private Long seed;
-
-    /** List of upstream transformations. */
-    private List<UpstreamTransformer<K, V>> list;
-
-    /**
-     * Creates empty upstream transformers chain (basically identity function).
-     *
-     * @param <K> Type of upstream keys.
-     * @param <V> Type of upstream values.
-     * @return Empty upstream transformers chain.
-     */
-    public static <K, V> UpstreamTransformerChain<K, V> empty() {
-        return new UpstreamTransformerChain<>();
-    }
-
-    /**
-     * Creates upstream transformers chain consisting of one specified transformer.
-     *
-     * @param <K> Type of upstream keys.
-     * @param <V> Type of upstream values.
-     * @return Upstream transformers chain consisting of one specified transformer.
-     */
-    public static <K, V> UpstreamTransformerChain<K, V> of(UpstreamTransformer<K, V> trans) {
-        UpstreamTransformerChain<K, V> res = new UpstreamTransformerChain<>();
-        return res.addUpstreamTransformer(trans);
-    }
-
-    /**
-     * Construct instance of this class.
-     */
-    private UpstreamTransformerChain() {
-        list = new ArrayList<>();
-        seed = new Random().nextLong();
-    }
-
-    /**
-     * Adds upstream transformer to this chain.
-     *
-     * @param next Transformer to add.
-     * @return This chain with added transformer.
-     */
-    public UpstreamTransformerChain<K, V> addUpstreamTransformer(UpstreamTransformer<K, V> next) {
-        list.add(next);
-
-        return this;
-    }
-
-    /**
-     * Add upstream transformer based on given lambda.
-     *
-     * @param transformer Transformer.
-     * @return This object.
-     */
-    public UpstreamTransformerChain<K, V> addUpstreamTransformer(IgniteFunction<Stream<UpstreamEntry<K, V>>,
-        Stream<UpstreamEntry<K, V>>> transformer) {
-        return addUpstreamTransformer((rnd, upstream) -> transformer.apply(upstream));
-    }
-
-    /**
-     * Performs stream transformation using RNG based on provided seed as pseudo-randomness source for all
-     * transformers in the chain.
-     *
-     * @param upstream Upstream.
-     * @return Transformed upstream.
-     */
-    public Stream<UpstreamEntry<K, V>> transform(Stream<UpstreamEntry<K, V>> upstream) {
-        Random rnd = new Random(seed);
-
-        Stream<UpstreamEntry<K, V>> res = upstream;
-
-        for (UpstreamTransformer<K, V> kvUpstreamTransformer : list)
-            res = kvUpstreamTransformer.transform(rnd, res);
-
-        return res;
-    }
-
-    /**
-     * Checks if this chain is empty.
-     *
-     * @return Result of check if this chain is empty.
-     */
-    public boolean isEmpty() {
-        return list.isEmpty();
-    }
-
-    /**
-     * Set seed for transformations.
-     *
-     * @param seed Seed.
-     * @return This object.
-     */
-    public UpstreamTransformerChain<K, V> setSeed(long seed) {
-        this.seed = seed;
-
-        return this;
-    }
-
-    /**
-     * Modifies seed for transformations if it is present.
-     *
-     * @param f Modification function.
-     * @return This object.
-     */
-    public UpstreamTransformerChain<K, V> modifySeed(IgniteFunction<Long, Long> f) {
-        seed = f.apply(seed);
-
-        return this;
-    }
-
-    /**
-     * Get seed used for RNG in transformations.
-     *
-     * @return Seed used for RNG in transformations.
-     */
-    public Long seed() {
-        return seed;
-    }
-}
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/dataset/impl/bootstrapping/BootstrappedDatasetBuilder.java b/modules/ml/src/main/java/org/apache/ignite/ml/dataset/impl/bootstrapping/BootstrappedDatasetBuilder.java
index 8707e3a..c8d78dd 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/dataset/impl/bootstrapping/BootstrappedDatasetBuilder.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/dataset/impl/bootstrapping/BootstrappedDatasetBuilder.java
@@ -20,9 +20,11 @@
 import java.util.Arrays;
 import java.util.Iterator;
 import org.apache.commons.math3.distribution.PoissonDistribution;
+import org.apache.commons.math3.random.Well19937c;
 import org.apache.ignite.ml.dataset.PartitionDataBuilder;
 import org.apache.ignite.ml.dataset.UpstreamEntry;
 import org.apache.ignite.ml.dataset.primitive.context.EmptyContext;
+import org.apache.ignite.ml.environment.LearningEnvironment;
 import org.apache.ignite.ml.math.functions.IgniteBiFunction;
 import org.apache.ignite.ml.math.primitives.vector.Vector;
 
@@ -69,13 +71,22 @@
     }
 
     /** {@inheritDoc} */
-    @Override public BootstrappedDatasetPartition build(Iterator<UpstreamEntry<K, V>> upstreamData, long upstreamDataSize,
+    @Override public BootstrappedDatasetPartition build(
+        LearningEnvironment env,
+        Iterator<UpstreamEntry<K, V>> upstreamData,
+        long upstreamDataSize,
         EmptyContext ctx) {
 
         BootstrappedVector[] dataset = new BootstrappedVector[Math.toIntExact(upstreamDataSize)];
 
         int cntr = 0;
-        PoissonDistribution poissonDistribution = new PoissonDistribution(subsampleSize);
+
+        PoissonDistribution poissonDistribution = new PoissonDistribution(
+            new Well19937c(env.randomNumbersGenerator().nextLong()),
+            subsampleSize,
+            PoissonDistribution.DEFAULT_EPSILON,
+            PoissonDistribution.DEFAULT_MAX_ITERATIONS);
+
         while(upstreamData.hasNext()) {
             UpstreamEntry<K, V> nextRow = upstreamData.next();
             Vector features = featureExtractor.apply(nextRow.getKey(), nextRow.getValue());
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/dataset/impl/cache/CacheBasedDataset.java b/modules/ml/src/main/java/org/apache/ignite/ml/dataset/impl/cache/CacheBasedDataset.java
index 0736906..bde4bb6 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/dataset/impl/cache/CacheBasedDataset.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/dataset/impl/cache/CacheBasedDataset.java
@@ -28,8 +28,10 @@
 import org.apache.ignite.ml.dataset.Dataset;
 import org.apache.ignite.ml.dataset.DatasetBuilder;
 import org.apache.ignite.ml.dataset.PartitionDataBuilder;
-import org.apache.ignite.ml.dataset.UpstreamTransformerChain;
+import org.apache.ignite.ml.dataset.UpstreamTransformerBuilder;
 import org.apache.ignite.ml.dataset.impl.cache.util.ComputeUtils;
+import org.apache.ignite.ml.environment.LearningEnvironment;
+import org.apache.ignite.ml.environment.LearningEnvironmentBuilder;
 import org.apache.ignite.ml.math.functions.IgniteBiFunction;
 import org.apache.ignite.ml.math.functions.IgniteBinaryOperator;
 import org.apache.ignite.ml.math.functions.IgniteFunction;
@@ -61,8 +63,8 @@
     /** Filter for {@code upstream} data. */
     private final IgniteBiPredicate<K, V> filter;
 
-    /** Chain of transformers applied to upstream. */
-    private final UpstreamTransformerChain<K, V> upstreamTransformers;
+    /** Builder of transformation applied to upstream. */
+    private final UpstreamTransformerBuilder<K, V> upstreamTransformerBuilder;
 
     /** Ignite Cache with partition {@code context}. */
     private final IgniteCache<Integer, C> datasetCache;
@@ -73,6 +75,9 @@
     /** Dataset ID that is used to identify dataset in local storage on the node where computation is performed. */
     private final UUID datasetId;
 
+    /** Learning environment builder. */
+    private final LearningEnvironmentBuilder envBuilder;
+
     /**
      * Constructs a new instance of dataset based on Ignite Cache, which is used as {@code upstream} and as reliable storage for
      * partition {@code context} as well.
@@ -80,7 +85,7 @@
      * @param ignite Ignite instance.
      * @param upstreamCache Ignite Cache with {@code upstream} data.
      * @param filter Filter for {@code upstream} data.
-     * @param upstreamTransformers Transformers of upstream data (see description in {@link DatasetBuilder}).
+     * @param upstreamTransformerBuilder Transformer of upstream data (see description in {@link DatasetBuilder}).
      * @param datasetCache Ignite Cache with partition {@code context}.
      * @param partDataBuilder Partition {@code data} builder.
      * @param datasetId Dataset ID.
@@ -89,39 +94,45 @@
         Ignite ignite,
         IgniteCache<K, V> upstreamCache,
         IgniteBiPredicate<K, V> filter,
-        UpstreamTransformerChain<K, V> upstreamTransformers,
-        IgniteCache<Integer, C> datasetCache, PartitionDataBuilder<K, V, C, D> partDataBuilder,
+        UpstreamTransformerBuilder<K, V> upstreamTransformerBuilder,
+        IgniteCache<Integer, C> datasetCache,
+        LearningEnvironmentBuilder envBuilder,
+        PartitionDataBuilder<K, V, C, D> partDataBuilder,
         UUID datasetId) {
         this.ignite = ignite;
         this.upstreamCache = upstreamCache;
         this.filter = filter;
-        this.upstreamTransformers = upstreamTransformers;
+        this.upstreamTransformerBuilder = upstreamTransformerBuilder;
         this.datasetCache = datasetCache;
         this.partDataBuilder = partDataBuilder;
+        this.envBuilder = envBuilder;
         this.datasetId = datasetId;
     }
 
     /** {@inheritDoc} */
-    @Override public <R> R computeWithCtx(IgniteTriFunction<C, D, Integer, R> map, IgniteBinaryOperator<R> reduce, R identity) {
+    @Override public <R> R computeWithCtx(IgniteTriFunction<C, D, LearningEnvironment, R> map, IgniteBinaryOperator<R> reduce, R identity) {
         String upstreamCacheName = upstreamCache.getName();
         String datasetCacheName = datasetCache.getName();
 
         return computeForAllPartitions(part -> {
+            LearningEnvironment env = ComputeUtils.getLearningEnvironment(ignite, datasetId, part, envBuilder);
+
             C ctx = ComputeUtils.getContext(Ignition.localIgnite(), datasetCacheName, part);
 
             D data = ComputeUtils.getData(
                 Ignition.localIgnite(),
                 upstreamCacheName,
                 filter,
-                upstreamTransformers,
+                upstreamTransformerBuilder,
                 datasetCacheName,
                 datasetId,
-                part,
-                partDataBuilder
+                partDataBuilder,
+                env
             );
 
+
             if (data != null) {
-                R res = map.apply(ctx, data, part);
+                R res = map.apply(ctx, data, env);
 
                 // Saves partition context after update.
                 ComputeUtils.saveContext(Ignition.localIgnite(), datasetCacheName, part, ctx);
@@ -134,23 +145,24 @@
     }
 
     /** {@inheritDoc} */
-    @Override public <R> R compute(IgniteBiFunction<D, Integer, R> map, IgniteBinaryOperator<R> reduce, R identity) {
+    @Override public <R> R compute(IgniteBiFunction<D, LearningEnvironment, R> map, IgniteBinaryOperator<R> reduce, R identity) {
         String upstreamCacheName = upstreamCache.getName();
         String datasetCacheName = datasetCache.getName();
 
         return computeForAllPartitions(part -> {
+            LearningEnvironment env = ComputeUtils.getLearningEnvironment(Ignition.localIgnite(), datasetId, part, envBuilder);
+
             D data = ComputeUtils.getData(
                 Ignition.localIgnite(),
                 upstreamCacheName,
                 filter,
-                upstreamTransformers,
+                upstreamTransformerBuilder,
                 datasetCacheName,
                 datasetId,
-                part,
-                partDataBuilder
+                partDataBuilder,
+                env
             );
-
-            return data != null ? map.apply(data, part) : null;
+            return data != null ? map.apply(data, env) : null;
         }, reduce, identity);
     }
 
@@ -158,6 +170,7 @@
     @Override public void close() {
         datasetCache.destroy();
         ComputeUtils.removeData(ignite, datasetId);
+        ComputeUtils.removeLearningEnv(ignite, datasetId);
     }
 
     /**
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/dataset/impl/cache/CacheBasedDatasetBuilder.java b/modules/ml/src/main/java/org/apache/ignite/ml/dataset/impl/cache/CacheBasedDatasetBuilder.java
index 1d00875..be40158 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/dataset/impl/cache/CacheBasedDatasetBuilder.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/dataset/impl/cache/CacheBasedDatasetBuilder.java
@@ -27,9 +27,10 @@
 import org.apache.ignite.ml.dataset.DatasetBuilder;
 import org.apache.ignite.ml.dataset.PartitionContextBuilder;
 import org.apache.ignite.ml.dataset.PartitionDataBuilder;
-import org.apache.ignite.ml.dataset.UpstreamTransformerChain;
+import org.apache.ignite.ml.dataset.UpstreamTransformerBuilder;
 import org.apache.ignite.ml.dataset.impl.cache.util.ComputeUtils;
 import org.apache.ignite.ml.dataset.impl.cache.util.DatasetAffinityFunctionWrapper;
+import org.apache.ignite.ml.environment.LearningEnvironmentBuilder;
 
 /**
  * A dataset builder that makes {@link CacheBasedDataset}. Encapsulate logic of building cache based dataset such as
@@ -57,8 +58,8 @@
     /** Filter for {@code upstream} data. */
     private final IgniteBiPredicate<K, V> filter;
 
-    /** Chain of upstream transformers. */
-    private final UpstreamTransformerChain<K, V> transformersChain;
+    /** Upstream transformer builder. */
+    private final UpstreamTransformerBuilder<K, V> transformerBuilder;
 
     /**
      * Constructs a new instance of cache based dataset builder that makes {@link CacheBasedDataset} with default
@@ -79,16 +80,32 @@
      * @param filter Filter for {@code upstream} data.
      */
     public CacheBasedDatasetBuilder(Ignite ignite, IgniteCache<K, V> upstreamCache, IgniteBiPredicate<K, V> filter) {
+        this(ignite, upstreamCache, filter, UpstreamTransformerBuilder.identity());
+    }
+
+    /**
+     * Constructs a new instance of cache based dataset builder that makes {@link CacheBasedDataset}.
+     *
+     * @param ignite Ignite instance.
+     * @param upstreamCache Ignite Cache with {@code upstream} data.
+     * @param filter Filter for {@code upstream} data.
+     */
+    public CacheBasedDatasetBuilder(Ignite ignite,
+        IgniteCache<K, V> upstreamCache,
+        IgniteBiPredicate<K, V> filter,
+        UpstreamTransformerBuilder<K, V> transformerBuilder) {
         this.ignite = ignite;
         this.upstreamCache = upstreamCache;
         this.filter = filter;
-        transformersChain = UpstreamTransformerChain.empty();
+        this.transformerBuilder = transformerBuilder;
     }
 
     /** {@inheritDoc} */
     @SuppressWarnings("unchecked")
     @Override public <C extends Serializable, D extends AutoCloseable> CacheBasedDataset<K, V, C, D> build(
-        PartitionContextBuilder<K, V, C> partCtxBuilder, PartitionDataBuilder<K, V, C, D> partDataBuilder) {
+        LearningEnvironmentBuilder envBuilder,
+        PartitionContextBuilder<K, V, C> partCtxBuilder,
+        PartitionDataBuilder<K, V, C, D> partDataBuilder) {
         UUID datasetId = UUID.randomUUID();
 
         // Retrieves affinity function of the upstream Ignite Cache.
@@ -106,25 +123,24 @@
         ComputeUtils.initContext(
             ignite,
             upstreamCache.getName(),
+            transformerBuilder,
             filter,
-            transformersChain,
             datasetCache.getName(),
             partCtxBuilder,
+            envBuilder,
             RETRIES,
             RETRY_INTERVAL
         );
 
-        return new CacheBasedDataset<>(ignite, upstreamCache, filter, transformersChain, datasetCache, partDataBuilder, datasetId);
+        return new CacheBasedDataset<>(ignite, upstreamCache, filter, transformerBuilder, datasetCache, envBuilder, partDataBuilder, datasetId);
     }
 
     /** {@inheritDoc} */
-    @Override public UpstreamTransformerChain<K, V> upstreamTransformersChain() {
-        return transformersChain;
+    @Override public DatasetBuilder<K, V> withUpstreamTransformer(UpstreamTransformerBuilder<K, V> builder) {
+        return new CacheBasedDatasetBuilder<>(ignite, upstreamCache, filter, transformerBuilder.andThen(builder));
     }
 
-    /**
-     * {@inheritDoc}
-     */
+    /** {@inheritDoc} */
     @Override public DatasetBuilder<K, V> withFilter(IgniteBiPredicate<K, V> filterToAdd) {
         return new CacheBasedDatasetBuilder<>(ignite, upstreamCache,
             (e1, e2) -> filter.apply(e1, e2) && filterToAdd.apply(e1, e2));
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/dataset/impl/cache/util/ComputeUtils.java b/modules/ml/src/main/java/org/apache/ignite/ml/dataset/impl/cache/util/ComputeUtils.java
index 4f18a18..1dc5591 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/dataset/impl/cache/util/ComputeUtils.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/dataset/impl/cache/util/ComputeUtils.java
@@ -26,6 +26,8 @@
 import java.util.Iterator;
 import java.util.Map;
 import java.util.UUID;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.locks.LockSupport;
 import java.util.stream.Stream;
 import org.apache.ignite.Ignite;
@@ -41,7 +43,10 @@
 import org.apache.ignite.ml.dataset.PartitionContextBuilder;
 import org.apache.ignite.ml.dataset.PartitionDataBuilder;
 import org.apache.ignite.ml.dataset.UpstreamEntry;
-import org.apache.ignite.ml.dataset.UpstreamTransformerChain;
+import org.apache.ignite.ml.dataset.UpstreamTransformer;
+import org.apache.ignite.ml.dataset.UpstreamTransformerBuilder;
+import org.apache.ignite.ml.environment.LearningEnvironment;
+import org.apache.ignite.ml.environment.LearningEnvironmentBuilder;
 import org.apache.ignite.ml.math.functions.IgniteFunction;
 import org.apache.ignite.ml.util.Utils;
 
@@ -49,11 +54,12 @@
  * Util class that provides common methods to perform computations on top of the Ignite Compute Grid.
  */
 public class ComputeUtils {
-    /**
-     * Template of the key used to store partition {@code data} in local storage.
-     */
+    /** Template of the key used to store partition {@code data} in local storage. */
     private static final String DATA_STORAGE_KEY_TEMPLATE = "part_data_storage_%s";
 
+    /** Template of the key used to store partition {@link LearningEnvironment} in local storage. */
+    private static final String ENVIRONMENT_STORAGE_KEY_TEMPLATE = "part_environment_storage_%s";
+
     /**
      * Calls the specified {@code fun} function on all partitions so that is't guaranteed that partitions with the same
      * index of all specified caches will be placed on the same node and will not be moved before computation is
@@ -134,6 +140,30 @@
     }
 
     /**
+     * Gets learning environment for given partition. If learning environment is not found in local node map,
+     * it will be created with specified {@link LearningEnvironmentBuilder}.
+     *
+     * @param ignite Ignite instance.
+     * @param datasetId Dataset id.
+     * @param part Partition index.
+     * @param envBuilder {@link LearningEnvironmentBuilder}.
+     * @return Learning environment for given partition.
+     */
+    public static LearningEnvironment getLearningEnvironment(Ignite ignite,
+        UUID datasetId,
+        int part,
+        LearningEnvironmentBuilder envBuilder) {
+
+        @SuppressWarnings("unchecked")
+        ConcurrentMap<Integer, LearningEnvironment> envStorage = (ConcurrentMap<Integer, LearningEnvironment>)ignite
+            .cluster()
+            .nodeLocalMap()
+            .computeIfAbsent(String.format(ENVIRONMENT_STORAGE_KEY_TEMPLATE, datasetId), key -> new ConcurrentHashMap<>());
+
+        return envStorage.computeIfAbsent(part, envBuilder::buildForWorker);
+    }
+
+    /**
      * Extracts partition {@code data} from the local storage, if it's not found in local storage recovers this {@code
      * data} from a partition {@code upstream} and {@code context}. Be aware that this method should be called from
      * the node where partition is placed.
@@ -141,11 +171,11 @@
      * @param ignite Ignite instance.
      * @param upstreamCacheName Name of an {@code upstream} cache.
      * @param filter Filter for {@code upstream} data.
-     * @param transformersChain Upstream transformers.
+     * @param transformerBuilder Builder of upstream transformers.
      * @param datasetCacheName Name of a partition {@code context} cache.
      * @param datasetId Dataset ID.
-     * @param part Partition index.
      * @param partDataBuilder Partition data builder.
+     * @param env Learning environment.
      * @param <K> Type of a key in {@code upstream} data.
      * @param <V> Type of a value in {@code upstream} data.
      * @param <C> Type of a partition {@code context}.
@@ -155,17 +185,18 @@
     public static <K, V, C extends Serializable, D extends AutoCloseable> D getData(
         Ignite ignite,
         String upstreamCacheName, IgniteBiPredicate<K, V> filter,
-        UpstreamTransformerChain<K, V> transformersChain,
-        String datasetCacheName,
-        UUID datasetId,
-        int part,
-        PartitionDataBuilder<K, V, C, D> partDataBuilder) {
+        UpstreamTransformerBuilder<K, V> transformerBuilder,
+        String datasetCacheName, UUID datasetId,
+        PartitionDataBuilder<K, V, C, D> partDataBuilder,
+        LearningEnvironment env) {
 
         PartitionDataStorage dataStorage = (PartitionDataStorage)ignite
             .cluster()
             .nodeLocalMap()
             .computeIfAbsent(String.format(DATA_STORAGE_KEY_TEMPLATE, datasetId), key -> new PartitionDataStorage());
 
+        final int part = env.partition();
+
         return dataStorage.computeDataIfAbsent(part, () -> {
             IgniteCache<Integer, C> learningCtxCache = ignite.cache(datasetCacheName);
             C ctx = learningCtxCache.get(part);
@@ -177,25 +208,24 @@
             qry.setPartition(part);
             qry.setFilter(filter);
 
-            UpstreamTransformerChain<K, V> chainCopy = Utils.copy(transformersChain);
-            chainCopy.modifySeed(s -> s + part);
+            UpstreamTransformer<K, V> transformer = transformerBuilder.build(env);
+            UpstreamTransformer<K, V> transformerCp = Utils.copy(transformer);
 
-            long cnt = computeCount(upstreamCache, qry, chainCopy);
+            long cnt = computeCount(upstreamCache, qry, transformer);
 
             if (cnt > 0) {
                 try (QueryCursor<UpstreamEntry<K, V>> cursor = upstreamCache.query(qry,
                     e -> new UpstreamEntry<>(e.getKey(), e.getValue()))) {
 
                     Iterator<UpstreamEntry<K, V>> it = cursor.iterator();
-                    if (!chainCopy.isEmpty()) {
-                        Stream<UpstreamEntry<K, V>> transformedStream = chainCopy.transform(Utils.asStream(it, cnt));
-                        it = transformedStream.iterator();
-                    }
+                    Stream<UpstreamEntry<K, V>> transformedStream = transformerCp.transform(Utils.asStream(it, cnt));
+                    it = transformedStream.iterator();
+
 
                     Iterator<UpstreamEntry<K, V>> iter = new IteratorWithConcurrentModificationChecker<>(it, cnt,
                         "Cache expected to be not modified during dataset data building [partition=" + part + ']');
 
-                    return partDataBuilder.build(iter, cnt, ctx);
+                    return partDataBuilder.build(env, iter, cnt, ctx);
                 }
             }
 
@@ -214,27 +244,40 @@
     }
 
     /**
+     * Remove learning environment from local cache by Dataset ID.
+     *
+     * @param ignite Ingnite instance.
+     * @param datasetId Dataset ID.
+     */
+    public static void removeLearningEnv(Ignite ignite, UUID datasetId) {
+        ignite.cluster().nodeLocalMap().remove(String.format(ENVIRONMENT_STORAGE_KEY_TEMPLATE, datasetId));
+    }
+
+    /**
      * Initializes partition {@code context} by loading it from a partition {@code upstream}.
-     *  @param <K> Type of a key in {@code upstream} data.
-     * @param <V> Type of a value in {@code upstream} data.
-     * @param <C> Type of a partition {@code context}.
      * @param ignite Ignite instance.
      * @param upstreamCacheName Name of an {@code upstream} cache.
      * @param filter Filter for {@code upstream} data.
-     * @param transformersChain Upstream data {@link Stream} transformers chain.
+     * @param transformerBuilder Upstream transformer builder.
      * @param ctxBuilder Partition {@code context} builder.
+     * @param envBuilder Environment builder.
+     * @param <K> Type of a key in {@code upstream} data.
+     * @param <V> Type of a value in {@code upstream} data.
+     * @param <C> Type of a partition {@code context}.
      */
     public static <K, V, C extends Serializable> void initContext(
         Ignite ignite,
         String upstreamCacheName,
+        UpstreamTransformerBuilder<K, V> transformerBuilder,
         IgniteBiPredicate<K, V> filter,
-        UpstreamTransformerChain<K, V> transformersChain,
         String datasetCacheName,
         PartitionContextBuilder<K, V, C> ctxBuilder,
+        LearningEnvironmentBuilder envBuilder,
         int retries,
         int interval) {
         affinityCallWithRetries(ignite, Arrays.asList(datasetCacheName, upstreamCacheName), part -> {
             Ignite locIgnite = Ignition.localIgnite();
+            LearningEnvironment env = envBuilder.buildForWorker(part);
 
             IgniteCache<K, V> locUpstreamCache = locIgnite.cache(upstreamCacheName);
 
@@ -244,25 +287,24 @@
             qry.setFilter(filter);
 
             C ctx;
-            UpstreamTransformerChain<K, V> chainCopy = Utils.copy(transformersChain);
-            chainCopy.modifySeed(s -> s + part);
+            UpstreamTransformer<K, V> transformer = transformerBuilder.build(env);
+            UpstreamTransformer<K, V> transformerCp = Utils.copy(transformer);
 
-            long cnt = computeCount(locUpstreamCache, qry, transformersChain);
+            long cnt = computeCount(locUpstreamCache, qry, transformer);
 
             try (QueryCursor<UpstreamEntry<K, V>> cursor = locUpstreamCache.query(qry,
                 e -> new UpstreamEntry<>(e.getKey(), e.getValue()))) {
 
                 Iterator<UpstreamEntry<K, V>> it = cursor.iterator();
-                if (!chainCopy.isEmpty()) {
-                    Stream<UpstreamEntry<K, V>> transformedStream = chainCopy.transform(Utils.asStream(it, cnt));
-                    it = transformedStream.iterator();
-                }
+                Stream<UpstreamEntry<K, V>> transformedStream = transformerCp.transform(Utils.asStream(it, cnt));
+                it = transformedStream.iterator();
+
                 Iterator<UpstreamEntry<K, V>> iter = new IteratorWithConcurrentModificationChecker<>(
                     it,
                     cnt,
                     "Cache expected to be not modified during dataset data building [partition=" + part + ']');
 
-                ctx = ctxBuilder.build(iter, cnt);
+                ctx = ctxBuilder.build(env, iter, cnt);
             }
 
             IgniteCache<Integer, C> datasetCache = locIgnite.cache(datasetCacheName);
@@ -279,9 +321,10 @@
      * @param ignite Ignite instance.
      * @param upstreamCacheName Name of an {@code upstream} cache.
      * @param filter Filter for {@code upstream} data.
-     * @param transformersChain Transformers of upstream data.
+     * @param transformerBuilder Builder of transformer of upstream data.
      * @param datasetCacheName Name of a partition {@code context} cache.
      * @param ctxBuilder Partition {@code context} builder.
+     * @param envBuilder Environment builder.
      * @param retries Number of retries for the case when one of partitions not found on the node.
      * @param <K> Type of a key in {@code upstream} data.
      * @param <V> Type of a value in {@code upstream} data.
@@ -291,11 +334,12 @@
         Ignite ignite,
         String upstreamCacheName,
         IgniteBiPredicate<K, V> filter,
-        UpstreamTransformerChain<K, V> transformersChain,
+        UpstreamTransformerBuilder<K, V> transformerBuilder,
         String datasetCacheName,
         PartitionContextBuilder<K, V, C> ctxBuilder,
+        LearningEnvironmentBuilder envBuilder,
         int retries) {
-        initContext(ignite, upstreamCacheName, filter, transformersChain, datasetCacheName, ctxBuilder, retries, 0);
+        initContext(ignite, upstreamCacheName, transformerBuilder, filter, datasetCacheName, ctxBuilder, envBuilder, retries, 0);
     }
 
     /**
@@ -328,25 +372,21 @@
     /**
      * Computes number of entries selected from the cache by the query.
      *
-     * @param <K> Type of a key in {@code upstream} data.
-     * @param <V> Type of a value in {@code upstream} data.
      * @param cache Ignite cache with upstream data.
      * @param qry Cache query.
-     * @param transformersChain Transformers of stream of upstream data.
+     * @param transformer Upstream transformer.
+     * @param <K> Type of a key in {@code upstream} data.
+     * @param <V> Type of a value in {@code upstream} data.
      * @return Number of entries supplied by the iterator.
      */
     private static <K, V> long computeCount(
         IgniteCache<K, V> cache,
         ScanQuery<K, V> qry,
-        UpstreamTransformerChain<K, V> transformersChain) {
+        UpstreamTransformer<K, V> transformer) {
         try (QueryCursor<UpstreamEntry<K, V>> cursor = cache.query(qry,
             e -> new UpstreamEntry<>(e.getKey(), e.getValue()))) {
 
-            // 'If' statement below is just for optimization, to avoid unnecessary iterator -> stream -> iterator
-            // operations.
-            return transformersChain.isEmpty() ?
-                computeCount(cursor.iterator()) :
-                computeCount(transformersChain.transform(Utils.asStream(cursor.iterator())).iterator());
+            return computeCount(transformer.transform(Utils.asStream(cursor.iterator())).iterator());
         }
     }
 
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/dataset/impl/local/LocalDataset.java b/modules/ml/src/main/java/org/apache/ignite/ml/dataset/impl/local/LocalDataset.java
index 975beda..8c67c02 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/dataset/impl/local/LocalDataset.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/dataset/impl/local/LocalDataset.java
@@ -20,6 +20,7 @@
 import java.io.Serializable;
 import java.util.List;
 import org.apache.ignite.ml.dataset.Dataset;
+import org.apache.ignite.ml.environment.LearningEnvironment;
 import org.apache.ignite.ml.math.functions.IgniteBiFunction;
 import org.apache.ignite.ml.math.functions.IgniteBinaryOperator;
 import org.apache.ignite.ml.math.functions.IgniteTriFunction;
@@ -32,6 +33,9 @@
  * @param <D> Type of a partition {@code data}.
  */
 public class LocalDataset<C extends Serializable, D extends AutoCloseable> implements Dataset<C, D> {
+    /** Partition {@code data} storage. */
+    private final List<LearningEnvironment> envs;
+
     /** Partition {@code context} storage. */
     private final List<C> ctx;
 
@@ -42,38 +46,42 @@
      * Constructs a new instance of dataset based on local data structures such as {@code Map} and {@code List} and
      * doesn't requires Ignite environment.
      *
+     * @param envs List of {@link LearningEnvironment}.
      * @param ctx Partition {@code context} storage.
      * @param data Partition {@code data} storage.
      */
-    LocalDataset(List<C> ctx, List<D> data) {
+    LocalDataset(List<LearningEnvironment> envs, List<C> ctx, List<D> data) {
+        this.envs = envs;
         this.ctx = ctx;
         this.data = data;
     }
 
     /** {@inheritDoc} */
-    @Override public <R> R computeWithCtx(IgniteTriFunction<C, D, Integer, R> map, IgniteBinaryOperator<R> reduce,
+    @Override public <R> R computeWithCtx(IgniteTriFunction<C, D, LearningEnvironment, R> map, IgniteBinaryOperator<R> reduce,
         R identity) {
         R res = identity;
 
         for (int part = 0; part < ctx.size(); part++) {
             D partData = data.get(part);
+            LearningEnvironment env = envs.get(part);
 
             if (partData != null)
-                res = reduce.apply(res, map.apply(ctx.get(part), partData, part));
+                res = reduce.apply(res, map.apply(ctx.get(part), partData, env));
         }
 
         return res;
     }
 
     /** {@inheritDoc} */
-    @Override public <R> R compute(IgniteBiFunction<D, Integer, R> map, IgniteBinaryOperator<R> reduce, R identity) {
+    @Override public <R> R compute(IgniteBiFunction<D, LearningEnvironment, R> map, IgniteBinaryOperator<R> reduce, R identity) {
         R res = identity;
 
         for (int part = 0; part < data.size(); part++) {
             D partData = data.get(part);
+            LearningEnvironment env = envs.get(part);
 
             if (partData != null)
-                res = reduce.apply(res, map.apply(partData, part));
+                res = reduce.apply(res, map.apply(partData, env));
         }
 
         return res;
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/dataset/impl/local/LocalDatasetBuilder.java b/modules/ml/src/main/java/org/apache/ignite/ml/dataset/impl/local/LocalDatasetBuilder.java
index 2514f3e..b8cd8dc 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/dataset/impl/local/LocalDatasetBuilder.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/dataset/impl/local/LocalDatasetBuilder.java
@@ -22,12 +22,17 @@
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
 import org.apache.ignite.lang.IgniteBiPredicate;
 import org.apache.ignite.ml.dataset.DatasetBuilder;
 import org.apache.ignite.ml.dataset.PartitionContextBuilder;
 import org.apache.ignite.ml.dataset.PartitionDataBuilder;
 import org.apache.ignite.ml.dataset.UpstreamEntry;
-import org.apache.ignite.ml.dataset.UpstreamTransformerChain;
+import org.apache.ignite.ml.dataset.UpstreamTransformer;
+import org.apache.ignite.ml.dataset.UpstreamTransformerBuilder;
+import org.apache.ignite.ml.environment.LearningEnvironment;
+import org.apache.ignite.ml.environment.LearningEnvironmentBuilder;
 import org.apache.ignite.ml.math.functions.IgniteFunction;
 import org.apache.ignite.ml.util.Utils;
 
@@ -49,7 +54,7 @@
     private final IgniteBiPredicate<K, V> filter;
 
     /** Upstream transformers. */
-    private final UpstreamTransformerChain<K, V> upstreamTransformers;
+    private final UpstreamTransformerBuilder<K, V> upstreamTransformerBuilder;
 
     /**
      * Constructs a new instance of local dataset builder that makes {@link LocalDataset} with default predicate that
@@ -68,16 +73,34 @@
      * @param upstreamMap {@code Map} with upstream data.
      * @param filter Filter for {@code upstream} data.
      * @param partitions Number of partitions.
+     * @param upstreamTransformerBuilder Builder of upstream transformer.
      */
-    public LocalDatasetBuilder(Map<K, V> upstreamMap, IgniteBiPredicate<K, V> filter, int partitions) {
+    public LocalDatasetBuilder(Map<K, V> upstreamMap,
+        IgniteBiPredicate<K, V> filter,
+        int partitions,
+        UpstreamTransformerBuilder<K, V> upstreamTransformerBuilder) {
         this.upstreamMap = upstreamMap;
         this.filter = filter;
         this.partitions = partitions;
-        this.upstreamTransformers = UpstreamTransformerChain.empty();
+        this.upstreamTransformerBuilder = upstreamTransformerBuilder;
+    }
+
+    /**
+     * Constructs a new instance of local dataset builder that makes {@link LocalDataset}.
+     *
+     * @param upstreamMap {@code Map} with upstream data.
+     * @param filter Filter for {@code upstream} data.
+     * @param partitions Number of partitions.
+     */
+    public LocalDatasetBuilder(Map<K, V> upstreamMap,
+        IgniteBiPredicate<K, V> filter,
+        int partitions) {
+        this(upstreamMap, filter, partitions, UpstreamTransformerBuilder.identity());
     }
 
     /** {@inheritDoc} */
     @Override public <C extends Serializable, D extends AutoCloseable> LocalDataset<C, D> build(
+        LearningEnvironmentBuilder envBuilder,
         PartitionContextBuilder<K, V, C> partCtxBuilder, PartitionDataBuilder<K, V, C, D> partDataBuilder) {
         List<C> ctxList = new ArrayList<>();
         List<D> dataList = new ArrayList<>();
@@ -99,36 +122,29 @@
 
         int ptr = 0;
 
+        List<LearningEnvironment> envs = IntStream.range(0, partitions).boxed().map(envBuilder::buildForWorker)
+            .collect(Collectors.toList());
+
         for (int part = 0; part < partitions; part++) {
-            int cnt = part == partitions - 1 ? entriesList.size() - ptr : Math.min(partSize, entriesList.size() - ptr);
+            int cntBeforeTransform =
+                part == partitions - 1 ? entriesList.size() - ptr : Math.min(partSize, entriesList.size() - ptr);
+            LearningEnvironment env = envs.get(part);
+            UpstreamTransformer<K, V> transformer1 = upstreamTransformerBuilder.build(env);
+            UpstreamTransformer<K, V> transformer2 = Utils.copy(transformer1);
+            UpstreamTransformer<K, V> transformer3 = Utils.copy(transformer1);
 
-            int p = part;
-            upstreamTransformers.modifySeed(s -> s + p);
+            int cnt = (int)transformer1.transform(Utils.asStream(new IteratorWindow<>(thirdKeysIter, k -> k, cntBeforeTransform))).count();
 
-            if (!upstreamTransformers.isEmpty()) {
-                cnt = (int)upstreamTransformers.transform(
-                    Utils.asStream(new IteratorWindow<>(thirdKeysIter, k -> k, cnt))).count();
-            }
+            Iterator<UpstreamEntry<K, V>> iter =
+                transformer2.transform(Utils.asStream(new IteratorWindow<>(firstKeysIter, k -> k, cntBeforeTransform))).iterator();
 
-            Iterator<UpstreamEntry<K, V>> iter;
-            if (upstreamTransformers.isEmpty())
-                iter = new IteratorWindow<>(firstKeysIter, k -> k, cnt);
+            C ctx = cntBeforeTransform > 0 ? partCtxBuilder.build(env, iter, cnt) : null;
 
-            else {
-                iter = upstreamTransformers.transform(
-                    Utils.asStream(new IteratorWindow<>(firstKeysIter, k -> k, cnt))).iterator();
-            }
-            C ctx = cnt > 0 ? partCtxBuilder.build(iter, cnt) : null;
+            Iterator<UpstreamEntry<K, V>> iter1 = transformer3.transform(
+                    Utils.asStream(new IteratorWindow<>(secondKeysIter, k -> k, cntBeforeTransform))).iterator();
 
-            Iterator<UpstreamEntry<K, V>> iter1;
-            if (upstreamTransformers.isEmpty()) {
-                iter1 = upstreamTransformers.transform(
-                    Utils.asStream(new IteratorWindow<>(secondKeysIter, k -> k, cnt))).iterator();
-            }
-            else
-                iter1 = new IteratorWindow<>(secondKeysIter, k -> k, cnt);
-
-            D data = cnt > 0 ? partDataBuilder.build(
+            D data = cntBeforeTransform > 0 ? partDataBuilder.build(
+                env,
                 iter1,
                 cnt,
                 ctx
@@ -137,20 +153,18 @@
             ctxList.add(ctx);
             dataList.add(data);
 
-            ptr += cnt;
+            ptr += cntBeforeTransform;
         }
 
-        return new LocalDataset<>(ctxList, dataList);
+        return new LocalDataset<>(envs, ctxList, dataList);
     }
 
     /** {@inheritDoc} */
-    @Override public UpstreamTransformerChain<K, V> upstreamTransformersChain() {
-        return upstreamTransformers;
+    @Override public DatasetBuilder<K, V> withUpstreamTransformer(UpstreamTransformerBuilder<K, V> builder) {
+        return new LocalDatasetBuilder<>(upstreamMap, filter, partitions, upstreamTransformerBuilder.andThen(builder));
     }
 
-    /**
-     * {@inheritDoc}
-     */
+    /** {@inheritDoc} */
     @Override public DatasetBuilder<K, V> withFilter(IgniteBiPredicate<K, V> filterToAdd) {
         return new LocalDatasetBuilder<>(upstreamMap,
             (e1, e2) -> filter.apply(e1, e2) && filterToAdd.apply(e1, e2), partitions);
@@ -164,24 +178,16 @@
      * @param <T> Target type of entries.
      */
     private static class IteratorWindow<K, T> implements Iterator<T> {
-        /**
-         * Delegate iterator.
-         */
+        /** Delegate iterator. */
         private final Iterator<K> delegate;
 
-        /**
-         * Transformer that transforms entries from one type to another.
-         */
+        /** Transformer that transforms entries from one type to another. */
         private final IgniteFunction<K, T> map;
 
-        /**
-         * Count of entries to produce.
-         */
+        /** Count of entries to produce. */
         private final int cnt;
 
-        /**
-         * Number of already produced entries.
-         */
+        /** Number of already produced entries. */
         private int ptr;
 
         /**
@@ -197,16 +203,12 @@
             this.cnt = cnt;
         }
 
-        /**
-         * {@inheritDoc}
-         */
+        /** {@inheritDoc} */
         @Override public boolean hasNext() {
             return delegate.hasNext() && ptr < cnt;
         }
 
-        /**
-         * {@inheritDoc}
-         */
+        /** {@inheritDoc} */
         @Override public T next() {
             ++ptr;
 
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/dataset/primitive/DatasetWrapper.java b/modules/ml/src/main/java/org/apache/ignite/ml/dataset/primitive/DatasetWrapper.java
index 578a149..270c7eb 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/dataset/primitive/DatasetWrapper.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/dataset/primitive/DatasetWrapper.java
@@ -19,6 +19,7 @@
 
 import java.io.Serializable;
 import org.apache.ignite.ml.dataset.Dataset;
+import org.apache.ignite.ml.environment.LearningEnvironment;
 import org.apache.ignite.ml.math.functions.IgniteBiFunction;
 import org.apache.ignite.ml.math.functions.IgniteBinaryOperator;
 import org.apache.ignite.ml.math.functions.IgniteTriFunction;
@@ -46,13 +47,13 @@
     }
 
     /** {@inheritDoc} */
-    @Override public <R> R computeWithCtx(IgniteTriFunction<C, D, Integer, R> map, IgniteBinaryOperator<R> reduce,
+    @Override public <R> R computeWithCtx(IgniteTriFunction<C, D, LearningEnvironment, R> map, IgniteBinaryOperator<R> reduce,
         R identity) {
         return delegate.computeWithCtx(map, reduce, identity);
     }
 
     /** {@inheritDoc} */
-    @Override public <R> R compute(IgniteBiFunction<D, Integer, R> map, IgniteBinaryOperator<R> reduce, R identity) {
+    @Override public <R> R compute(IgniteBiFunction<D, LearningEnvironment, R> map, IgniteBinaryOperator<R> reduce, R identity) {
         return delegate.compute(map, reduce, identity);
     }
 
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/dataset/primitive/FeatureMatrixWithLabelsOnHeapDataBuilder.java b/modules/ml/src/main/java/org/apache/ignite/ml/dataset/primitive/FeatureMatrixWithLabelsOnHeapDataBuilder.java
index be1724c..5273fa6 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/dataset/primitive/FeatureMatrixWithLabelsOnHeapDataBuilder.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/dataset/primitive/FeatureMatrixWithLabelsOnHeapDataBuilder.java
@@ -21,6 +21,7 @@
 import java.util.Iterator;
 import org.apache.ignite.ml.dataset.PartitionDataBuilder;
 import org.apache.ignite.ml.dataset.UpstreamEntry;
+import org.apache.ignite.ml.environment.LearningEnvironment;
 import org.apache.ignite.ml.math.functions.IgniteBiFunction;
 import org.apache.ignite.ml.math.primitives.vector.Vector;
 import org.apache.ignite.ml.tree.data.DecisionTreeData;
@@ -56,7 +57,11 @@
     }
 
     /** {@inheritDoc} */
-    @Override public FeatureMatrixWithLabelsOnHeapData build(Iterator<UpstreamEntry<K, V>> upstreamData, long upstreamDataSize, C ctx) {
+    @Override public FeatureMatrixWithLabelsOnHeapData build(
+        LearningEnvironment env,
+        Iterator<UpstreamEntry<K, V>> upstreamData,
+        long upstreamDataSize,
+        C ctx) {
         double[][] features = new double[Math.toIntExact(upstreamDataSize)][];
         double[] labels = new double[Math.toIntExact(upstreamDataSize)];
 
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/dataset/primitive/builder/context/EmptyContextBuilder.java b/modules/ml/src/main/java/org/apache/ignite/ml/dataset/primitive/builder/context/EmptyContextBuilder.java
index 03b69b5..9fd77b5 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/dataset/primitive/builder/context/EmptyContextBuilder.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/dataset/primitive/builder/context/EmptyContextBuilder.java
@@ -21,6 +21,7 @@
 import org.apache.ignite.ml.dataset.PartitionContextBuilder;
 import org.apache.ignite.ml.dataset.UpstreamEntry;
 import org.apache.ignite.ml.dataset.primitive.context.EmptyContext;
+import org.apache.ignite.ml.environment.LearningEnvironment;
 
 /**
  * A partition {@code context} builder that makes {@link EmptyContext}.
@@ -33,7 +34,7 @@
     private static final long serialVersionUID = 6620781747993467186L;
 
     /** {@inheritDoc} */
-    @Override public EmptyContext build(Iterator<UpstreamEntry<K, V>> upstreamData, long upstreamDataSize) {
+    @Override public EmptyContext build(LearningEnvironment env, Iterator<UpstreamEntry<K, V>> upstreamData, long upstreamDataSize) {
         return new EmptyContext();
     }
 }
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/dataset/primitive/builder/data/SimpleDatasetDataBuilder.java b/modules/ml/src/main/java/org/apache/ignite/ml/dataset/primitive/builder/data/SimpleDatasetDataBuilder.java
index cf5bc7a..b14d8a2 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/dataset/primitive/builder/data/SimpleDatasetDataBuilder.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/dataset/primitive/builder/data/SimpleDatasetDataBuilder.java
@@ -22,6 +22,7 @@
 import org.apache.ignite.ml.dataset.PartitionDataBuilder;
 import org.apache.ignite.ml.dataset.UpstreamEntry;
 import org.apache.ignite.ml.dataset.primitive.data.SimpleDatasetData;
+import org.apache.ignite.ml.environment.LearningEnvironment;
 import org.apache.ignite.ml.math.functions.IgniteBiFunction;
 import org.apache.ignite.ml.math.primitives.vector.Vector;
 
@@ -50,7 +51,9 @@
     }
 
     /** {@inheritDoc} */
-    @Override public SimpleDatasetData build(Iterator<UpstreamEntry<K, V>> upstreamData, long upstreamDataSize, C ctx) {
+    @Override public SimpleDatasetData build(
+        LearningEnvironment env,
+        Iterator<UpstreamEntry<K, V>> upstreamData, long upstreamDataSize, C ctx) {
         // Prepares the matrix of features in flat column-major format.
         int cols = -1;
         double[] features = null;
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/dataset/primitive/builder/data/SimpleLabeledDatasetDataBuilder.java b/modules/ml/src/main/java/org/apache/ignite/ml/dataset/primitive/builder/data/SimpleLabeledDatasetDataBuilder.java
index 6286255..48166ee 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/dataset/primitive/builder/data/SimpleLabeledDatasetDataBuilder.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/dataset/primitive/builder/data/SimpleLabeledDatasetDataBuilder.java
@@ -22,6 +22,7 @@
 import org.apache.ignite.ml.dataset.PartitionDataBuilder;
 import org.apache.ignite.ml.dataset.UpstreamEntry;
 import org.apache.ignite.ml.dataset.primitive.data.SimpleLabeledDatasetData;
+import org.apache.ignite.ml.environment.LearningEnvironment;
 import org.apache.ignite.ml.math.functions.IgniteBiFunction;
 import org.apache.ignite.ml.math.primitives.vector.Vector;
 
@@ -56,7 +57,9 @@
     }
 
     /** {@inheritDoc} */
-    @Override public SimpleLabeledDatasetData build(Iterator<UpstreamEntry<K, V>> upstreamData,
+    @Override public SimpleLabeledDatasetData build(
+        LearningEnvironment env,
+        Iterator<UpstreamEntry<K, V>> upstreamData,
         long upstreamDataSize, C ctx) {
         // Prepares the matrix of features in flat column-major format.
         int featureCols = -1;
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/environment/DefaultLearningEnvironmentBuilder.java b/modules/ml/src/main/java/org/apache/ignite/ml/environment/DefaultLearningEnvironmentBuilder.java
new file mode 100644
index 0000000..4aef8f2
--- /dev/null
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/environment/DefaultLearningEnvironmentBuilder.java
@@ -0,0 +1,178 @@
+/*
+ * 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.ml.environment;
+
+import java.util.Random;
+import org.apache.ignite.ml.environment.logging.MLLogger;
+import org.apache.ignite.ml.environment.logging.NoOpLogger;
+import org.apache.ignite.ml.environment.parallelism.DefaultParallelismStrategy;
+import org.apache.ignite.ml.environment.parallelism.NoParallelismStrategy;
+import org.apache.ignite.ml.environment.parallelism.ParallelismStrategy;
+import org.apache.ignite.ml.math.functions.IgniteFunction;
+
+import static org.apache.ignite.ml.math.functions.IgniteFunction.constant;
+
+/**
+ * Builder for {@link LearningEnvironment}.
+ */
+public class DefaultLearningEnvironmentBuilder implements LearningEnvironmentBuilder {
+    /** Serial version id. */
+    private static final long serialVersionUID = 8502532880517447662L;
+
+    /** Dependency (partition -> Parallelism strategy). */
+    private IgniteFunction<Integer, ParallelismStrategy> parallelismStgy;
+
+    /** Dependency (partition -> Logging factory). */
+    private IgniteFunction<Integer, MLLogger.Factory> loggingFactory;
+
+    /** Dependency (partition -> Random number generator seed). */
+    private IgniteFunction<Integer, Long> seed;
+
+    /** Dependency (partition -> Random numbers generator supplier). */
+    private IgniteFunction<Integer, Random> rngSupplier;
+
+    /**
+     * Creates an instance of DefaultLearningEnvironmentBuilder.
+     */
+    DefaultLearningEnvironmentBuilder() {
+        parallelismStgy = constant(NoParallelismStrategy.INSTANCE);
+        loggingFactory = constant(NoOpLogger.factory());
+        seed = constant(new Random().nextLong());
+        rngSupplier = constant(new Random());
+    }
+
+    /** {@inheritDoc} */
+    @Override public LearningEnvironmentBuilder withRNGSeedDependency(IgniteFunction<Integer, Long> seed) {
+        this.seed = seed;
+
+        return this;
+    }
+
+    /** {@inheritDoc} */
+    @Override public LearningEnvironmentBuilder withRandomDependency(IgniteFunction<Integer, Random> rngSupplier) {
+        this.rngSupplier = rngSupplier;
+
+        return this;
+    }
+
+    /** {@inheritDoc} */
+    @Override public DefaultLearningEnvironmentBuilder withParallelismStrategyDependency(
+        IgniteFunction<Integer, ParallelismStrategy> stgy) {
+        this.parallelismStgy = stgy;
+
+        return this;
+    }
+
+    /** {@inheritDoc} */
+    @Override public DefaultLearningEnvironmentBuilder withParallelismStrategyTypeDependency(
+        IgniteFunction<Integer, ParallelismStrategy.Type> stgyType) {
+        this.parallelismStgy = part -> strategyByType(stgyType.apply(part));
+
+        return this;
+    }
+
+    /**
+     * Get parallelism strategy by {@link ParallelismStrategy.Type}.
+     *
+     * @param stgyType Strategy type.
+     * @return {@link ParallelismStrategy}.
+     */
+    private static ParallelismStrategy strategyByType(ParallelismStrategy.Type stgyType) {
+        switch (stgyType) {
+            case NO_PARALLELISM:
+                return NoParallelismStrategy.INSTANCE;
+            case ON_DEFAULT_POOL:
+                return new DefaultParallelismStrategy();
+        }
+        throw new IllegalStateException("Wrong type");
+    }
+
+
+    /** {@inheritDoc} */
+    @Override public DefaultLearningEnvironmentBuilder withLoggingFactoryDependency(
+        IgniteFunction<Integer, MLLogger.Factory> loggingFactory) {
+        this.loggingFactory = loggingFactory;
+        return this;
+    }
+
+    /** {@inheritDoc} */
+    @Override public LearningEnvironment buildForWorker(int part) {
+        Random random = rngSupplier.apply(part);
+        random.setSeed(seed.apply(part));
+        return new LearningEnvironmentImpl(part, random, parallelismStgy.apply(part), loggingFactory.apply(part));
+    }
+
+    /** Default LearningEnvironment implementation. */
+    private class LearningEnvironmentImpl implements LearningEnvironment {
+        /** Parallelism strategy. */
+        private final ParallelismStrategy parallelismStgy;
+
+        /** Logging factory. */
+        private final MLLogger.Factory loggingFactory;
+
+        /** Partition. */
+        private final int part;
+
+        /** Random numbers generator. */
+        private final Random randomNumGen;
+
+        /**
+         * Creates an instance of LearningEnvironmentImpl.
+         *
+         * @param part Partition.
+         * @param rng Random numbers generator.
+         * @param parallelismStgy Parallelism strategy.
+         * @param loggingFactory Logging factory.
+         */
+        private LearningEnvironmentImpl(
+            int part,
+            Random rng,
+            ParallelismStrategy parallelismStgy,
+            MLLogger.Factory loggingFactory) {
+            this.part = part;
+            this.parallelismStgy = parallelismStgy;
+            this.loggingFactory = loggingFactory;
+            randomNumGen = rng;
+        }
+
+        /** {@inheritDoc} */
+        @Override public ParallelismStrategy parallelismStrategy() {
+            return parallelismStgy;
+        }
+
+        /** {@inheritDoc} */
+        @Override public MLLogger logger() {
+            return loggingFactory.create(getClass());
+        }
+
+        /** {@inheritDoc} */
+        @Override public Random randomNumbersGenerator() {
+            return randomNumGen;
+        }
+
+        /** {@inheritDoc} */
+        @Override public <T> MLLogger logger(Class<T> clazz) {
+            return loggingFactory.create(clazz);
+        }
+
+        /** {@inheritDoc} */
+        @Override public int partition() {
+            return part;
+        }
+    }
+}
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/environment/LearningEnvironment.java b/modules/ml/src/main/java/org/apache/ignite/ml/environment/LearningEnvironment.java
index f5fb693..f1e4f32 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/environment/LearningEnvironment.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/environment/LearningEnvironment.java
@@ -17,6 +17,8 @@
 
 package org.apache.ignite.ml.environment;
 
+import java.util.Random;
+import org.apache.ignite.ml.dataset.Dataset;
 import org.apache.ignite.ml.environment.logging.MLLogger;
 import org.apache.ignite.ml.environment.parallelism.ParallelismStrategy;
 
@@ -26,7 +28,7 @@
  */
 public interface LearningEnvironment {
     /** Default environment */
-    public static final LearningEnvironment DEFAULT = builder().build();
+    public static final LearningEnvironment DEFAULT_TRAINER_ENV = LearningEnvironmentBuilder.defaultBuilder().buildForTrainer();
 
     /**
      * Returns Parallelism Strategy instance.
@@ -39,6 +41,13 @@
     public MLLogger logger();
 
     /**
+     * Random numbers generator.
+     *
+     * @return Random numbers generator.
+     */
+    public Random randomNumbersGenerator();
+
+    /**
      * Returns an instance of logger for specific class.
      *
      * @param forCls Logging class context.
@@ -46,9 +55,9 @@
     public <T> MLLogger logger(Class<T> forCls);
 
     /**
-     * Creates an instance of LearningEnvironmentBuilder.
+     * Gets current partition. If this is called not in one of compute tasks of {@link Dataset}, will return -1.
+     *
+     * @return Partition.
      */
-    public static LearningEnvironmentBuilder builder() {
-        return new LearningEnvironmentBuilder();
-    }
+    public int partition();
 }
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/environment/LearningEnvironmentBuilder.java b/modules/ml/src/main/java/org/apache/ignite/ml/environment/LearningEnvironmentBuilder.java
index 98f584f..8fcc6b2 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/environment/LearningEnvironmentBuilder.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/environment/LearningEnvironmentBuilder.java
@@ -17,109 +17,134 @@
 
 package org.apache.ignite.ml.environment;
 
+import java.io.Serializable;
+import java.util.Random;
 import org.apache.ignite.ml.environment.logging.MLLogger;
-import org.apache.ignite.ml.environment.logging.NoOpLogger;
-import org.apache.ignite.ml.environment.parallelism.DefaultParallelismStrategy;
-import org.apache.ignite.ml.environment.parallelism.NoParallelismStrategy;
 import org.apache.ignite.ml.environment.parallelism.ParallelismStrategy;
+import org.apache.ignite.ml.math.functions.IgniteFunction;
+
+import static org.apache.ignite.ml.math.functions.IgniteFunction.constant;
 
 /**
- * Builder for LearningEnvironment.
+ * Builder of learning environment.
  */
-public class LearningEnvironmentBuilder {
-    /** Parallelism strategy. */
-    private ParallelismStrategy parallelismStgy;
-    /** Logging factory. */
-    private MLLogger.Factory loggingFactory;
-
+public interface LearningEnvironmentBuilder extends Serializable {
     /**
-     * Creates an instance of LearningEnvironmentBuilder.
-     */
-    public LearningEnvironmentBuilder() {
-        parallelismStgy = NoParallelismStrategy.INSTANCE;
-        loggingFactory = NoOpLogger.factory();
-    }
-
-    /**
-     * Specifies Parallelism Strategy for LearningEnvironment.
+     * Builds {@link LearningEnvironment} for worker on given partition.
      *
-     * @param stgy Parallelism Strategy.
+     * @param part Partition.
+     * @return {@link LearningEnvironment} for worker on given partition.
      */
-    public <T> LearningEnvironmentBuilder withParallelismStrategy(ParallelismStrategy stgy) {
-        this.parallelismStgy = stgy;
+    public LearningEnvironment buildForWorker(int part);
 
-        return this;
+    /**
+     * Builds learning environment for trainer.
+     *
+     * @return Learning environment for trainer.
+     */
+    public default LearningEnvironment buildForTrainer() {
+        return buildForWorker(-1);
     }
 
     /**
-     * Specifies Parallelism Strategy for LearningEnvironment.
+     * Specifies dependency (partition -> Parallelism Strategy Type for LearningEnvironment).
+     *
+     * @param stgyType Function describing dependency (partition -> Parallelism Strategy Type).
+     * @return This object.
+     */
+    public LearningEnvironmentBuilder withParallelismStrategyTypeDependency(
+        IgniteFunction<Integer, ParallelismStrategy.Type> stgyType);
+
+    /**
+     * Specifies Parallelism Strategy Type for LearningEnvironment. Same strategy type will be used for all partitions.
      *
      * @param stgyType Parallelism Strategy Type.
+     * @return This object.
      */
-    public LearningEnvironmentBuilder withParallelismStrategy(ParallelismStrategy.Type stgyType) {
-        switch (stgyType) {
-            case NO_PARALLELISM:
-                this.parallelismStgy = NoParallelismStrategy.INSTANCE;
-                break;
-            case ON_DEFAULT_POOL:
-                this.parallelismStgy = new DefaultParallelismStrategy();
-                break;
-        }
-        return this;
+    public default LearningEnvironmentBuilder withParallelismStrategyType(ParallelismStrategy.Type stgyType) {
+        return withParallelismStrategyTypeDependency(constant(stgyType));
     }
 
-
     /**
-     * Specifies Logging factory for LearningEnvironment.
+     * Specifies dependency (partition -> Parallelism Strategy for LearningEnvironment).
      *
-     * @param loggingFactory Logging Factory.
+     * @param stgy Function describing dependency (partition -> Parallelism Strategy).
+     * @return This object.
      */
-    public LearningEnvironmentBuilder withLoggingFactory(MLLogger.Factory loggingFactory) {
-        this.loggingFactory = loggingFactory;
-        return this;
+    public LearningEnvironmentBuilder withParallelismStrategyDependency(IgniteFunction<Integer, ParallelismStrategy> stgy);
+
+    /**
+     * Specifies Parallelism Strategy for LearningEnvironment. Same strategy type will be used for all partitions.
+     *
+     * @param stgy Parallelism Strategy.
+     * @param <T> Parallelism strategy type.
+     * @return This object.
+     */
+    public default <T extends ParallelismStrategy & Serializable> LearningEnvironmentBuilder withParallelismStrategy(T stgy) {
+        return withParallelismStrategyDependency(constant(stgy));
+    }
+
+
+    /**
+     * Specify dependency (partition -> logging factory).
+     *
+     * @param loggingFactory Function describing (partition -> logging factory).
+     * @return This object.
+     */
+    public LearningEnvironmentBuilder withLoggingFactoryDependency(IgniteFunction<Integer, MLLogger.Factory> loggingFactory);
+
+    /**
+     * Specify logging factory.
+     *
+     * @param loggingFactory Logging factory.
+     * @return This object.
+     */
+    public default <T extends MLLogger.Factory & Serializable> LearningEnvironmentBuilder withLoggingFactory(T loggingFactory) {
+        return withLoggingFactoryDependency(constant(loggingFactory));
     }
 
     /**
-     * Create an instance of LearningEnvironment.
+     * Specify dependency (partition -> seed for random number generator). Same seed will be used for all partitions.
+     *
+     * @param seed Function describing dependency (partition -> seed for random number generator).
+     * @return This object.
      */
-    public LearningEnvironment build() {
-        return new LearningEnvironmentImpl(parallelismStgy, loggingFactory);
+    public LearningEnvironmentBuilder withRNGSeedDependency(IgniteFunction<Integer, Long> seed);
+
+    /**
+     * Specify seed for random number generator.
+     *
+     * @param seed Seed for random number generator.
+     * @return This object.
+     */
+    public default LearningEnvironmentBuilder withRNGSeed(long seed) {
+        return withRNGSeedDependency(constant(seed));
     }
 
     /**
-     * Default LearningEnvironment implementation.
+     * Specify dependency (partition -> random numbers generator).
+     *
+     * @param rngSupplier Function describing dependency (partition -> random numbers generator).
+     * @return This object.
      */
-    private class LearningEnvironmentImpl implements LearningEnvironment {
-        /** Parallelism strategy. */
-        private final ParallelismStrategy parallelismStgy;
-        /** Logging factory. */
-        private final MLLogger.Factory loggingFactory;
+    public LearningEnvironmentBuilder withRandomDependency(IgniteFunction<Integer, Random> rngSupplier);
 
-        /**
-         * Creates an instance of LearningEnvironmentImpl.
-         *
-         * @param parallelismStgy Parallelism strategy.
-         * @param loggingFactory Logging factory.
-         */
-        private LearningEnvironmentImpl(ParallelismStrategy parallelismStgy,
-            MLLogger.Factory loggingFactory) {
-            this.parallelismStgy = parallelismStgy;
-            this.loggingFactory = loggingFactory;
-        }
+    /**
+     * Specify random numbers generator for learning environment. Same random will be used for all partitions.
+     *
+     * @param random Rrandom numbers generator for learning environment.
+     * @return This object.
+     */
+    public default LearningEnvironmentBuilder withRandom(Random random) {
+        return withRandomDependency(constant(random));
+    }
 
-        /** {@inheritDoc} */
-        @Override public ParallelismStrategy parallelismStrategy() {
-            return parallelismStgy;
-        }
-
-        /** {@inheritDoc} */
-        @Override public MLLogger logger() {
-            return loggingFactory.create(getClass());
-        }
-
-        /** {@inheritDoc} */
-        @Override public <T> MLLogger logger(Class<T> clazz) {
-            return loggingFactory.create(clazz);
-        }
+    /**
+     * Get default {@link LearningEnvironmentBuilder}.
+     *
+     * @return Default {@link LearningEnvironmentBuilder}.
+     */
+    public static LearningEnvironmentBuilder defaultBuilder() {
+        return new DefaultLearningEnvironmentBuilder();
     }
 }
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/environment/logging/ConsoleLogger.java b/modules/ml/src/main/java/org/apache/ignite/ml/environment/logging/ConsoleLogger.java
index e064fc3..c124e06 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/environment/logging/ConsoleLogger.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/environment/logging/ConsoleLogger.java
@@ -82,6 +82,9 @@
      * ConsoleLogger factory.
      */
     private static class Factory implements MLLogger.Factory {
+        /** Serial version uuid. */
+        private static final long serialVersionUID = 5864605548782107893L;
+
         /** Max Verbose level. */
         private final VerboseLevel maxVerboseLevel;
 
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/environment/parallelism/ParallelismStrategy.java b/modules/ml/src/main/java/org/apache/ignite/ml/environment/parallelism/ParallelismStrategy.java
index e7228f8..329ce89 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/environment/parallelism/ParallelismStrategy.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/environment/parallelism/ParallelismStrategy.java
@@ -26,7 +26,6 @@
  * bagging, learning submodels for One-vs-All model, Cross-Validation etc.
  */
 public interface ParallelismStrategy {
-
     /**
      * The type of parallelism.
      */
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/inference/ModelDescriptor.java b/modules/ml/src/main/java/org/apache/ignite/ml/inference/ModelDescriptor.java
index e156063..49a2593 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/inference/ModelDescriptor.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/inference/ModelDescriptor.java
@@ -83,4 +83,12 @@
     public InfModelParser<byte[], byte[]> getParser() {
         return parser;
     }
+
+    /** {@inheritDoc} */
+    @Override public String toString() {
+        return "ModelDescriptor{" +
+            "name='" + name + '\'' +
+            ", desc='" + desc + '\'' +
+            '}';
+    }
 }
\ No newline at end of file
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/inference/reader/FileSystemInfModelReader.java b/modules/ml/src/main/java/org/apache/ignite/ml/inference/reader/FileSystemInfModelReader.java
index 1ad2161..0f04270 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/inference/reader/FileSystemInfModelReader.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/inference/reader/FileSystemInfModelReader.java
@@ -24,7 +24,7 @@
 import org.apache.ignite.ml.inference.util.DirectorySerializer;
 
 /**
- * Model reader that reads directory and serializes it using {@link DirectorySerializer}.
+ * Model reader that reads directory or file and serializes it using {@link DirectorySerializer}.
  */
 public class FileSystemInfModelReader implements InfModelReader {
     /** */
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/inference/reader/ModelStorageInfModelReader.java b/modules/ml/src/main/java/org/apache/ignite/ml/inference/reader/ModelStorageInfModelReader.java
new file mode 100644
index 0000000..2a4d4b4
--- /dev/null
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/inference/reader/ModelStorageInfModelReader.java
@@ -0,0 +1,64 @@
+/*
+ * 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.ml.inference.reader;
+
+import org.apache.ignite.Ignition;
+import org.apache.ignite.ml.inference.storage.model.ModelStorage;
+import org.apache.ignite.ml.inference.storage.model.ModelStorageFactory;
+import org.apache.ignite.ml.inference.util.DirectorySerializer;
+import org.apache.ignite.ml.math.functions.IgniteSupplier;
+
+/**
+ * Model reader that reads directory or file from model storage and serializes it using {@link DirectorySerializer}.
+ */
+public class ModelStorageInfModelReader implements InfModelReader {
+    /** */
+    private static final long serialVersionUID = -5878564742783562872L;
+
+    /** Path to the directory or file. */
+    private final String path;
+
+    /** Model storage supplier. */
+    private final IgniteSupplier<ModelStorage> mdlStorageSupplier;
+
+    /**
+     * Constructs a new instance of model storage inference model builder.
+     *
+     * @param path Path to the directory or file.
+     */
+    public ModelStorageInfModelReader(String path, IgniteSupplier<ModelStorage> mdlStorageSupplier) {
+        this.path = path;
+        this.mdlStorageSupplier = mdlStorageSupplier;
+    }
+
+    /**
+     * Constructs a new instance of model storage inference model builder.
+     *
+     * @param path Path to the directory or file.
+     */
+    public ModelStorageInfModelReader(String path) {
+        this(path, () -> new ModelStorageFactory().getModelStorage(Ignition.ignite()));
+    }
+
+    /** {@inheritDoc} */
+    @Override public byte[] read() {
+        ModelStorage storage = mdlStorageSupplier.get();
+
+        return storage.getFile(path);
+    }
+}
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/inference/storage/IgniteModelDescriptorStorage.java b/modules/ml/src/main/java/org/apache/ignite/ml/inference/storage/descriptor/IgniteModelDescriptorStorage.java
similarity index 68%
rename from modules/ml/src/main/java/org/apache/ignite/ml/inference/storage/IgniteModelDescriptorStorage.java
rename to modules/ml/src/main/java/org/apache/ignite/ml/inference/storage/descriptor/IgniteModelDescriptorStorage.java
index a198190..07503c5 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/inference/storage/IgniteModelDescriptorStorage.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/inference/storage/descriptor/IgniteModelDescriptorStorage.java
@@ -15,29 +15,30 @@
  * limitations under the License.
  */
 
-package org.apache.ignite.ml.inference.storage;
+package org.apache.ignite.ml.inference.storage.descriptor;
 
-import org.apache.ignite.Ignite;
+import java.util.Iterator;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.stream.StreamSupport;
 import org.apache.ignite.IgniteCache;
+import org.apache.ignite.lang.IgniteBiTuple;
 import org.apache.ignite.ml.inference.ModelDescriptor;
 
 /**
  * Model descriptor storage based on Apache Ignite cache.
  */
 public class IgniteModelDescriptorStorage implements ModelDescriptorStorage {
-    /** Apache Ignite cache name to keep model descriptors. */
-    private static final String MODEL_DESCRIPTOR_CACHE_NAME = "MODEL_DESCRIPTOR_CACHE";
-
     /** Apache Ignite cache to keep model descriptors. */
     private final IgniteCache<String, ModelDescriptor> models;
 
     /**
      * Constructs a new instance of Ignite model descriptor storage.
      *
-     * @param ignite Ignite instance.
+     * @param models Ignite cache with model descriptors.
      */
-    public IgniteModelDescriptorStorage(Ignite ignite) {
-        models = ignite.getOrCreateCache(MODEL_DESCRIPTOR_CACHE_NAME);
+    public IgniteModelDescriptorStorage(IgniteCache<String, ModelDescriptor> models) {
+        this.models = models;
     }
 
     /** {@inheritDoc} */
@@ -54,4 +55,12 @@
     @Override public void remove(String mdlId) {
         models.remove(mdlId);
     }
+
+    /** {@inheritDoc} */
+    @Override public Iterator<IgniteBiTuple<String, ModelDescriptor>> iterator() {
+        return StreamSupport.stream(Spliterators.spliteratorUnknownSize(models.iterator(), Spliterator.ORDERED), false)
+            .map(e -> new IgniteBiTuple<>(e.getKey(), e.getValue()))
+            .iterator();
+
+    }
 }
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/inference/storage/LocalModelDescriptorStorage.java b/modules/ml/src/main/java/org/apache/ignite/ml/inference/storage/descriptor/LocalModelDescriptorStorage.java
similarity index 81%
rename from modules/ml/src/main/java/org/apache/ignite/ml/inference/storage/LocalModelDescriptorStorage.java
rename to modules/ml/src/main/java/org/apache/ignite/ml/inference/storage/descriptor/LocalModelDescriptorStorage.java
index 99e3dac..df54ab7 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/inference/storage/LocalModelDescriptorStorage.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/inference/storage/descriptor/LocalModelDescriptorStorage.java
@@ -15,10 +15,12 @@
  * limitations under the License.
  */
 
-package org.apache.ignite.ml.inference.storage;
+package org.apache.ignite.ml.inference.storage.descriptor;
 
+import java.util.Iterator;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
+import org.apache.ignite.lang.IgniteBiTuple;
 import org.apache.ignite.ml.inference.ModelDescriptor;
 
 /**
@@ -42,4 +44,9 @@
     @Override public void remove(String name) {
         models.remove(name);
     }
+
+    /** {@inheritDoc} */
+    @Override public Iterator<IgniteBiTuple<String, ModelDescriptor>> iterator() {
+        return models.entrySet().stream().map(e -> new IgniteBiTuple<>(e.getKey(), e.getValue())).iterator();
+    }
 }
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/inference/storage/ModelDescriptorStorage.java b/modules/ml/src/main/java/org/apache/ignite/ml/inference/storage/descriptor/ModelDescriptorStorage.java
similarity index 73%
rename from modules/ml/src/main/java/org/apache/ignite/ml/inference/storage/ModelDescriptorStorage.java
rename to modules/ml/src/main/java/org/apache/ignite/ml/inference/storage/descriptor/ModelDescriptorStorage.java
index 46b6b65..4bb8cfd 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/inference/storage/ModelDescriptorStorage.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/inference/storage/descriptor/ModelDescriptorStorage.java
@@ -15,14 +15,16 @@
  * limitations under the License.
  */
 
-package org.apache.ignite.ml.inference.storage;
+package org.apache.ignite.ml.inference.storage.descriptor;
 
+import java.util.Iterator;
+import org.apache.ignite.lang.IgniteBiTuple;
 import org.apache.ignite.ml.inference.ModelDescriptor;
 
 /**
  * Storage that allows to load, keep and get access to model descriptors (see {@link ModelDescriptor}).
  */
-public interface ModelDescriptorStorage {
+public interface ModelDescriptorStorage extends Iterable<IgniteBiTuple<String, ModelDescriptor>> {
     /**
      * Saves the specified model descriptor with the specified model identifier.
      *
@@ -45,4 +47,12 @@
      * @param mdlId Model identifier.
      */
     public void remove(String mdlId);
+
+    /**
+     * Returns iterator of model descriptors stored in this model descriptor storage. The objects produces by the
+     * iterator are pairs of model identifier and model descriptor.
+     *
+     * @return Iterator of pairs of model identifier and model descriptor.
+     */
+    public Iterator<IgniteBiTuple<String, ModelDescriptor>> iterator();
 }
\ No newline at end of file
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/inference/storage/descriptor/ModelDescriptorStorageFactory.java b/modules/ml/src/main/java/org/apache/ignite/ml/inference/storage/descriptor/ModelDescriptorStorageFactory.java
new file mode 100644
index 0000000..7f5daf4
--- /dev/null
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/inference/storage/descriptor/ModelDescriptorStorageFactory.java
@@ -0,0 +1,43 @@
+/*
+ * 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.ml.inference.storage.descriptor;
+
+import org.apache.ignite.Ignite;
+import org.apache.ignite.IgniteCache;
+import org.apache.ignite.ml.inference.ModelDescriptor;
+
+/**
+ * Model descriptor storage factory. Provides {@link ModelDescriptorStorage}.
+ */
+public class ModelDescriptorStorageFactory {
+    /** Model descriptor storage cache name. */
+    public static final String MODEL_DESCRIPTOR_STORAGE_CACHE_NAME = "MODEL_DESCRIPTOR_STORAGE";
+
+    /**
+     * Returns model descriptor storage based on Apache Ignite cache.
+     *
+     * @param ignite Ignite instance.
+     * @return Model descriptor storage.
+     */
+    public ModelDescriptorStorage getModelDescriptorStorage(Ignite ignite) {
+        IgniteCache<String, ModelDescriptor> cache = ignite.cache(MODEL_DESCRIPTOR_STORAGE_CACHE_NAME);
+
+        return new IgniteModelDescriptorStorage(cache);
+    }
+
+}
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/regressions/logistic/binomial/package-info.java b/modules/ml/src/main/java/org/apache/ignite/ml/inference/storage/descriptor/package-info.java
similarity index 87%
copy from modules/ml/src/main/java/org/apache/ignite/ml/regressions/logistic/binomial/package-info.java
copy to modules/ml/src/main/java/org/apache/ignite/ml/inference/storage/descriptor/package-info.java
index d32b1ee..b94273b 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/regressions/logistic/binomial/package-info.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/inference/storage/descriptor/package-info.java
@@ -17,6 +17,6 @@
 
 /**
  * <!-- Package description. -->
- * Contains binomial logistic regression.
+ * Root package for inference model descriptor storages.
  */
-package org.apache.ignite.ml.regressions.logistic.binomial;
\ No newline at end of file
+package org.apache.ignite.ml.inference.storage.descriptor;
\ No newline at end of file
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/inference/storage/model/DefaultModelStorage.java b/modules/ml/src/main/java/org/apache/ignite/ml/inference/storage/model/DefaultModelStorage.java
new file mode 100644
index 0000000..b765198
--- /dev/null
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/inference/storage/model/DefaultModelStorage.java
@@ -0,0 +1,313 @@
+/*
+ * 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.ml.inference.storage.model;
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Deque;
+import java.util.LinkedList;
+import java.util.Set;
+import java.util.concurrent.locks.Lock;
+import java.util.function.Supplier;
+import org.apache.ignite.lang.IgniteBiTuple;
+
+/**
+ * Default implementation of {@link ModelStorage} that can use any {@link ModelStorageProvider} as a backend storage
+ * system.
+ */
+public class DefaultModelStorage implements ModelStorage {
+    /** Ignite Cache that is used to store model storage files. */
+    private final ModelStorageProvider storageProvider;
+
+    /**
+     * Constructs a new instance of Ignite model storage.
+     *
+     * @param storageProvider Model storage provider.
+     */
+    public DefaultModelStorage(ModelStorageProvider storageProvider) {
+        this.storageProvider = storageProvider;
+    }
+
+    /** {@inheritDoc} */
+    @Override public void putFile(String path, byte[] data, boolean onlyIfNotExist) {
+        String parentPath = getParent(path);
+
+        // Paths are locked in child-first order.
+        Lock pathLock = storageProvider.lock(path);
+        Lock parentPathLock = storageProvider.lock(parentPath);
+
+        synchronize(() -> {
+            if (exists(path) && onlyIfNotExist)
+                throw new IllegalArgumentException("File already exists [path=" + path + "]");
+
+            FileOrDirectory parent = storageProvider.get(parentPath);
+
+            // If parent doesn't exist throw an exception.
+            if (parent == null)
+                throw new IllegalArgumentException("Cannot create file because directory doesn't exist [path="
+                    + path + "]");
+
+            // If parent is not a directory throw an exception.
+            if (!parent.isDirectory())
+                throw new IllegalArgumentException("Cannot create file because parent is not a directory [path="
+                    + path + "]");
+
+            Directory dir = (Directory) parent;
+            // Update parent if it's a new file.
+            if (!dir.getFiles().contains(path)) {
+                dir.getFiles().add(path);
+                storageProvider.put(parentPath, parent);
+            }
+
+            // Save file into cache.
+            storageProvider.put(path, new File(data));
+        }, pathLock, parentPathLock);
+    }
+
+    /**  {@inheritDoc}*/
+    @Override public byte[] getFile(String path) {
+        FileOrDirectory fileOrDir = storageProvider.get(path);
+
+        Lock pathLock = storageProvider.lock(path);
+
+        return synchronize(() -> {
+            // If file doesn't exist throw an exception.
+            if (fileOrDir == null)
+                throw new IllegalArgumentException("File doesn't exist [path=" + path + "]");
+
+            // If file is not a regular file throw an exception.
+            if (!fileOrDir.isFile())
+                throw new IllegalArgumentException("File is not a regular file [path=" + path + "]");
+
+            return ((File) fileOrDir).getData();
+        }, pathLock);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void mkdir(String path, boolean onlyIfNotExist) {
+        String parentPath = getParent(path);
+
+        // Paths are locked in child-first order.
+        Lock pathLock = storageProvider.lock(path);
+        Lock parentPathLock = storageProvider.lock(parentPath);
+
+        synchronize(() -> {
+            // If a directory associated with specified path exists return.
+            if (isDirectory(path)) {
+                if (onlyIfNotExist)
+                    throw new IllegalArgumentException("Directory already exists [path=" + path + "]");
+
+                return;
+            }
+
+            // If a regular file associated with specified path exists throw an exception.
+            if (isFile(path))
+                throw new IllegalArgumentException("File with specified path already exists [path=" + path + "]");
+
+            FileOrDirectory parent = storageProvider.get(parentPath);
+
+            // If parent doesn't exist throw an exception.
+            if (parent == null)
+                throw new IllegalArgumentException("Cannot create directory because parent directory does not exist"
+                    + " [path=" + path + "]");
+
+            // If parent is not a directory throw an exception.
+            if (!parent.isDirectory())
+                throw new IllegalArgumentException("Cannot create directory because parent is not a directory [path="
+                    + path + "]");
+
+            Directory dir = (Directory) parent;
+            dir.getFiles().add(path);
+
+            // Update parent and save directory into cache.
+            storageProvider.put(parentPath, parent);
+            storageProvider.put(path, new Directory());
+        }, pathLock, parentPathLock);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void mkdirs(String path) {
+        Deque<IgniteBiTuple<String, Lock>> pathsToBeCreated = new LinkedList<>();
+
+        IgniteBiTuple<String, Lock> parentWithLock = null;
+
+        try {
+            while (path != null) {
+                // Paths are locked in child-first order.
+                Lock lock = storageProvider.lock(path);
+                lock.lock();
+
+                pathsToBeCreated.push(new IgniteBiTuple<>(path, lock));
+
+                if (exists(path)) {
+                    if (isDirectory(path)) {
+                        parentWithLock = pathsToBeCreated.pop();
+                        break;
+                    }
+
+                    throw new IllegalArgumentException("Cannot create directory because parent is not a directory "
+                        + "[path=" + path + "]");
+                }
+
+                path = getParent(path);
+            }
+
+            while (!pathsToBeCreated.isEmpty()) {
+                IgniteBiTuple<String, Lock> pathWithLock = pathsToBeCreated.pop();
+
+                storageProvider.put(pathWithLock.get1(), new Directory());
+
+                if (parentWithLock != null) {
+                    Directory parentDir = (Directory)storageProvider.get(parentWithLock.get1());
+                    parentDir.getFiles().add(pathWithLock.get1());
+                    storageProvider.put(parentWithLock.get1(), parentDir);
+                    parentWithLock.get2().unlock();
+                }
+
+                parentWithLock = pathWithLock;
+            }
+
+            if (parentWithLock != null)
+                parentWithLock.get2().unlock();
+        }
+        finally {
+            for (IgniteBiTuple<String, Lock> pathWithLock : pathsToBeCreated)
+                pathWithLock.get2().unlock();
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override public Set<String> listFiles(String path) {
+        Lock pathLock = storageProvider.lock(path);
+
+        pathLock.lock();
+
+        return synchronize(() -> {
+            FileOrDirectory dir = storageProvider.get(path);
+
+            // If directory doesn't exist throw an exception.
+            if (dir == null)
+                throw new IllegalArgumentException("Directory doesn't exist [path=" + path + "]");
+
+            // If directory isn't a directory throw an exception.
+            if (!dir.isDirectory())
+                throw new IllegalArgumentException("Specified path is not associated with directory [path=" + path
+                    + "]");
+
+            return ((Directory) dir).getFiles();
+        }, pathLock);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void remove(String path) {
+        Lock pathLock = storageProvider.lock(path);
+
+        synchronize(() -> {
+            FileOrDirectory file = storageProvider.get(path);
+            storageProvider.remove(path);
+
+            if (file.isDirectory()) {
+                for (String s : ((Directory) file).getFiles())
+                    remove(s);
+            }
+        }, pathLock);
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean exists(String path) {
+        return storageProvider.get(path) != null;
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean isDirectory(String path) {
+        FileOrDirectory file = storageProvider.get(path);
+
+        return file != null && file.isDirectory();
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean isFile(String path) {
+        FileOrDirectory file = storageProvider.get(path);
+
+        return file != null && file.isFile();
+    }
+
+    /**
+     * Returns parent directory for the specified path.
+     *
+     * @param path Path.
+     * @return Parent directory path.
+     */
+    private String getParent(String path) {
+        Path parentPath = Paths.get(path).getParent();
+        return parentPath == null ? null : parentPath.toString();
+    }
+
+    /**
+     * Wraps task execution into locks.
+     *
+     * @param task Runnable task.
+     * @param locks List of locks.
+     */
+    static void synchronize(Runnable task, Lock... locks) {
+        synchronize(() -> {
+            task.run();
+            return null;
+        }, locks);
+    }
+
+    /**
+     * Wraps task execution into locks. Util method.
+     * @param task Task to executed.
+     * @param locks List of locks.
+     */
+    static <T> T synchronize(Supplier<T> task, Lock... locks) {
+        Throwable ex = null;
+        T res;
+
+        int i = 0;
+        try {
+            for (; i < locks.length; i++)
+                locks[i].lock();
+
+            res = task.get();
+        }
+        finally {
+            for (i = i - 1; i >= 0; i--) {
+                try {
+                    locks[i].unlock();
+                }
+                catch (RuntimeException | Error e) {
+                    ex = e;
+                }
+            }
+        }
+
+        if (ex != null) {
+            if (ex instanceof RuntimeException)
+                throw (RuntimeException) ex;
+
+            if (ex instanceof Error)
+                throw (Error) ex;
+
+            throw new IllegalStateException("Unexpected type of throwable");
+        }
+
+        return res;
+    }
+}
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheGetEntryOptimisticSerializableSeltTest.java b/modules/ml/src/main/java/org/apache/ignite/ml/inference/storage/model/Directory.java
similarity index 60%
copy from modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheGetEntryOptimisticSerializableSeltTest.java
copy to modules/ml/src/main/java/org/apache/ignite/ml/inference/storage/model/Directory.java
index 6ded4a9..303760f 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheGetEntryOptimisticSerializableSeltTest.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/inference/storage/model/Directory.java
@@ -15,22 +15,28 @@
  * limitations under the License.
  */
 
-package org.apache.ignite.internal.processors.cache;
+package org.apache.ignite.ml.inference.storage.model;
 
-import org.apache.ignite.transactions.TransactionConcurrency;
-import org.apache.ignite.transactions.TransactionIsolation;
+import java.util.HashSet;
+import java.util.Set;
 
 /**
- * Test getEntry and getEntries methods.
+ * Implementation of directory {@link ModelStorageProvider} works with.
  */
-public class CacheGetEntryOptimisticSerializableSeltTest extends CacheGetEntryAbstractTest {
-    /** {@inheritDoc} */
-    @Override protected TransactionConcurrency concurrency() {
-        return TransactionConcurrency.OPTIMISTIC;
-    }
+class Directory implements FileOrDirectory {
+    /** */
+    private static final long serialVersionUID = -6441963559954107245L;
+
+    /** List of files in the directory. */
+    private final Set<String> files = new HashSet<>();
 
     /** {@inheritDoc} */
-    @Override protected TransactionIsolation isolation() {
-        return TransactionIsolation.SERIALIZABLE;
+    @Override public boolean isFile() {
+        return false;
+    }
+
+    /** */
+    Set<String> getFiles() {
+        return files;
     }
 }
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/inference/storage/model/File.java b/modules/ml/src/main/java/org/apache/ignite/ml/inference/storage/model/File.java
new file mode 100644
index 0000000..774bdaf
--- /dev/null
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/inference/storage/model/File.java
@@ -0,0 +1,48 @@
+/*
+ * 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.ml.inference.storage.model;
+
+/**
+ * Implementation of file {@link ModelStorageProvider} works with.
+ */
+class File implements FileOrDirectory {
+    /** */
+    private static final long serialVersionUID = -7739751667495712802L;
+
+    /** File content. */
+    private final byte[] data;
+
+    /**
+     * Constructs a new instance of file.
+     *
+     * @param data File content.
+     */
+    protected File(byte[] data) {
+        this.data = data;
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean isFile() {
+        return true;
+    }
+
+    /** */
+    protected byte[] getData() {
+        return data;
+    }
+}
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/inference/storage/model/FileOrDirectory.java b/modules/ml/src/main/java/org/apache/ignite/ml/inference/storage/model/FileOrDirectory.java
new file mode 100644
index 0000000..de16751
--- /dev/null
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/inference/storage/model/FileOrDirectory.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.ml.inference.storage.model;
+
+import java.io.Serializable;
+
+/**
+ * Base interface for file or directory {@link ModelStorageProvider} works with.
+ */
+public interface FileOrDirectory extends Serializable {
+    /**
+     * Returns {@code true} if this object is a regular file, otherwise {@code false}.
+     *
+     * @return {@code true} if this object is a regular file, otherwise {@code false}.
+     */
+    public boolean isFile();
+
+    /**
+     * Return {@code true} if this object is a directory, otherwise {@code false}.
+     *
+     * @return {@code true} if this object is a directory, otherwise {@code false}.
+     */
+    public default boolean isDirectory() {
+        return !isFile();
+    }
+}
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/inference/storage/model/IgniteModelStorageProvider.java b/modules/ml/src/main/java/org/apache/ignite/ml/inference/storage/model/IgniteModelStorageProvider.java
new file mode 100644
index 0000000..7e40aed
--- /dev/null
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/inference/storage/model/IgniteModelStorageProvider.java
@@ -0,0 +1,58 @@
+/*
+ * 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.ml.inference.storage.model;
+
+import java.util.concurrent.locks.Lock;
+import org.apache.ignite.IgniteCache;
+
+/**
+ * Implementation of {@link ModelStorageProvider} based on Apache Ignite cache.
+ */
+public class IgniteModelStorageProvider implements ModelStorageProvider {
+    /** Storage of the files and directories. */
+    private final IgniteCache<String, FileOrDirectory> cache;
+
+    /**
+     * Constructs a new instance of Ignite model storage provider.
+     *
+     * @param cache Storage of the files and directories.
+     */
+    public IgniteModelStorageProvider(IgniteCache<String, FileOrDirectory> cache) {
+        this.cache = cache;
+    }
+
+    /** {@inheritDoc} */
+    @Override public FileOrDirectory get(String path) {
+        return cache.get(path);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void put(String path, FileOrDirectory file) {
+        cache.put(path, file);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void remove(String path) {
+        cache.remove(path);
+    }
+
+    /** {@inheritDoc} */
+    @Override public Lock lock(String path) {
+        return cache.lock(path);
+    }
+}
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/inference/storage/model/LocalModelStorageProvider.java b/modules/ml/src/main/java/org/apache/ignite/ml/inference/storage/model/LocalModelStorageProvider.java
new file mode 100644
index 0000000..e86533d
--- /dev/null
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/inference/storage/model/LocalModelStorageProvider.java
@@ -0,0 +1,56 @@
+/*
+ * 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.ml.inference.storage.model;
+
+import java.lang.ref.WeakReference;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+/**
+ * Implementation of {@link ModelStorageProvider} based on local {@link ConcurrentHashMap}.
+ */
+public class LocalModelStorageProvider implements ModelStorageProvider {
+    /** Storage of the files and directories. */
+    private final ConcurrentMap<String, FileOrDirectory> storage = new ConcurrentHashMap<>();
+
+    /** Storage of the locks. */
+    private final ConcurrentMap<String, WeakReference<Lock>> locks = new ConcurrentHashMap<>();
+
+    /** {@inheritDoc} */
+    @Override public FileOrDirectory get(String key) {
+        return storage.get(key);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void put(String key, FileOrDirectory file) {
+        storage.put(key, file);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void remove(String key) {
+        storage.remove(key);
+    }
+
+    /** {@inheritDoc} */
+    @Override public Lock lock(String key) {
+        Lock lock = new ReentrantLock();
+        return locks.computeIfAbsent(key, k -> new WeakReference<>(lock)).get();
+    }
+}
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/inference/storage/model/ModelStorage.java b/modules/ml/src/main/java/org/apache/ignite/ml/inference/storage/model/ModelStorage.java
new file mode 100644
index 0000000..f4e6f85
--- /dev/null
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/inference/storage/model/ModelStorage.java
@@ -0,0 +1,115 @@
+/*
+ * 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.ml.inference.storage.model;
+
+import java.util.Set;
+
+/**
+ * Storage that allows to load, keep and get access to model in byte representation.
+ */
+public interface ModelStorage {
+    /**
+     * Creates a new or replaces existing file.
+     *
+     * @param path Path to file.
+     * @param data File content.
+     * @param onlyIfNotExist If file already exists throw an exception.
+     */
+    public void putFile(String path, byte[] data, boolean onlyIfNotExist);
+
+    /**
+     * Creates a new or replaces existing file.
+     *
+     * @param path Path to file.
+     * @param data File content.
+     */
+    public default void putFile(String path, byte[] data) {
+        putFile(path, data, false);
+    }
+
+    /**
+     * Returns file content.
+     *
+     * @param path Path to file.
+     * @return File content.
+     */
+    public byte[] getFile(String path);
+
+    /**
+     * Creates directory.
+     *
+     * @param path Path to directory.
+     * @param onlyIfNotExist If directory already exists throw an exception.
+     */
+    public void mkdir(String path, boolean onlyIfNotExist);
+
+    /**
+     * Creates directory.
+     *
+     * @param path Path to directory.
+     */
+    public default void mkdir(String path) {
+        mkdir(path, false);
+    }
+
+    /**
+     * Creates directory and all required parent directories in the path.
+     *
+     * @param path Path to directory.
+     */
+    public void mkdirs(String path);
+
+    /**
+     * Returns list of files in the specified directory.
+     *
+     * @param path Path to directory.
+     * @return List of files in the specified directory.
+     */
+    public Set<String> listFiles(String path);
+
+    /**
+     * Removes specified directory or file.
+     *
+     * @param path Path to directory or file.
+     */
+    public void remove(String path);
+
+    /**
+     * Returns {@code true} if a regular file or directory exist, otherwise {@code false}.
+     *
+     * @param path Path to directory or file.
+     * @return {@code true} if a regular file or directory exist, otherwise {@code false}.
+     */
+    public boolean exists(String path);
+
+    /**
+     * Returns {@code true} if the specified path associated with a directory.
+     *
+     * @param path Path to directory or file.
+     * @return {@code true} if the specified path associated with a directory.
+     */
+    public boolean isDirectory(String path);
+
+    /**
+     * Returns {@code true} if the specified path associated with a regular file.
+     *
+     * @param path Path to directory or file.
+     * @return {@code true} if the specified path associated with a regular file.
+     */
+    public boolean isFile(String path);
+}
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/inference/storage/model/ModelStorageFactory.java b/modules/ml/src/main/java/org/apache/ignite/ml/inference/storage/model/ModelStorageFactory.java
new file mode 100644
index 0000000..96246ff
--- /dev/null
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/inference/storage/model/ModelStorageFactory.java
@@ -0,0 +1,42 @@
+/*
+ * 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.ml.inference.storage.model;
+
+import org.apache.ignite.Ignite;
+import org.apache.ignite.IgniteCache;
+
+/**
+ * Model storage factory. Provides {@link ModelStorage}.
+ */
+public class ModelStorageFactory {
+    /** Model storage cache name. */
+    public static final String MODEL_STORAGE_CACHE_NAME = "MODEL_STORAGE";
+
+    /**
+     * Returns model storage based on Apache Ignite cache.
+     *
+     * @param ignite Ignite instance.
+     * @return Model storage.
+     */
+    public ModelStorage getModelStorage(Ignite ignite) {
+        IgniteCache<String, FileOrDirectory> cache = ignite.cache(MODEL_STORAGE_CACHE_NAME);
+        ModelStorageProvider storageProvider = new IgniteModelStorageProvider(cache);
+
+        return new DefaultModelStorage(storageProvider);
+    }
+}
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/inference/storage/model/ModelStorageProvider.java b/modules/ml/src/main/java/org/apache/ignite/ml/inference/storage/model/ModelStorageProvider.java
new file mode 100644
index 0000000..af11755
--- /dev/null
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/inference/storage/model/ModelStorageProvider.java
@@ -0,0 +1,56 @@
+/*
+ * 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.ml.inference.storage.model;
+
+import java.util.concurrent.locks.Lock;
+
+/**
+ * Model storage provider that keeps files and directories presented as {@link FileOrDirectory} files and correspondent
+ * locks.
+ */
+public interface ModelStorageProvider {
+    /**
+     * Returns file or directory associated with the specified path.
+     *
+     * @param path Path of file or directory.
+     * @return File or directory associated with the specified path.
+     */
+    public FileOrDirectory get(String path);
+
+    /**
+     * Saves file or directory associated with the specified path.
+     *
+     * @param path Path to the file or directory.
+     * @param file File or directory to be saved.
+     */
+    public void put(String path, FileOrDirectory file);
+
+    /**
+     * Removes file or directory associated with the specified path.
+     *
+     * @param path Path to the file or directory.
+     */
+    public void remove(String path);
+
+    /**
+     * Locks the specified path.
+     *
+     * @param path Path to be locked.
+     */
+    public Lock lock(String path);
+}
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/regressions/logistic/binomial/package-info.java b/modules/ml/src/main/java/org/apache/ignite/ml/inference/storage/model/package-info.java
similarity index 89%
rename from modules/ml/src/main/java/org/apache/ignite/ml/regressions/logistic/binomial/package-info.java
rename to modules/ml/src/main/java/org/apache/ignite/ml/inference/storage/model/package-info.java
index d32b1ee..c203307 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/regressions/logistic/binomial/package-info.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/inference/storage/model/package-info.java
@@ -17,6 +17,6 @@
 
 /**
  * <!-- Package description. -->
- * Contains binomial logistic regression.
+ * Root package for inference model storages.
  */
-package org.apache.ignite.ml.regressions.logistic.binomial;
\ No newline at end of file
+package org.apache.ignite.ml.inference.storage.model;
\ No newline at end of file
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/inference/storage/package-info.java b/modules/ml/src/main/java/org/apache/ignite/ml/inference/storage/package-info.java
index 168f4e4..c310e62 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/inference/storage/package-info.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/inference/storage/package-info.java
@@ -17,6 +17,6 @@
 
 /**
  * <!-- Package description. -->
- * Root package for model inference descriptor storages.
+ * Root package for inference model storages.
  */
 package org.apache.ignite.ml.inference.storage;
\ No newline at end of file
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/knn/KNNUtils.java b/modules/ml/src/main/java/org/apache/ignite/ml/knn/KNNUtils.java
index d7bccd8..8239ebd 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/knn/KNNUtils.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/knn/KNNUtils.java
@@ -21,6 +21,7 @@
 import org.apache.ignite.ml.dataset.DatasetBuilder;
 import org.apache.ignite.ml.dataset.PartitionDataBuilder;
 import org.apache.ignite.ml.dataset.primitive.context.EmptyContext;
+import org.apache.ignite.ml.environment.LearningEnvironmentBuilder;
 import org.apache.ignite.ml.math.functions.IgniteBiFunction;
 import org.apache.ignite.ml.math.primitives.vector.Vector;
 import org.apache.ignite.ml.structures.LabeledVector;
@@ -35,12 +36,15 @@
     /**
      * Builds dataset.
      *
+     * @param envBuilder Learning environment builder.
      * @param datasetBuilder Dataset builder.
      * @param featureExtractor Feature extractor.
      * @param lbExtractor Label extractor.
      * @return Dataset.
      */
-    @Nullable public static <K, V> Dataset<EmptyContext, LabeledVectorSet<Double, LabeledVector>> buildDataset(DatasetBuilder<K, V> datasetBuilder, IgniteBiFunction<K, V, Vector> featureExtractor, IgniteBiFunction<K, V, Double> lbExtractor) {
+    @Nullable public static <K, V> Dataset<EmptyContext, LabeledVectorSet<Double, LabeledVector>> buildDataset(
+        LearningEnvironmentBuilder envBuilder,
+        DatasetBuilder<K, V> datasetBuilder, IgniteBiFunction<K, V, Vector> featureExtractor, IgniteBiFunction<K, V, Double> lbExtractor) {
         PartitionDataBuilder<K, V, EmptyContext, LabeledVectorSet<Double, LabeledVector>> partDataBuilder
             = new LabeledDatasetPartitionDataBuilderOnHeap<>(
             featureExtractor,
@@ -51,7 +55,8 @@
 
         if (datasetBuilder != null) {
             dataset = datasetBuilder.build(
-                (upstream, upstreamSize) -> new EmptyContext(),
+                envBuilder,
+                (env, upstream, upstreamSize) -> new EmptyContext(),
                 partDataBuilder
             );
         }
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/knn/ann/ANNClassificationTrainer.java b/modules/ml/src/main/java/org/apache/ignite/ml/knn/ann/ANNClassificationTrainer.java
index e56a10a..c32ca56 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/knn/ann/ANNClassificationTrainer.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/knn/ann/ANNClassificationTrainer.java
@@ -31,6 +31,7 @@
 import org.apache.ignite.ml.dataset.DatasetBuilder;
 import org.apache.ignite.ml.dataset.PartitionDataBuilder;
 import org.apache.ignite.ml.dataset.primitive.context.EmptyContext;
+import org.apache.ignite.ml.environment.LearningEnvironmentBuilder;
 import org.apache.ignite.ml.math.distances.DistanceMeasure;
 import org.apache.ignite.ml.math.distances.EuclideanDistance;
 import org.apache.ignite.ml.math.functions.IgniteBiFunction;
@@ -105,6 +106,12 @@
         return mdl.getDistanceMeasure().equals(distance) && mdl.getCandidates().rowSize() == k;
     }
 
+    /** {@inheritDoc} */
+    @Override public ANNClassificationTrainer withEnvironmentBuilder(
+        LearningEnvironmentBuilder envBuilder) {
+        return (ANNClassificationTrainer)super.withEnvironmentBuilder(envBuilder);
+    }
+
     /** */
     @NotNull private LabeledVectorSet<ProbableLabel, LabeledVector> buildLabelsForCandidates(List<Vector> centers,
         CentroidStat centroidStat) {
@@ -180,7 +187,8 @@
         );
 
         try (Dataset<EmptyContext, LabeledVectorSet<Double, LabeledVector>> dataset = datasetBuilder.build(
-            (upstream, upstreamSize) -> new EmptyContext(),
+            envBuilder,
+            (env, upstream, upstreamSize) -> new EmptyContext(),
             partDataBuilder
         )) {
             return dataset.compute(data -> {
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/knn/classification/KNNClassificationTrainer.java b/modules/ml/src/main/java/org/apache/ignite/ml/knn/classification/KNNClassificationTrainer.java
index 1a3ff73..ed55318 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/knn/classification/KNNClassificationTrainer.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/knn/classification/KNNClassificationTrainer.java
@@ -18,6 +18,7 @@
 package org.apache.ignite.ml.knn.classification;
 
 import org.apache.ignite.ml.dataset.DatasetBuilder;
+import org.apache.ignite.ml.environment.LearningEnvironmentBuilder;
 import org.apache.ignite.ml.knn.KNNUtils;
 import org.apache.ignite.ml.math.functions.IgniteBiFunction;
 import org.apache.ignite.ml.math.primitives.vector.Vector;
@@ -46,7 +47,7 @@
         DatasetBuilder<K, V> datasetBuilder, IgniteBiFunction<K, V, Vector> featureExtractor,
         IgniteBiFunction<K, V, Double> lbExtractor) {
 
-        KNNClassificationModel res = new KNNClassificationModel(KNNUtils.buildDataset(datasetBuilder,
+        KNNClassificationModel res = new KNNClassificationModel(KNNUtils.buildDataset(envBuilder, datasetBuilder,
             featureExtractor, lbExtractor));
         if (mdl != null)
             res.copyStateFrom(mdl);
@@ -54,6 +55,11 @@
     }
 
     /** {@inheritDoc} */
+    @Override public KNNClassificationTrainer withEnvironmentBuilder(LearningEnvironmentBuilder envBuilder) {
+        return (KNNClassificationTrainer)super.withEnvironmentBuilder(envBuilder);
+    }
+
+    /** {@inheritDoc} */
     @Override protected boolean checkState(KNNClassificationModel mdl) {
         return true;
     }
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/knn/regression/KNNRegressionTrainer.java b/modules/ml/src/main/java/org/apache/ignite/ml/knn/regression/KNNRegressionTrainer.java
index 7a42dc8..9b348f3 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/knn/regression/KNNRegressionTrainer.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/knn/regression/KNNRegressionTrainer.java
@@ -42,10 +42,13 @@
     }
 
     /** {@inheritDoc} */
-    @Override public <K, V> KNNRegressionModel updateModel(KNNRegressionModel mdl, DatasetBuilder<K, V> datasetBuilder,
-        IgniteBiFunction<K, V, Vector> featureExtractor, IgniteBiFunction<K, V, Double> lbExtractor) {
+    @Override public <K, V> KNNRegressionModel updateModel(
+        KNNRegressionModel mdl,
+        DatasetBuilder<K, V> datasetBuilder,
+        IgniteBiFunction<K, V, Vector> featureExtractor,
+        IgniteBiFunction<K, V, Double> lbExtractor) {
 
-        KNNRegressionModel res = new KNNRegressionModel(KNNUtils.buildDataset(datasetBuilder,
+        KNNRegressionModel res = new KNNRegressionModel(KNNUtils.buildDataset(envBuilder, datasetBuilder,
             featureExtractor, lbExtractor));
         if (mdl != null)
             res.copyStateFrom(mdl);
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/math/functions/IgniteFunction.java b/modules/ml/src/main/java/org/apache/ignite/ml/math/functions/IgniteFunction.java
index 9d19592..2673b90 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/math/functions/IgniteFunction.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/math/functions/IgniteFunction.java
@@ -26,5 +26,15 @@
  * @see java.util.function.Function
  */
 public interface IgniteFunction<T, R> extends Function<T, R>, Serializable {
-
+    /**
+     * {@link IgniteFunction} returning specified constant.
+     *
+     * @param r Constant to return.
+     * @param <T> Type of input.
+     * @param <R> Type of output.
+     * @return {@link IgniteFunction} returning specified constant.
+     */
+    static <T, R> IgniteFunction<T, R> constant(R r) {
+        return t -> r;
+    }
 }
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/math/isolve/lsqr/LSQROnHeap.java b/modules/ml/src/main/java/org/apache/ignite/ml/math/isolve/lsqr/LSQROnHeap.java
index 14356e1..e0376b8 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/math/isolve/lsqr/LSQROnHeap.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/math/isolve/lsqr/LSQROnHeap.java
@@ -23,6 +23,7 @@
 import org.apache.ignite.ml.dataset.DatasetBuilder;
 import org.apache.ignite.ml.dataset.PartitionDataBuilder;
 import org.apache.ignite.ml.dataset.primitive.data.SimpleLabeledDatasetData;
+import org.apache.ignite.ml.environment.LearningEnvironmentBuilder;
 
 /**
  * Distributed implementation of LSQR algorithm based on {@link AbstractLSQR} and {@link Dataset}.
@@ -35,12 +36,15 @@
      * Constructs a new instance of OnHeap LSQR algorithm implementation.
      *
      * @param datasetBuilder Dataset builder.
+     * @param envBuilder Learning environment builder.
      * @param partDataBuilder Partition data builder.
      */
     public LSQROnHeap(DatasetBuilder<K, V> datasetBuilder,
+        LearningEnvironmentBuilder envBuilder,
         PartitionDataBuilder<K, V, LSQRPartitionContext, SimpleLabeledDatasetData> partDataBuilder) {
         this.dataset = datasetBuilder.build(
-            (upstream, upstreamSize) -> new LSQRPartitionContext(),
+            envBuilder,
+            (env, upstream, upstreamSize) -> new LSQRPartitionContext(),
             partDataBuilder
         );
     }
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/math/primitives/vector/VectorUtils.java b/modules/ml/src/main/java/org/apache/ignite/ml/math/primitives/vector/VectorUtils.java
index 5e1341b..3c580c3 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/math/primitives/vector/VectorUtils.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/math/primitives/vector/VectorUtils.java
@@ -40,6 +40,17 @@
     }
 
     /**
+     * Create new vector of specified size n with specified value.
+     *
+     * @param val Value.
+     * @param n Size;
+     * @return New vector of specified size n with specified value.
+     */
+    public static DenseVector fill(double val, int n) {
+        return (DenseVector)new DenseVector(n).assign(val);
+    }
+
+    /**
      * Turn number into a local Vector of given size with one-hot encoding.
      *
      * @param num Number to turn into vector.
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/multiclass/OneVsRestTrainer.java b/modules/ml/src/main/java/org/apache/ignite/ml/multiclass/OneVsRestTrainer.java
index 7426506..f265318 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/multiclass/OneVsRestTrainer.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/multiclass/OneVsRestTrainer.java
@@ -115,7 +115,8 @@
         List<Double> res = new ArrayList<>();
 
         try (Dataset<EmptyContext, LabelPartitionDataOnHeap> dataset = datasetBuilder.build(
-            (upstream, upstreamSize) -> new EmptyContext(),
+            envBuilder,
+            (env, upstream, upstreamSize) -> new EmptyContext(),
             partDataBuilder
         )) {
             final Set<Double> clsLabels = dataset.compute(data -> {
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/naivebayes/gaussian/GaussianNaiveBayesTrainer.java b/modules/ml/src/main/java/org/apache/ignite/ml/naivebayes/gaussian/GaussianNaiveBayesTrainer.java
index 7ee423d..cdaac5a 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/naivebayes/gaussian/GaussianNaiveBayesTrainer.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/naivebayes/gaussian/GaussianNaiveBayesTrainer.java
@@ -24,6 +24,7 @@
 import org.apache.ignite.ml.dataset.DatasetBuilder;
 import org.apache.ignite.ml.dataset.UpstreamEntry;
 import org.apache.ignite.ml.dataset.primitive.context.EmptyContext;
+import org.apache.ignite.ml.environment.LearningEnvironmentBuilder;
 import org.apache.ignite.ml.math.functions.IgniteBiFunction;
 import org.apache.ignite.ml.math.primitives.vector.Vector;
 import org.apache.ignite.ml.trainers.SingleLabelDatasetTrainer;
@@ -59,14 +60,20 @@
     }
 
     /** {@inheritDoc} */
+    @Override public GaussianNaiveBayesTrainer withEnvironmentBuilder(LearningEnvironmentBuilder envBuilder) {
+        return (GaussianNaiveBayesTrainer)super.withEnvironmentBuilder(envBuilder);
+    }
+
+    /** {@inheritDoc} */
     @Override protected <K, V> GaussianNaiveBayesModel updateModel(GaussianNaiveBayesModel mdl,
         DatasetBuilder<K, V> datasetBuilder, IgniteBiFunction<K, V, Vector> featureExtractor,
         IgniteBiFunction<K, V, Double> lbExtractor) {
         assert datasetBuilder != null;
 
         try (Dataset<EmptyContext, GaussianNaiveBayesSumsHolder> dataset = datasetBuilder.build(
-            (upstream, upstreamSize) -> new EmptyContext(),
-            (upstream, upstreamSize, ctx) -> {
+            envBuilder,
+            (env, upstream, upstreamSize) -> new EmptyContext(),
+            (env, upstream, upstreamSize, ctx) -> {
 
                 GaussianNaiveBayesSumsHolder res = new GaussianNaiveBayesSumsHolder();
                 while (upstream.hasNext()) {
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/nn/MLPTrainer.java b/modules/ml/src/main/java/org/apache/ignite/ml/nn/MLPTrainer.java
index c75c5bb..ea0bb6c 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/nn/MLPTrainer.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/nn/MLPTrainer.java
@@ -124,6 +124,7 @@
         assert updatesStgy!= null;
 
         try (Dataset<EmptyContext, SimpleLabeledDatasetData> dataset = datasetBuilder.build(
+            envBuilder,
             new EmptyContextBuilder<>(),
             new SimpleLabeledDatasetDataBuilder<>(featureExtractor, lbExtractor)
         )) {
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/pipeline/Pipeline.java b/modules/ml/src/main/java/org/apache/ignite/ml/pipeline/Pipeline.java
index 8bfcb34..1aeac6b 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/pipeline/Pipeline.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/pipeline/Pipeline.java
@@ -26,6 +26,7 @@
 import org.apache.ignite.ml.dataset.DatasetBuilder;
 import org.apache.ignite.ml.dataset.impl.cache.CacheBasedDatasetBuilder;
 import org.apache.ignite.ml.dataset.impl.local.LocalDatasetBuilder;
+import org.apache.ignite.ml.environment.LearningEnvironmentBuilder;
 import org.apache.ignite.ml.math.functions.IgniteBiFunction;
 import org.apache.ignite.ml.math.primitives.vector.Vector;
 import org.apache.ignite.ml.preprocessing.PreprocessingTrainer;
@@ -53,6 +54,9 @@
     /** Final trainer stage. */
     private DatasetTrainer finalStage;
 
+    /** Learning environment builder. */
+    private LearningEnvironmentBuilder envBuilder = LearningEnvironmentBuilder.defaultBuilder();
+
     /**
      * Adds feature extractor as a zero stage.
      *
@@ -110,6 +114,15 @@
     }
 
     /**
+     * Set learning environment builder.
+     *
+     * @param envBuilder Learning environment builder.
+     */
+    public void setEnvironmentBuilder(LearningEnvironmentBuilder envBuilder) {
+        this.envBuilder = envBuilder;
+    }
+
+    /**
      * Fits the pipeline to the input mock data.
      *
      * @param data Data.
@@ -132,6 +145,7 @@
         preprocessors.forEach(e -> {
 
             finalFeatureExtractor = e.fit(
+                envBuilder,
                 datasetBuilder,
                 finalFeatureExtractor
             );
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/preprocessing/PreprocessingTrainer.java b/modules/ml/src/main/java/org/apache/ignite/ml/preprocessing/PreprocessingTrainer.java
index b977864..89751eb 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/preprocessing/PreprocessingTrainer.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/preprocessing/PreprocessingTrainer.java
@@ -23,6 +23,7 @@
 import org.apache.ignite.ml.dataset.DatasetBuilder;
 import org.apache.ignite.ml.dataset.impl.cache.CacheBasedDatasetBuilder;
 import org.apache.ignite.ml.dataset.impl.local.LocalDatasetBuilder;
+import org.apache.ignite.ml.environment.LearningEnvironmentBuilder;
 import org.apache.ignite.ml.math.functions.IgniteBiFunction;
 
 /**
@@ -37,22 +38,39 @@
     /**
      * Fits preprocessor.
      *
+     * @param envBuilder Learning environment builder.
      * @param datasetBuilder Dataset builder.
      * @param basePreprocessor Base preprocessor.
      * @return Preprocessor.
      */
-    public IgniteBiFunction<K, V, R> fit(DatasetBuilder<K, V> datasetBuilder,
+    public IgniteBiFunction<K, V, R> fit(
+        LearningEnvironmentBuilder envBuilder,
+        DatasetBuilder<K, V> datasetBuilder,
         IgniteBiFunction<K, V, T> basePreprocessor);
 
     /**
      * Fits preprocessor.
      *
+     * @param datasetBuilder Dataset builder.
+     * @param basePreprocessor Base preprocessor.
+     * @return Preprocessor.
+     */
+    public default IgniteBiFunction<K, V, R> fit(
+        DatasetBuilder<K, V> datasetBuilder,
+        IgniteBiFunction<K, V, T> basePreprocessor) {
+        return fit(LearningEnvironmentBuilder.defaultBuilder(), datasetBuilder, basePreprocessor);
+    }
+
+    /**
+     * Fits preprocessor.
+     *
      * @param ignite Ignite instance.
      * @param cache Ignite cache.
      * @param basePreprocessor Base preprocessor.
      * @return Preprocessor.
      */
-    public default IgniteBiFunction<K, V, R> fit(Ignite ignite, IgniteCache<K, V> cache,
+    public default IgniteBiFunction<K, V, R> fit(
+        Ignite ignite, IgniteCache<K, V> cache,
         IgniteBiFunction<K, V, T> basePreprocessor) {
         return fit(
             new CacheBasedDatasetBuilder<>(ignite, cache),
@@ -63,12 +81,54 @@
     /**
      * Fits preprocessor.
      *
+     * @param envBuilder Learning environment builder.
+     * @param ignite Ignite instance.
+     * @param cache Ignite cache.
+     * @param basePreprocessor Base preprocessor.
+     * @return Preprocessor.
+     */
+    public default IgniteBiFunction<K, V, R> fit(
+        LearningEnvironmentBuilder envBuilder,
+        Ignite ignite, IgniteCache<K, V> cache,
+        IgniteBiFunction<K, V, T> basePreprocessor) {
+        return fit(
+            envBuilder,
+            new CacheBasedDatasetBuilder<>(ignite, cache),
+            basePreprocessor
+        );
+    }
+
+    /**
+     * Fits preprocessor.
+     *
      * @param data Data.
      * @param parts Number of partitions.
      * @param basePreprocessor Base preprocessor.
      * @return Preprocessor.
      */
-    public default IgniteBiFunction<K, V, R> fit(Map<K, V> data, int parts,
+    public default IgniteBiFunction<K, V, R> fit(
+        LearningEnvironmentBuilder envBuilder,
+        Map<K, V> data,
+        int parts,
+        IgniteBiFunction<K, V, T> basePreprocessor) {
+        return fit(
+            envBuilder,
+            new LocalDatasetBuilder<>(data, parts),
+            basePreprocessor
+        );
+    }
+
+    /**
+     * Fits preprocessor.
+     *
+     * @param data Data.
+     * @param parts Number of partitions.
+     * @param basePreprocessor Base preprocessor.
+     * @return Preprocessor.
+     */
+    public default IgniteBiFunction<K, V, R> fit(
+        Map<K, V> data,
+        int parts,
         IgniteBiFunction<K, V, T> basePreprocessor) {
         return fit(
             new LocalDatasetBuilder<>(data, parts),
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/preprocessing/binarization/BinarizationTrainer.java b/modules/ml/src/main/java/org/apache/ignite/ml/preprocessing/binarization/BinarizationTrainer.java
index ad8c90e7..039794c 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/preprocessing/binarization/BinarizationTrainer.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/preprocessing/binarization/BinarizationTrainer.java
@@ -18,6 +18,7 @@
 package org.apache.ignite.ml.preprocessing.binarization;
 
 import org.apache.ignite.ml.dataset.DatasetBuilder;
+import org.apache.ignite.ml.environment.LearningEnvironmentBuilder;
 import org.apache.ignite.ml.math.functions.IgniteBiFunction;
 import org.apache.ignite.ml.math.primitives.vector.Vector;
 import org.apache.ignite.ml.preprocessing.PreprocessingTrainer;
@@ -33,7 +34,9 @@
     private double threshold;
 
     /** {@inheritDoc} */
-    @Override public BinarizationPreprocessor<K, V> fit(DatasetBuilder<K, V> datasetBuilder,
+    @Override public BinarizationPreprocessor<K, V> fit(
+        LearningEnvironmentBuilder envBuilder,
+        DatasetBuilder<K, V> datasetBuilder,
         IgniteBiFunction<K, V, Vector> basePreprocessor) {
         return new BinarizationPreprocessor<>(threshold, basePreprocessor);
     }
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/preprocessing/encoding/EncoderTrainer.java b/modules/ml/src/main/java/org/apache/ignite/ml/preprocessing/encoding/EncoderTrainer.java
index d5668e4..14a509e 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/preprocessing/encoding/EncoderTrainer.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/preprocessing/encoding/EncoderTrainer.java
@@ -29,6 +29,7 @@
 import org.apache.ignite.ml.dataset.DatasetBuilder;
 import org.apache.ignite.ml.dataset.UpstreamEntry;
 import org.apache.ignite.ml.dataset.primitive.context.EmptyContext;
+import org.apache.ignite.ml.environment.LearningEnvironmentBuilder;
 import org.apache.ignite.ml.math.functions.IgniteBiFunction;
 import org.apache.ignite.ml.math.primitives.vector.Vector;
 import org.apache.ignite.ml.preprocessing.PreprocessingTrainer;
@@ -53,14 +54,17 @@
     private EncoderSortingStrategy encoderSortingStgy = EncoderSortingStrategy.FREQUENCY_DESC;
 
     /** {@inheritDoc} */
-    @Override public EncoderPreprocessor<K, V> fit(DatasetBuilder<K, V> datasetBuilder,
-                                                   IgniteBiFunction<K, V, Object[]> basePreprocessor) {
+    @Override public EncoderPreprocessor<K, V> fit(
+        LearningEnvironmentBuilder envBuilder,
+        DatasetBuilder<K, V> datasetBuilder,
+        IgniteBiFunction<K, V, Object[]> basePreprocessor) {
         if (handledIndices.isEmpty())
             throw new RuntimeException("Add indices of handled features");
 
         try (Dataset<EmptyContext, EncoderPartitionData> dataset = datasetBuilder.build(
-            (upstream, upstreamSize) -> new EmptyContext(),
-            (upstream, upstreamSize, ctx) -> {
+            envBuilder,
+            (env, upstream, upstreamSize) -> new EmptyContext(),
+            (env, upstream, upstreamSize, ctx) -> {
                 // This array will contain not null values for handled indices
                 Map<String, Integer>[] categoryFrequencies = null;
 
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/preprocessing/imputing/ImputerTrainer.java b/modules/ml/src/main/java/org/apache/ignite/ml/preprocessing/imputing/ImputerTrainer.java
index 090b0a4..e8920f3 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/preprocessing/imputing/ImputerTrainer.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/preprocessing/imputing/ImputerTrainer.java
@@ -23,8 +23,10 @@
 import java.util.Optional;
 import org.apache.ignite.ml.dataset.Dataset;
 import org.apache.ignite.ml.dataset.DatasetBuilder;
+import org.apache.ignite.ml.dataset.PartitionContextBuilder;
 import org.apache.ignite.ml.dataset.UpstreamEntry;
 import org.apache.ignite.ml.dataset.primitive.context.EmptyContext;
+import org.apache.ignite.ml.environment.LearningEnvironmentBuilder;
 import org.apache.ignite.ml.math.functions.IgniteBiFunction;
 import org.apache.ignite.ml.math.primitives.vector.Vector;
 import org.apache.ignite.ml.math.primitives.vector.VectorUtils;
@@ -43,11 +45,13 @@
     private ImputingStrategy imputingStgy = ImputingStrategy.MEAN;
 
     /** {@inheritDoc} */
-    @Override public ImputerPreprocessor<K, V> fit(DatasetBuilder<K, V> datasetBuilder,
+    @Override public ImputerPreprocessor<K, V> fit(LearningEnvironmentBuilder envBuilder, DatasetBuilder<K, V> datasetBuilder,
         IgniteBiFunction<K, V, Vector> basePreprocessor) {
+        PartitionContextBuilder<K, V, EmptyContext> builder = (env, upstream, upstreamSize) -> new EmptyContext();
         try (Dataset<EmptyContext, ImputerPartitionData> dataset = datasetBuilder.build(
-            (upstream, upstreamSize) -> new EmptyContext(),
-            (upstream, upstreamSize, ctx) -> {
+            envBuilder,
+            builder,
+            (env, upstream, upstreamSize, ctx) -> {
                 double[] sums = null;
                 int[] counts = null;
                 Map<Double, Integer>[] valuesByFreq = null;
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/preprocessing/maxabsscaling/MaxAbsScalerTrainer.java b/modules/ml/src/main/java/org/apache/ignite/ml/preprocessing/maxabsscaling/MaxAbsScalerTrainer.java
index c8b1dca..52acea3 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/preprocessing/maxabsscaling/MaxAbsScalerTrainer.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/preprocessing/maxabsscaling/MaxAbsScalerTrainer.java
@@ -21,6 +21,7 @@
 import org.apache.ignite.ml.dataset.DatasetBuilder;
 import org.apache.ignite.ml.dataset.UpstreamEntry;
 import org.apache.ignite.ml.dataset.primitive.context.EmptyContext;
+import org.apache.ignite.ml.environment.LearningEnvironmentBuilder;
 import org.apache.ignite.ml.math.functions.IgniteBiFunction;
 import org.apache.ignite.ml.math.primitives.vector.Vector;
 import org.apache.ignite.ml.preprocessing.PreprocessingTrainer;
@@ -33,11 +34,14 @@
  */
 public class MaxAbsScalerTrainer<K, V> implements PreprocessingTrainer<K, V, Vector, Vector> {
     /** {@inheritDoc} */
-    @Override public MaxAbsScalerPreprocessor<K, V> fit(DatasetBuilder<K, V> datasetBuilder,
+    @Override public MaxAbsScalerPreprocessor<K, V> fit(
+        LearningEnvironmentBuilder envBuilder,
+        DatasetBuilder<K, V> datasetBuilder,
         IgniteBiFunction<K, V, Vector> basePreprocessor) {
         try (Dataset<EmptyContext, MaxAbsScalerPartitionData> dataset = datasetBuilder.build(
-            (upstream, upstreamSize) -> new EmptyContext(),
-            (upstream, upstreamSize, ctx) -> {
+            envBuilder,
+            (env, upstream, upstreamSize) -> new EmptyContext(),
+            (env, upstream, upstreamSize, ctx) -> {
                 double[] maxAbs = null;
 
                 while (upstream.hasNext()) {
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/preprocessing/minmaxscaling/MinMaxScalerTrainer.java b/modules/ml/src/main/java/org/apache/ignite/ml/preprocessing/minmaxscaling/MinMaxScalerTrainer.java
index 6a39236..71f2afc 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/preprocessing/minmaxscaling/MinMaxScalerTrainer.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/preprocessing/minmaxscaling/MinMaxScalerTrainer.java
@@ -19,8 +19,10 @@
 
 import org.apache.ignite.ml.dataset.Dataset;
 import org.apache.ignite.ml.dataset.DatasetBuilder;
+import org.apache.ignite.ml.dataset.PartitionContextBuilder;
 import org.apache.ignite.ml.dataset.UpstreamEntry;
 import org.apache.ignite.ml.dataset.primitive.context.EmptyContext;
+import org.apache.ignite.ml.environment.LearningEnvironmentBuilder;
 import org.apache.ignite.ml.math.functions.IgniteBiFunction;
 import org.apache.ignite.ml.math.primitives.vector.Vector;
 import org.apache.ignite.ml.preprocessing.PreprocessingTrainer;
@@ -33,11 +35,15 @@
  */
 public class MinMaxScalerTrainer<K, V> implements PreprocessingTrainer<K, V, Vector, Vector> {
     /** {@inheritDoc} */
-    @Override public MinMaxScalerPreprocessor<K, V> fit(DatasetBuilder<K, V> datasetBuilder,
+    @Override public MinMaxScalerPreprocessor<K, V> fit(
+        LearningEnvironmentBuilder envBuilder,
+        DatasetBuilder<K, V> datasetBuilder,
         IgniteBiFunction<K, V, Vector> basePreprocessor) {
+        PartitionContextBuilder<K, V, EmptyContext> ctxBuilder = (env, upstream, upstreamSize) -> new EmptyContext();
         try (Dataset<EmptyContext, MinMaxScalerPartitionData> dataset = datasetBuilder.build(
-            (upstream, upstreamSize) -> new EmptyContext(),
-            (upstream, upstreamSize, ctx) -> {
+            envBuilder,
+            ctxBuilder,
+            (env, upstream, upstreamSize, ctx) -> {
                 double[] min = null;
                 double[] max = null;
 
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/preprocessing/normalization/NormalizationTrainer.java b/modules/ml/src/main/java/org/apache/ignite/ml/preprocessing/normalization/NormalizationTrainer.java
index b2dc6ed..08c4a68 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/preprocessing/normalization/NormalizationTrainer.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/preprocessing/normalization/NormalizationTrainer.java
@@ -18,6 +18,7 @@
 package org.apache.ignite.ml.preprocessing.normalization;
 
 import org.apache.ignite.ml.dataset.DatasetBuilder;
+import org.apache.ignite.ml.environment.LearningEnvironmentBuilder;
 import org.apache.ignite.ml.math.functions.IgniteBiFunction;
 import org.apache.ignite.ml.math.primitives.vector.Vector;
 import org.apache.ignite.ml.preprocessing.PreprocessingTrainer;
@@ -33,7 +34,9 @@
     private int p = 2;
 
     /** {@inheritDoc} */
-    @Override public NormalizationPreprocessor<K, V> fit(DatasetBuilder<K, V> datasetBuilder,
+    @Override public NormalizationPreprocessor<K, V> fit(
+        LearningEnvironmentBuilder envBuilder,
+        DatasetBuilder<K, V> datasetBuilder,
         IgniteBiFunction<K, V, Vector> basePreprocessor) {
         return new NormalizationPreprocessor<>(p, basePreprocessor);
     }
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/preprocessing/standardscaling/StandardScalerTrainer.java b/modules/ml/src/main/java/org/apache/ignite/ml/preprocessing/standardscaling/StandardScalerTrainer.java
index 5147b05..604f0b0 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/preprocessing/standardscaling/StandardScalerTrainer.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/preprocessing/standardscaling/StandardScalerTrainer.java
@@ -21,6 +21,7 @@
 import org.apache.ignite.ml.dataset.DatasetBuilder;
 import org.apache.ignite.ml.dataset.UpstreamEntry;
 import org.apache.ignite.ml.dataset.primitive.context.EmptyContext;
+import org.apache.ignite.ml.environment.LearningEnvironmentBuilder;
 import org.apache.ignite.ml.math.functions.IgniteBiFunction;
 import org.apache.ignite.ml.math.primitives.vector.Vector;
 import org.apache.ignite.ml.preprocessing.PreprocessingTrainer;
@@ -33,9 +34,10 @@
  */
 public class StandardScalerTrainer<K, V> implements PreprocessingTrainer<K, V, Vector, Vector> {
     /** {@inheritDoc} */
-    @Override public StandardScalerPreprocessor<K, V> fit(DatasetBuilder<K, V> datasetBuilder,
+    @Override public StandardScalerPreprocessor<K, V> fit(LearningEnvironmentBuilder envBuilder,
+        DatasetBuilder<K, V> datasetBuilder,
         IgniteBiFunction<K, V, Vector> basePreprocessor) {
-        StandardScalerData standardScalerData = computeSum(datasetBuilder, basePreprocessor);
+        StandardScalerData standardScalerData = computeSum(envBuilder, datasetBuilder, basePreprocessor);
 
         int n = standardScalerData.sum.length;
         long cnt = standardScalerData.cnt;
@@ -51,11 +53,13 @@
     }
 
     /** Computes sum, squared sum and row count. */
-    private StandardScalerData computeSum(DatasetBuilder<K, V> datasetBuilder,
+    private StandardScalerData computeSum(LearningEnvironmentBuilder envBuilder,
+        DatasetBuilder<K, V> datasetBuilder,
         IgniteBiFunction<K, V, Vector> basePreprocessor) {
         try (Dataset<EmptyContext, StandardScalerData> dataset = datasetBuilder.build(
-            (upstream, upstreamSize) -> new EmptyContext(),
-            (upstream, upstreamSize, ctx) -> {
+            envBuilder,
+            (env, upstream, upstreamSize) -> new EmptyContext(),
+            (env, upstream, upstreamSize, ctx) -> {
                 double[] sum = null;
                 double[] squaredSum = null;
                 long cnt = 0;
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/regressions/linear/LinearRegressionLSQRTrainer.java b/modules/ml/src/main/java/org/apache/ignite/ml/regressions/linear/LinearRegressionLSQRTrainer.java
index 5497177..dc245d2 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/regressions/linear/LinearRegressionLSQRTrainer.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/regressions/linear/LinearRegressionLSQRTrainer.java
@@ -50,6 +50,7 @@
 
         try (LSQROnHeap<K, V> lsqr = new LSQROnHeap<>(
             datasetBuilder,
+            envBuilder,
             new SimpleLabeledDatasetDataBuilder<>(
                 new FeatureExtractorWrapper<>(featureExtractor),
                 lbExtractor.andThen(e -> new double[] {e})
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/regressions/logistic/binomial/LogisticRegressionModel.java b/modules/ml/src/main/java/org/apache/ignite/ml/regressions/logistic/LogisticRegressionModel.java
similarity index 98%
rename from modules/ml/src/main/java/org/apache/ignite/ml/regressions/logistic/binomial/LogisticRegressionModel.java
rename to modules/ml/src/main/java/org/apache/ignite/ml/regressions/logistic/LogisticRegressionModel.java
index f206532..5cc44f8 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/regressions/logistic/binomial/LogisticRegressionModel.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/regressions/logistic/LogisticRegressionModel.java
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package org.apache.ignite.ml.regressions.logistic.binomial;
+package org.apache.ignite.ml.regressions.logistic;
 
 import java.io.Serializable;
 import java.util.Objects;
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/regressions/logistic/binomial/LogisticRegressionSGDTrainer.java b/modules/ml/src/main/java/org/apache/ignite/ml/regressions/logistic/LogisticRegressionSGDTrainer.java
similarity index 99%
rename from modules/ml/src/main/java/org/apache/ignite/ml/regressions/logistic/binomial/LogisticRegressionSGDTrainer.java
rename to modules/ml/src/main/java/org/apache/ignite/ml/regressions/logistic/LogisticRegressionSGDTrainer.java
index 47fa59d..cdbfe4c 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/regressions/logistic/binomial/LogisticRegressionSGDTrainer.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/regressions/logistic/LogisticRegressionSGDTrainer.java
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package org.apache.ignite.ml.regressions.logistic.binomial;
+package org.apache.ignite.ml.regressions.logistic;
 
 import java.io.Serializable;
 import java.util.Arrays;
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/regressions/logistic/multiclass/LogRegressionMultiClassModel.java b/modules/ml/src/main/java/org/apache/ignite/ml/regressions/logistic/multiclass/LogRegressionMultiClassModel.java
deleted file mode 100644
index a7c9118..0000000
--- a/modules/ml/src/main/java/org/apache/ignite/ml/regressions/logistic/multiclass/LogRegressionMultiClassModel.java
+++ /dev/null
@@ -1,115 +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.ml.regressions.logistic.multiclass;
-
-import java.io.Serializable;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.TreeMap;
-import org.apache.ignite.ml.Exportable;
-import org.apache.ignite.ml.Exporter;
-import org.apache.ignite.ml.Model;
-import org.apache.ignite.ml.math.primitives.vector.Vector;
-import org.apache.ignite.ml.regressions.logistic.binomial.LogisticRegressionModel;
-
-/** Base class for multi-classification model for set of Logistic Regression classifiers. */
-public class LogRegressionMultiClassModel implements Model<Vector, Double>, Exportable<LogRegressionMultiClassModel>, Serializable {
-    /** */
-    private static final long serialVersionUID = -114986533350117L;
-
-    /** List of models associated with each class. */
-    private Map<Double, LogisticRegressionModel> models;
-
-    /** */
-    public LogRegressionMultiClassModel() {
-        this.models = new HashMap<>();
-    }
-
-    /** {@inheritDoc} */
-    @Override public Double apply(Vector input) {
-        TreeMap<Double, Double> maxMargins = new TreeMap<>();
-
-        models.forEach((k, v) -> maxMargins.put(1.0 / (1.0 + Math.exp(-(input.dot(v.weights()) + v.intercept()))), k));
-
-        return maxMargins.lastEntry().getValue();
-    }
-
-    /** {@inheritDoc} */
-    @Override public <P> void saveModel(Exporter<LogRegressionMultiClassModel, P> exporter, P path) {
-        exporter.save(this, path);
-    }
-
-    /** {@inheritDoc} */
-    @Override public boolean equals(Object o) {
-        if (this == o)
-            return true;
-
-        if (o == null || getClass() != o.getClass())
-            return false;
-
-        LogRegressionMultiClassModel mdl = (LogRegressionMultiClassModel)o;
-
-        return Objects.equals(models, mdl.models);
-    }
-
-    /** {@inheritDoc} */
-    @Override public int hashCode() {
-        return Objects.hash(models);
-    }
-
-    /** {@inheritDoc} */
-    @Override public String toString() {
-        StringBuilder wholeStr = new StringBuilder();
-
-        models.forEach((clsLb, mdl) ->
-            wholeStr
-                .append("The class with label ")
-                .append(clsLb)
-                .append(" has classifier: ")
-                .append(mdl.toString())
-                .append(System.lineSeparator())
-        );
-
-        return wholeStr.toString();
-    }
-
-    /** {@inheritDoc} */
-    @Override public String toString(boolean pretty) {
-        return toString();
-    }
-
-    /**
-     * Adds a specific Log Regression binary classifier to the bunch of same classifiers.
-     *
-     * @param clsLb The class label for the added model.
-     * @param mdl The model.
-     */
-    public void add(double clsLb, LogisticRegressionModel mdl) {
-        models.put(clsLb, mdl);
-    }
-
-    /**
-     * @param clsLb Class label.
-     * @return model for class label if it exists.
-     */
-    public Optional<LogisticRegressionModel> getModel(Double clsLb) {
-        return Optional.ofNullable(models.get(clsLb));
-    }
-}
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/regressions/logistic/multiclass/LogRegressionMultiClassTrainer.java b/modules/ml/src/main/java/org/apache/ignite/ml/regressions/logistic/multiclass/LogRegressionMultiClassTrainer.java
deleted file mode 100644
index 71d54fa..0000000
--- a/modules/ml/src/main/java/org/apache/ignite/ml/regressions/logistic/multiclass/LogRegressionMultiClassTrainer.java
+++ /dev/null
@@ -1,268 +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.ml.regressions.logistic.multiclass;
-
-import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Optional;
-import java.util.Set;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-import org.apache.ignite.ml.dataset.Dataset;
-import org.apache.ignite.ml.dataset.DatasetBuilder;
-import org.apache.ignite.ml.dataset.PartitionDataBuilder;
-import org.apache.ignite.ml.dataset.primitive.context.EmptyContext;
-import org.apache.ignite.ml.math.functions.IgniteBiFunction;
-import org.apache.ignite.ml.math.primitives.vector.Vector;
-import org.apache.ignite.ml.nn.UpdatesStrategy;
-import org.apache.ignite.ml.optimization.updatecalculators.SimpleGDParameterUpdate;
-import org.apache.ignite.ml.optimization.updatecalculators.SimpleGDUpdateCalculator;
-import org.apache.ignite.ml.regressions.logistic.binomial.LogisticRegressionModel;
-import org.apache.ignite.ml.regressions.logistic.binomial.LogisticRegressionSGDTrainer;
-import org.apache.ignite.ml.structures.partition.LabelPartitionDataBuilderOnHeap;
-import org.apache.ignite.ml.structures.partition.LabelPartitionDataOnHeap;
-import org.apache.ignite.ml.trainers.SingleLabelDatasetTrainer;
-
-/**
- * All common parameters are shared with bunch of binary classification trainers.
- */
-public class LogRegressionMultiClassTrainer<P extends Serializable>
-    extends SingleLabelDatasetTrainer<LogRegressionMultiClassModel> {
-    /** Update strategy. */
-    private UpdatesStrategy updatesStgy = new UpdatesStrategy<>(
-        new SimpleGDUpdateCalculator(0.2),
-        SimpleGDParameterUpdate::sumLocal,
-        SimpleGDParameterUpdate::avg
-    );
-
-    /** Max number of iteration. */
-    private int amountOfIterations = 100;
-
-    /** Batch size. */
-    private int batchSize = 100;
-
-    /** Number of local iterations. */
-    private int amountOfLocIterations = 100;
-
-    /** Seed for random generator. */
-    private long seed = 1234L;
-
-    /**
-     * Trains model based on the specified data.
-     *
-     * @param datasetBuilder Dataset builder.
-     * @param featureExtractor Feature extractor.
-     * @param lbExtractor Label extractor.
-     * @return Model.
-     */
-    @Override public <K, V> LogRegressionMultiClassModel fit(DatasetBuilder<K, V> datasetBuilder,
-        IgniteBiFunction<K, V, Vector> featureExtractor,
-        IgniteBiFunction<K, V, Double> lbExtractor) {
-        List<Double> classes = extractClassLabels(datasetBuilder, lbExtractor);
-
-        return updateModel(null, datasetBuilder, featureExtractor, lbExtractor);
-    }
-
-    /** {@inheritDoc} */
-    @Override public <K, V> LogRegressionMultiClassModel updateModel(LogRegressionMultiClassModel newMdl,
-        DatasetBuilder<K, V> datasetBuilder, IgniteBiFunction<K, V, Vector> featureExtractor,
-        IgniteBiFunction<K, V, Double> lbExtractor) {
-
-        List<Double> classes = extractClassLabels(datasetBuilder, lbExtractor);
-
-        if(classes.isEmpty())
-            return getLastTrainedModelOrThrowEmptyDatasetException(newMdl);
-
-        LogRegressionMultiClassModel multiClsMdl = new LogRegressionMultiClassModel();
-
-        classes.forEach(clsLb -> {
-            LogisticRegressionSGDTrainer<?> trainer =
-                new LogisticRegressionSGDTrainer<>()
-                    .withBatchSize(batchSize)
-                    .withLocIterations(amountOfLocIterations)
-                    .withMaxIterations(amountOfIterations)
-                    .withSeed(seed);
-
-            IgniteBiFunction<K, V, Double> lbTransformer = (k, v) -> {
-                Double lb = lbExtractor.apply(k, v);
-
-                if (lb.equals(clsLb))
-                    return 1.0;
-                else
-                    return 0.0;
-            };
-
-            LogisticRegressionModel mdl = Optional.ofNullable(newMdl)
-                .flatMap(multiClassModel -> multiClassModel.getModel(clsLb))
-                .map(learnedModel -> trainer.update(learnedModel, datasetBuilder, featureExtractor, lbTransformer))
-                .orElseGet(() -> trainer.fit(datasetBuilder, featureExtractor, lbTransformer));
-
-            multiClsMdl.add(clsLb, mdl);
-        });
-
-        return multiClsMdl;
-    }
-
-    /** {@inheritDoc} */
-    @Override protected boolean checkState(LogRegressionMultiClassModel mdl) {
-        return true;
-    }
-
-    /** Iterates among dataset and collects class labels. */
-    private <K, V> List<Double> extractClassLabels(DatasetBuilder<K, V> datasetBuilder,
-        IgniteBiFunction<K, V, Double> lbExtractor) {
-        assert datasetBuilder != null;
-
-        PartitionDataBuilder<K, V, EmptyContext, LabelPartitionDataOnHeap> partDataBuilder = new LabelPartitionDataBuilderOnHeap<>(lbExtractor);
-
-        List<Double> res = new ArrayList<>();
-
-        try (Dataset<EmptyContext, LabelPartitionDataOnHeap> dataset = datasetBuilder.build(
-            (upstream, upstreamSize) -> new EmptyContext(),
-            partDataBuilder
-        )) {
-            final Set<Double> clsLabels = dataset.compute(data -> {
-                final Set<Double> locClsLabels = new HashSet<>();
-
-                final double[] lbs = data.getY();
-
-                for (double lb : lbs)
-                    locClsLabels.add(lb);
-
-                return locClsLabels;
-            }, (a, b) -> {
-                if (a == null)
-                    return b == null ? new HashSet<>() : b;
-                if (b == null)
-                    return a;
-                return Stream.of(a, b).flatMap(Collection::stream).collect(Collectors.toSet());
-            });
-
-            if (clsLabels != null)
-                res.addAll(clsLabels);
-
-        }
-        catch (Exception e) {
-            throw new RuntimeException(e);
-        }
-        return res;
-    }
-
-    /**
-     * Set up the regularization parameter.
-     *
-     * @param batchSize The size of learning batch.
-     * @return Trainer with new batch size parameter value.
-     */
-    public LogRegressionMultiClassTrainer withBatchSize(int batchSize) {
-        this.batchSize = batchSize;
-        return this;
-    }
-
-    /**
-     * Get the batch size.
-     *
-     * @return The parameter value.
-     */
-    public double getBatchSize() {
-        return batchSize;
-    }
-
-    /**
-     * Get the amount of outer iterations of SGD algorithm.
-     *
-     * @return The parameter value.
-     */
-    public int getAmountOfIterations() {
-        return amountOfIterations;
-    }
-
-    /**
-     * Set up the amount of outer iterations.
-     *
-     * @param amountOfIterations The parameter value.
-     * @return Trainer with new amountOfIterations parameter value.
-     */
-    public LogRegressionMultiClassTrainer withAmountOfIterations(int amountOfIterations) {
-        this.amountOfIterations = amountOfIterations;
-        return this;
-    }
-
-    /**
-     * Get the amount of local iterations.
-     *
-     * @return The parameter value.
-     */
-    public int getAmountOfLocIterations() {
-        return amountOfLocIterations;
-    }
-
-    /**
-     * Set up the amount of local iterations of SGD algorithm.
-     *
-     * @param amountOfLocIterations The parameter value.
-     * @return Trainer with new amountOfLocIterations parameter value.
-     */
-    public LogRegressionMultiClassTrainer withAmountOfLocIterations(int amountOfLocIterations) {
-        this.amountOfLocIterations = amountOfLocIterations;
-        return this;
-    }
-
-    /**
-     * Set up the random seed parameter.
-     *
-     * @param seed Seed for random generator.
-     * @return Trainer with new seed parameter value.
-     */
-    public LogRegressionMultiClassTrainer withSeed(long seed) {
-        this.seed = seed;
-        return this;
-    }
-
-    /**
-     * Get the seed for random generator.
-     *
-     * @return The parameter value.
-     */
-    public long seed() {
-        return seed;
-    }
-
-    /**
-     * Set up the updates strategy.
-     *
-     * @param updatesStgy Update strategy.
-     * @return Trainer with new update strategy parameter value.
-     */
-    public LogRegressionMultiClassTrainer withUpdatesStgy(UpdatesStrategy updatesStgy) {
-        this.updatesStgy = updatesStgy;
-        return this;
-    }
-
-    /**
-     * Get the update strategy.
-     *
-     * @return The parameter value.
-     */
-    public UpdatesStrategy getUpdatesStgy() {
-        return updatesStgy;
-    }
-}
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/regressions/logistic/multiclass/package-info.java b/modules/ml/src/main/java/org/apache/ignite/ml/regressions/logistic/multiclass/package-info.java
deleted file mode 100644
index 2e7b947..0000000
--- a/modules/ml/src/main/java/org/apache/ignite/ml/regressions/logistic/multiclass/package-info.java
+++ /dev/null
@@ -1,22 +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 description. -->
- * Contains multi-class logistic regression.
- */
-package org.apache.ignite.ml.regressions.logistic.multiclass;
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/structures/partition/LabelPartitionDataBuilderOnHeap.java b/modules/ml/src/main/java/org/apache/ignite/ml/structures/partition/LabelPartitionDataBuilderOnHeap.java
index 4fba028..5549b08 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/structures/partition/LabelPartitionDataBuilderOnHeap.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/structures/partition/LabelPartitionDataBuilderOnHeap.java
@@ -21,6 +21,7 @@
 import java.util.Iterator;
 import org.apache.ignite.ml.dataset.PartitionDataBuilder;
 import org.apache.ignite.ml.dataset.UpstreamEntry;
+import org.apache.ignite.ml.environment.LearningEnvironment;
 import org.apache.ignite.ml.math.functions.IgniteBiFunction;
 
 /**
@@ -48,8 +49,11 @@
     }
 
     /** {@inheritDoc} */
-    @Override public LabelPartitionDataOnHeap build(Iterator<UpstreamEntry<K, V>> upstreamData, long upstreamDataSize,
-                                        C ctx) {
+    @Override public LabelPartitionDataOnHeap build(
+        LearningEnvironment env,
+        Iterator<UpstreamEntry<K, V>> upstreamData,
+        long upstreamDataSize,
+        C ctx) {
         double[] y = new double[Math.toIntExact(upstreamDataSize)];
 
         int ptr = 0;
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/structures/partition/LabeledDatasetPartitionDataBuilderOnHeap.java b/modules/ml/src/main/java/org/apache/ignite/ml/structures/partition/LabeledDatasetPartitionDataBuilderOnHeap.java
index 0351037..0d054f6 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/structures/partition/LabeledDatasetPartitionDataBuilderOnHeap.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/structures/partition/LabeledDatasetPartitionDataBuilderOnHeap.java
@@ -21,6 +21,7 @@
 import java.util.Iterator;
 import org.apache.ignite.ml.dataset.PartitionDataBuilder;
 import org.apache.ignite.ml.dataset.UpstreamEntry;
+import org.apache.ignite.ml.environment.LearningEnvironment;
 import org.apache.ignite.ml.math.functions.IgniteBiFunction;
 import org.apache.ignite.ml.math.primitives.vector.Vector;
 import org.apache.ignite.ml.structures.LabeledVector;
@@ -57,8 +58,10 @@
     }
 
     /** {@inheritDoc} */
-    @Override public LabeledVectorSet<Double, LabeledVector> build(Iterator<UpstreamEntry<K, V>> upstreamData,
-                                                                   long upstreamDataSize, C ctx) {
+    @Override public LabeledVectorSet<Double, LabeledVector> build(
+        LearningEnvironment env,
+        Iterator<UpstreamEntry<K, V>> upstreamData,
+        long upstreamDataSize, C ctx) {
         int xCols = -1;
         double[][] x = null;
         double[] y = new double[Math.toIntExact(upstreamDataSize)];
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/svm/SVMLinearBinaryClassificationModel.java b/modules/ml/src/main/java/org/apache/ignite/ml/svm/SVMLinearClassificationModel.java
similarity index 87%
rename from modules/ml/src/main/java/org/apache/ignite/ml/svm/SVMLinearBinaryClassificationModel.java
rename to modules/ml/src/main/java/org/apache/ignite/ml/svm/SVMLinearClassificationModel.java
index f5d2b28..579fdb2 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/svm/SVMLinearBinaryClassificationModel.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/svm/SVMLinearClassificationModel.java
@@ -27,7 +27,7 @@
 /**
  * Base class for SVM linear classification model.
  */
-public class SVMLinearBinaryClassificationModel implements Model<Vector, Double>, Exportable<SVMLinearBinaryClassificationModel>, Serializable {
+public class SVMLinearClassificationModel implements Model<Vector, Double>, Exportable<SVMLinearClassificationModel>, Serializable {
     /** */
     private static final long serialVersionUID = -996984622291440226L;
 
@@ -44,7 +44,7 @@
     private double intercept;
 
     /** */
-    public SVMLinearBinaryClassificationModel(Vector weights, double intercept) {
+    public SVMLinearClassificationModel(Vector weights, double intercept) {
         this.weights = weights;
         this.intercept = intercept;
     }
@@ -55,7 +55,7 @@
      * @param isKeepingRawLabels The parameter value.
      * @return Model with new isKeepingRawLabels parameter value.
      */
-    public SVMLinearBinaryClassificationModel withRawLabels(boolean isKeepingRawLabels) {
+    public SVMLinearClassificationModel withRawLabels(boolean isKeepingRawLabels) {
         this.isKeepingRawLabels = isKeepingRawLabels;
         return this;
     }
@@ -66,7 +66,7 @@
      * @param threshold The parameter value.
      * @return Model with new threshold parameter value.
      */
-    public SVMLinearBinaryClassificationModel withThreshold(double threshold) {
+    public SVMLinearClassificationModel withThreshold(double threshold) {
         this.threshold = threshold;
         return this;
     }
@@ -77,7 +77,7 @@
      * @param weights The parameter value.
      * @return Model with new weights parameter value.
      */
-    public SVMLinearBinaryClassificationModel withWeights(Vector weights) {
+    public SVMLinearClassificationModel withWeights(Vector weights) {
         this.weights = weights;
         return this;
     }
@@ -88,7 +88,7 @@
      * @param intercept The parameter value.
      * @return Model with new intercept parameter value.
      */
-    public SVMLinearBinaryClassificationModel withIntercept(double intercept) {
+    public SVMLinearClassificationModel withIntercept(double intercept) {
         this.intercept = intercept;
         return this;
     }
@@ -139,7 +139,7 @@
     }
 
     /** {@inheritDoc} */
-    @Override public <P> void saveModel(Exporter<SVMLinearBinaryClassificationModel, P> exporter, P path) {
+    @Override public <P> void saveModel(Exporter<SVMLinearClassificationModel, P> exporter, P path) {
         exporter.save(this, path);
     }
 
@@ -150,7 +150,7 @@
         if (o == null || getClass() != o.getClass())
             return false;
 
-        SVMLinearBinaryClassificationModel mdl = (SVMLinearBinaryClassificationModel)o;
+        SVMLinearClassificationModel mdl = (SVMLinearClassificationModel)o;
 
         return Double.compare(mdl.intercept, intercept) == 0
             && Double.compare(mdl.threshold, threshold) == 0
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/svm/SVMLinearBinaryClassificationTrainer.java b/modules/ml/src/main/java/org/apache/ignite/ml/svm/SVMLinearClassificationTrainer.java
similarity index 91%
rename from modules/ml/src/main/java/org/apache/ignite/ml/svm/SVMLinearBinaryClassificationTrainer.java
rename to modules/ml/src/main/java/org/apache/ignite/ml/svm/SVMLinearClassificationTrainer.java
index 47666f4..67484ea 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/svm/SVMLinearBinaryClassificationTrainer.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/svm/SVMLinearClassificationTrainer.java
@@ -39,7 +39,7 @@
  * and 1 labels for two classes and makes binary classification. </p> The paper about this algorithm could be found
  * here https://arxiv.org/abs/1409.1458.
  */
-public class SVMLinearBinaryClassificationTrainer extends SingleLabelDatasetTrainer<SVMLinearBinaryClassificationModel> {
+public class SVMLinearClassificationTrainer extends SingleLabelDatasetTrainer<SVMLinearClassificationModel> {
     /** Amount of outer SDCA algorithm iterations. */
     private int amountOfIterations = 200;
 
@@ -60,14 +60,14 @@
      * @param lbExtractor Label extractor.
      * @return Model.
      */
-    @Override public <K, V> SVMLinearBinaryClassificationModel fit(DatasetBuilder<K, V> datasetBuilder,
+    @Override public <K, V> SVMLinearClassificationModel fit(DatasetBuilder<K, V> datasetBuilder,
         IgniteBiFunction<K, V, Vector> featureExtractor, IgniteBiFunction<K, V, Double> lbExtractor) {
 
         return updateModel(null, datasetBuilder, featureExtractor, lbExtractor);
     }
 
     /** {@inheritDoc} */
-    @Override protected <K, V> SVMLinearBinaryClassificationModel updateModel(SVMLinearBinaryClassificationModel mdl,
+    @Override protected <K, V> SVMLinearClassificationModel updateModel(SVMLinearClassificationModel mdl,
         DatasetBuilder<K, V> datasetBuilder, IgniteBiFunction<K, V, Vector> featureExtractor,
         IgniteBiFunction<K, V, Double> lbExtractor) {
 
@@ -89,7 +89,8 @@
         Vector weights;
 
         try (Dataset<EmptyContext, LabeledVectorSet<Double, LabeledVector>> dataset = datasetBuilder.build(
-            (upstream, upstreamSize) -> new EmptyContext(),
+            envBuilder,
+            (env, upstream, upstreamSize) -> new EmptyContext(),
             partDataBuilder
         )) {
             if (mdl == null) {
@@ -116,11 +117,11 @@
         } catch (Exception e) {
             throw new RuntimeException(e);
         }
-        return new SVMLinearBinaryClassificationModel(weights.viewPart(1, weights.size() - 1), weights.get(0));
+        return new SVMLinearClassificationModel(weights.viewPart(1, weights.size() - 1), weights.get(0));
     }
 
     /** {@inheritDoc} */
-    @Override protected boolean checkState(SVMLinearBinaryClassificationModel mdl) {
+    @Override protected boolean checkState(SVMLinearClassificationModel mdl) {
         return true;
     }
 
@@ -128,7 +129,7 @@
      * @param mdl Model.
      * @return vector of model weights with intercept.
      */
-    private Vector getStateVector(SVMLinearBinaryClassificationModel mdl) {
+    private Vector getStateVector(SVMLinearClassificationModel mdl) {
         double intercept = mdl.intercept();
         Vector weights = mdl.weights();
 
@@ -261,7 +262,7 @@
      * @param lambda The regularization parameter. Should be more than 0.0.
      * @return Trainer with new lambda parameter value.
      */
-    public SVMLinearBinaryClassificationTrainer withLambda(double lambda) {
+    public SVMLinearClassificationTrainer withLambda(double lambda) {
         assert lambda > 0.0;
         this.lambda = lambda;
         return this;
@@ -291,7 +292,7 @@
      * @param amountOfIterations The parameter value.
      * @return Trainer with new amountOfIterations parameter value.
      */
-    public SVMLinearBinaryClassificationTrainer withAmountOfIterations(int amountOfIterations) {
+    public SVMLinearClassificationTrainer withAmountOfIterations(int amountOfIterations) {
         this.amountOfIterations = amountOfIterations;
         return this;
     }
@@ -311,7 +312,7 @@
      * @param amountOfLocIterations The parameter value.
      * @return Trainer with new amountOfLocIterations parameter value.
      */
-    public SVMLinearBinaryClassificationTrainer withAmountOfLocIterations(int amountOfLocIterations) {
+    public SVMLinearClassificationTrainer withAmountOfLocIterations(int amountOfLocIterations) {
         this.amountOfLocIterations = amountOfLocIterations;
         return this;
     }
@@ -331,7 +332,7 @@
      * @param seed The parameter value.
      * @return Model with new seed parameter value.
      */
-    public SVMLinearBinaryClassificationTrainer withSeed(long seed) {
+    public SVMLinearClassificationTrainer withSeed(long seed) {
         this.seed = seed;
         return this;
     }
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/svm/SVMLinearMultiClassClassificationModel.java b/modules/ml/src/main/java/org/apache/ignite/ml/svm/SVMLinearMultiClassClassificationModel.java
deleted file mode 100644
index 46bf4b2..0000000
--- a/modules/ml/src/main/java/org/apache/ignite/ml/svm/SVMLinearMultiClassClassificationModel.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.ml.svm;
-
-import java.io.Serializable;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.TreeMap;
-import org.apache.ignite.ml.Exportable;
-import org.apache.ignite.ml.Exporter;
-import org.apache.ignite.ml.Model;
-import org.apache.ignite.ml.math.primitives.vector.Vector;
-
-/** Base class for multi-classification model for set of SVM classifiers. */
-public class SVMLinearMultiClassClassificationModel implements Model<Vector, Double>, Exportable<SVMLinearMultiClassClassificationModel>, Serializable {
-    /** */
-    private static final long serialVersionUID = -667986511191350227L;
-
-    /** List of models associated with each class. */
-    private Map<Double, SVMLinearBinaryClassificationModel> models;
-
-    /** */
-    public SVMLinearMultiClassClassificationModel() {
-        this.models = new HashMap<>();
-    }
-
-    /** {@inheritDoc} */
-    @Override public Double apply(Vector input) {
-        TreeMap<Double, Double> maxMargins = new TreeMap<>();
-
-        models.forEach((k, v) -> maxMargins.put(input.dot(v.weights()) + v.intercept(), k));
-
-        return maxMargins.lastEntry().getValue();
-    }
-
-    /** {@inheritDoc} */
-    @Override public <P> void saveModel(Exporter<SVMLinearMultiClassClassificationModel, P> exporter, P path) {
-        exporter.save(this, path);
-    }
-
-    /** {@inheritDoc} */
-    @Override public boolean equals(Object o) {
-        if (this == o)
-            return true;
-
-        if (o == null || getClass() != o.getClass())
-            return false;
-
-        SVMLinearMultiClassClassificationModel mdl = (SVMLinearMultiClassClassificationModel)o;
-
-        return Objects.equals(models, mdl.models);
-    }
-
-    /** {@inheritDoc} */
-    @Override public int hashCode() {
-        return Objects.hash(models);
-    }
-
-    /** {@inheritDoc} */
-    @Override public String toString() {
-        StringBuilder wholeStr = new StringBuilder();
-
-        models.forEach((clsLb, mdl) ->
-            wholeStr
-                .append("The class with label ")
-                .append(clsLb)
-                .append(" has classifier: ")
-                .append(mdl.toString())
-                .append(System.lineSeparator())
-        );
-
-        return wholeStr.toString();
-    }
-
-    /** {@inheritDoc} */
-    @Override public String toString(boolean pretty) {
-        return toString();
-    }
-
-    /**
-     * Adds a specific SVM binary classifier to the bunch of same classifiers.
-     *
-     * @param clsLb The class label for the added model.
-     * @param mdl The model.
-     */
-    public void add(double clsLb, SVMLinearBinaryClassificationModel mdl) {
-        models.put(clsLb, mdl);
-    }
-
-    /**
-     * @param clsLb Class label.
-     * @return model trained for target class if it exists.
-     */
-    public Optional<SVMLinearBinaryClassificationModel> getModelForClass(double clsLb) {
-        return Optional.of(models.get(clsLb));
-    }
-}
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/svm/SVMLinearMultiClassClassificationTrainer.java b/modules/ml/src/main/java/org/apache/ignite/ml/svm/SVMLinearMultiClassClassificationTrainer.java
deleted file mode 100644
index b161914..0000000
--- a/modules/ml/src/main/java/org/apache/ignite/ml/svm/SVMLinearMultiClassClassificationTrainer.java
+++ /dev/null
@@ -1,268 +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.ml.svm;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-import org.apache.ignite.ml.dataset.Dataset;
-import org.apache.ignite.ml.dataset.DatasetBuilder;
-import org.apache.ignite.ml.dataset.PartitionDataBuilder;
-import org.apache.ignite.ml.dataset.primitive.context.EmptyContext;
-import org.apache.ignite.ml.math.functions.IgniteBiFunction;
-import org.apache.ignite.ml.math.primitives.vector.Vector;
-import org.apache.ignite.ml.structures.partition.LabelPartitionDataBuilderOnHeap;
-import org.apache.ignite.ml.structures.partition.LabelPartitionDataOnHeap;
-import org.apache.ignite.ml.trainers.SingleLabelDatasetTrainer;
-
-/**
- * Base class for a soft-margin SVM linear multiclass-classification trainer based on the communication-efficient
- * distributed dual coordinate ascent algorithm (CoCoA) with hinge-loss function.
- *
- * All common parameters are shared with bunch of binary classification trainers.
- */
-public class SVMLinearMultiClassClassificationTrainer
-    extends SingleLabelDatasetTrainer<SVMLinearMultiClassClassificationModel> {
-    /** Amount of outer SDCA algorithm iterations. */
-    private int amountOfIterations = 20;
-
-    /** Amount of local SDCA algorithm iterations. */
-    private int amountOfLocIterations = 50;
-
-    /** Regularization parameter. */
-    private double lambda = 0.2;
-
-    /** The seed number. */
-    private long seed = 1234L;
-
-    /**
-     * Trains model based on the specified data.
-     *
-     * @param datasetBuilder Dataset builder.
-     * @param featureExtractor Feature extractor.
-     * @param lbExtractor Label extractor.
-     * @return Model.
-     */
-    @Override public <K, V> SVMLinearMultiClassClassificationModel fit(DatasetBuilder<K, V> datasetBuilder,
-        IgniteBiFunction<K, V, Vector> featureExtractor,
-        IgniteBiFunction<K, V, Double> lbExtractor) {
-        return updateModel(null, datasetBuilder, featureExtractor, lbExtractor);
-    }
-
-    /** {@inheritDoc} */
-    @Override public <K, V> SVMLinearMultiClassClassificationModel updateModel(
-        SVMLinearMultiClassClassificationModel mdl,
-        DatasetBuilder<K, V> datasetBuilder, IgniteBiFunction<K, V, Vector> featureExtractor,
-        IgniteBiFunction<K, V, Double> lbExtractor) {
-
-        List<Double> classes = extractClassLabels(datasetBuilder, lbExtractor);
-        if (classes.isEmpty())
-            return getLastTrainedModelOrThrowEmptyDatasetException(mdl);
-
-        SVMLinearMultiClassClassificationModel multiClsMdl = new SVMLinearMultiClassClassificationModel();
-
-        classes.forEach(clsLb -> {
-            SVMLinearBinaryClassificationTrainer trainer = new SVMLinearBinaryClassificationTrainer()
-                .withAmountOfIterations(this.getAmountOfIterations())
-                .withAmountOfLocIterations(this.getAmountOfLocIterations())
-                .withLambda(this.getLambda())
-                .withSeed(this.seed);
-
-            IgniteBiFunction<K, V, Double> lbTransformer = (k, v) -> {
-                Double lb = lbExtractor.apply(k, v);
-
-                if (lb.equals(clsLb))
-                    return 1.0;
-                else
-                    return 0.0;
-            };
-
-            SVMLinearBinaryClassificationModel updatedMdl;
-
-            if (mdl == null)
-                updatedMdl = learnNewModel(trainer, datasetBuilder, featureExtractor, lbTransformer);
-            else
-                updatedMdl = updateModel(mdl, clsLb, trainer, datasetBuilder, featureExtractor, lbTransformer);
-            multiClsMdl.add(clsLb, updatedMdl);
-        });
-
-        return multiClsMdl;
-    }
-
-    /** {@inheritDoc} */
-    @Override protected boolean checkState(SVMLinearMultiClassClassificationModel mdl) {
-        return true;
-    }
-
-    /**
-     * Trains model based on the specified data.
-     *
-     * @param svmTrainer Prepared SVM trainer.
-     * @param datasetBuilder Dataset builder.
-     * @param featureExtractor Feature extractor.
-     * @param lbExtractor Label extractor.
-     */
-    private <K, V> SVMLinearBinaryClassificationModel learnNewModel(SVMLinearBinaryClassificationTrainer svmTrainer,
-        DatasetBuilder<K, V> datasetBuilder, IgniteBiFunction<K, V, Vector> featureExtractor,
-        IgniteBiFunction<K, V, Double> lbExtractor) {
-
-        return svmTrainer.fit(datasetBuilder, featureExtractor, lbExtractor);
-    }
-
-    /**
-     * Updates already learned model or fit new model if there is no model for current class label.
-     *
-     * @param multiClsMdl Learning multi-class model.
-     * @param clsLb Current class label.
-     * @param svmTrainer Prepared SVM trainer.
-     * @param datasetBuilder Dataset builder.
-     * @param featureExtractor Feature extractor.
-     * @param lbExtractor Label extractor.
-     */
-    private <K, V> SVMLinearBinaryClassificationModel updateModel(SVMLinearMultiClassClassificationModel multiClsMdl,
-        Double clsLb, SVMLinearBinaryClassificationTrainer svmTrainer, DatasetBuilder<K, V> datasetBuilder,
-        IgniteBiFunction<K, V, Vector> featureExtractor, IgniteBiFunction<K, V, Double> lbExtractor) {
-
-        return multiClsMdl.getModelForClass(clsLb)
-            .map(learnedModel -> svmTrainer.update(learnedModel, datasetBuilder, featureExtractor, lbExtractor))
-            .orElseGet(() -> svmTrainer.fit(datasetBuilder, featureExtractor, lbExtractor));
-    }
-
-    /** Iterates among dataset and collects class labels. */
-    private <K, V> List<Double> extractClassLabels(DatasetBuilder<K, V> datasetBuilder,
-        IgniteBiFunction<K, V, Double> lbExtractor) {
-        assert datasetBuilder != null;
-
-        PartitionDataBuilder<K, V, EmptyContext, LabelPartitionDataOnHeap> partDataBuilder = new LabelPartitionDataBuilderOnHeap<>(lbExtractor);
-
-        List<Double> res = new ArrayList<>();
-
-        try (Dataset<EmptyContext, LabelPartitionDataOnHeap> dataset = datasetBuilder.build(
-            (upstream, upstreamSize) -> new EmptyContext(),
-            partDataBuilder
-        )) {
-            final Set<Double> clsLabels = dataset.compute(data -> {
-                final Set<Double> locClsLabels = new HashSet<>();
-
-                final double[] lbs = data.getY();
-
-                for (double lb : lbs)
-                    locClsLabels.add(lb);
-
-                return locClsLabels;
-            }, (a, b) -> {
-                if (a == null)
-                    return b == null ? new HashSet<>() : b;
-                if (b == null)
-                    return a;
-                return Stream.of(a, b).flatMap(Collection::stream).collect(Collectors.toSet());
-            });
-
-            if (clsLabels != null)
-                res.addAll(clsLabels);
-        } catch (Exception e) {
-            throw new RuntimeException(e);
-        }
-        return res;
-    }
-
-    /**
-     * Set up the regularization parameter.
-     *
-     * @param lambda The regularization parameter. Should be more than 0.0.
-     * @return Trainer with new lambda parameter value.
-     */
-    public SVMLinearMultiClassClassificationTrainer withLambda(double lambda) {
-        assert lambda > 0.0;
-        this.lambda = lambda;
-        return this;
-    }
-
-    /**
-     * Get the regularization lambda.
-     *
-     * @return The property value.
-     */
-    public double getLambda() {
-        return lambda;
-    }
-
-    /**
-     * Gets the amount of outer iterations of SCDA algorithm.
-     *
-     * @return The property value.
-     */
-    public int getAmountOfIterations() {
-        return amountOfIterations;
-    }
-
-    /**
-     * Set up the amount of outer iterations of SCDA algorithm.
-     *
-     * @param amountOfIterations The parameter value.
-     * @return Trainer with new amountOfIterations parameter value.
-     */
-    public SVMLinearMultiClassClassificationTrainer withAmountOfIterations(int amountOfIterations) {
-        this.amountOfIterations = amountOfIterations;
-        return this;
-    }
-
-    /**
-     * Gets the amount of local iterations of SCDA algorithm.
-     *
-     * @return The property value.
-     */
-    public int getAmountOfLocIterations() {
-        return amountOfLocIterations;
-    }
-
-    /**
-     * Set up the amount of local iterations of SCDA algorithm.
-     *
-     * @param amountOfLocIterations The parameter value.
-     * @return Trainer with new amountOfLocIterations parameter value.
-     */
-    public SVMLinearMultiClassClassificationTrainer withAmountOfLocIterations(int amountOfLocIterations) {
-        this.amountOfLocIterations = amountOfLocIterations;
-        return this;
-    }
-
-    /**
-     * Gets the seed number.
-     *
-     * @return The property value.
-     */
-    public long getSeed() {
-        return seed;
-    }
-
-    /**
-     * Set up the seed.
-     *
-     * @param seed The parameter value.
-     * @return Model with new seed parameter value.
-     */
-    public SVMLinearMultiClassClassificationTrainer withSeed(long seed) {
-        this.seed = seed;
-        return this;
-    }
-}
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/trainers/DatasetTrainer.java b/modules/ml/src/main/java/org/apache/ignite/ml/trainers/DatasetTrainer.java
index f321744..dabf66a 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/trainers/DatasetTrainer.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/trainers/DatasetTrainer.java
@@ -26,6 +26,7 @@
 import org.apache.ignite.ml.dataset.impl.cache.CacheBasedDatasetBuilder;
 import org.apache.ignite.ml.dataset.impl.local.LocalDatasetBuilder;
 import org.apache.ignite.ml.environment.LearningEnvironment;
+import org.apache.ignite.ml.environment.LearningEnvironmentBuilder;
 import org.apache.ignite.ml.environment.logging.MLLogger;
 import org.apache.ignite.ml.math.functions.IgniteBiFunction;
 import org.apache.ignite.ml.math.primitives.vector.Vector;
@@ -38,8 +39,11 @@
  * @param <L> Type of a label.
  */
 public abstract class DatasetTrainer<M extends Model, L> {
+    /** Learning environment builder. */
+    protected LearningEnvironmentBuilder envBuilder = LearningEnvironmentBuilder.defaultBuilder();
+
     /** Learning Environment. */
-    protected LearningEnvironment environment = LearningEnvironment.DEFAULT;
+    protected LearningEnvironment environment = envBuilder.buildForTrainer();
 
     /**
      * Trains model based on the specified data.
@@ -289,11 +293,25 @@
     }
 
     /**
-     * Sets learning Environment
-     * @param environment Environment.
+     * Changes learning Environment.
+     *
+     * @param envBuilder Learning environment builder.
      */
-    public void setEnvironment(LearningEnvironment environment) {
-        this.environment = environment;
+    // TODO: IGNITE-10441 Think about more elegant ways to perform fluent API.
+    public DatasetTrainer<M, L> withEnvironmentBuilder(LearningEnvironmentBuilder envBuilder) {
+        this.envBuilder  = envBuilder;
+        this.environment = envBuilder.buildForTrainer();
+
+        return this;
+    }
+
+    /**
+     * Get learning environment.
+     *
+     * @return Learning environment.
+     */
+    public LearningEnvironment learningEnvironment() {
+        return environment;
     }
 
     /**
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/trainers/TrainerTransformers.java b/modules/ml/src/main/java/org/apache/ignite/ml/trainers/TrainerTransformers.java
index 05504c3..1019a39 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/trainers/TrainerTransformers.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/trainers/TrainerTransformers.java
@@ -17,21 +17,15 @@
 
 package org.apache.ignite.ml.trainers;
 
-import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Random;
 import java.util.stream.Collectors;
 import java.util.stream.IntStream;
-import org.apache.ignite.lang.IgniteBiPredicate;
 import org.apache.ignite.ml.Model;
 import org.apache.ignite.ml.composition.ModelsComposition;
 import org.apache.ignite.ml.composition.predictionsaggregator.PredictionsAggregator;
-import org.apache.ignite.ml.dataset.Dataset;
 import org.apache.ignite.ml.dataset.DatasetBuilder;
-import org.apache.ignite.ml.dataset.PartitionContextBuilder;
-import org.apache.ignite.ml.dataset.PartitionDataBuilder;
-import org.apache.ignite.ml.dataset.UpstreamTransformerChain;
 import org.apache.ignite.ml.environment.LearningEnvironment;
 import org.apache.ignite.ml.environment.logging.MLLogger;
 import org.apache.ignite.ml.environment.parallelism.Promise;
@@ -49,7 +43,7 @@
  */
 public class TrainerTransformers {
     /**
-     * Add bagging logic to a given trainer.
+     * Add bagging logic to a given trainer. No features bootstrapping is done.
      *
      * @param ensembleSize Size of ensemble.
      * @param subsampleRatio Subsample ratio to whole dataset.
@@ -63,9 +57,8 @@
         int ensembleSize,
         double subsampleRatio,
         PredictionsAggregator aggregator) {
-        return makeBagged(trainer, ensembleSize, subsampleRatio, -1, -1, aggregator, new Random().nextLong());
+        return makeBagged(trainer, ensembleSize, subsampleRatio, -1, -1, aggregator);
     }
-
     /**
      * Add bagging logic to a given trainer.
      *
@@ -74,31 +67,23 @@
      * @param aggregator Aggregator.
      * @param featureVectorSize Feature vector dimensionality.
      * @param featuresSubspaceDim Feature subspace dimensionality.
-     * @param transformationSeed Transformations seed.
      * @param <M> Type of one model in ensemble.
      * @param <L> Type of labels.
      * @return Bagged trainer.
      */
-    // TODO: IGNITE-10296: Inject capabilities of seeding through learning environment (remove).
     public static <M extends Model<Vector, Double>, L> DatasetTrainer<ModelsComposition, L> makeBagged(
         DatasetTrainer<M, L> trainer,
         int ensembleSize,
         double subsampleRatio,
         int featureVectorSize,
         int featuresSubspaceDim,
-        PredictionsAggregator aggregator,
-        Long transformationSeed) {
+        PredictionsAggregator aggregator) {
         return new DatasetTrainer<ModelsComposition, L>() {
             /** {@inheritDoc} */
             @Override public <K, V> ModelsComposition fit(
                 DatasetBuilder<K, V> datasetBuilder,
                 IgniteBiFunction<K, V, Vector> featureExtractor,
                 IgniteBiFunction<K, V, L> lbExtractor) {
-                datasetBuilder.upstreamTransformersChain().setSeed(
-                    transformationSeed == null
-                        ? new Random().nextLong()
-                        : transformationSeed);
-
                 return runOnEnsemble(
                     (db, i, fe) -> (() -> trainer.fit(db, fe, lbExtractor)),
                     datasetBuilder,
@@ -172,21 +157,17 @@
         log.log(MLLogger.VerboseLevel.LOW, "Start learning.");
 
         List<int[]> mappings = null;
-        if (featuresVectorSize > 0) {
+        if (featuresVectorSize > 0 && featureSubspaceDim != featuresVectorSize) {
             mappings = IntStream.range(0, ensembleSize).mapToObj(
                 modelIdx -> getMapping(
                     featuresVectorSize,
                     featureSubspaceDim,
-                    datasetBuilder.upstreamTransformersChain().seed() + modelIdx))
+                    environment.randomNumbersGenerator().nextLong() + modelIdx))
                 .collect(Collectors.toList());
         }
 
         Long startTs = System.currentTimeMillis();
 
-        datasetBuilder
-            .upstreamTransformersChain()
-            .addUpstreamTransformer(new BaggingUpstreamTransformer<>(subsampleRatio));
-
         List<IgniteSupplier<M>> tasks = new ArrayList<>();
         List<IgniteBiFunction<K, V, Vector>> extractors = new ArrayList<>();
         if (mappings != null) {
@@ -195,10 +176,8 @@
         }
 
         for (int i = 0; i < ensembleSize; i++) {
-            UpstreamTransformerChain<K, V> newChain = Utils.copy(datasetBuilder.upstreamTransformersChain());
-            DatasetBuilder<K, V> newBuilder = withNewChain(datasetBuilder, newChain);
-            int j = i;
-            newChain.modifySeed(s -> s * s + j);
+            DatasetBuilder<K, V> newBuilder =
+                datasetBuilder.withUpstreamTransformer(BaggingUpstreamTransformer.builder(subsampleRatio, i));
             tasks.add(
                 trainingTaskGenerator.apply(newBuilder, i, mappings != null ? extractors.get(i) : extractor));
         }
@@ -338,37 +317,4 @@
             return mapping;
         }
     }
-
-    /**
-     * Creates new dataset builder which is delegate of a given dataset builder in everything except
-     * new transformations chain.
-     *
-     * @param builder Initial builder.
-     * @param chain New chain.
-     * @param <K> Type of keys.
-     * @param <V> Type of values.
-     * @return new dataset builder which is delegate of a given dataset builder in everything except
-     * new transformations chain.
-     */
-    private static <K, V> DatasetBuilder<K, V> withNewChain(
-        DatasetBuilder<K, V> builder,
-        UpstreamTransformerChain<K, V> chain) {
-        return new DatasetBuilder<K, V>() {
-            /** {@inheritDoc} */
-            @Override public <C extends Serializable, D extends AutoCloseable> Dataset<C, D> build(
-                PartitionContextBuilder<K, V, C> partCtxBuilder, PartitionDataBuilder<K, V, C, D> partDataBuilder) {
-                return builder.build(partCtxBuilder, partDataBuilder);
-            }
-
-            /** {@inheritDoc} */
-            @Override public UpstreamTransformerChain<K, V> upstreamTransformersChain() {
-                return chain;
-            }
-
-            /** {@inheritDoc} */
-            @Override public DatasetBuilder<K, V> withFilter(IgniteBiPredicate<K, V> filterToAdd) {
-                return builder.withFilter(filterToAdd);
-            }
-        };
-    }
 }
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/trainers/transformers/BaggingUpstreamTransformer.java b/modules/ml/src/main/java/org/apache/ignite/ml/trainers/transformers/BaggingUpstreamTransformer.java
index f935ebd..7f45fdd 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/trainers/transformers/BaggingUpstreamTransformer.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/trainers/transformers/BaggingUpstreamTransformer.java
@@ -17,12 +17,12 @@
 
 package org.apache.ignite.ml.trainers.transformers;
 
-import java.util.Random;
 import java.util.stream.Stream;
 import org.apache.commons.math3.distribution.PoissonDistribution;
 import org.apache.commons.math3.random.Well19937c;
 import org.apache.ignite.ml.dataset.UpstreamEntry;
 import org.apache.ignite.ml.dataset.UpstreamTransformer;
+import org.apache.ignite.ml.dataset.UpstreamTransformerBuilder;
 
 /**
  * This class encapsulates the logic needed to do bagging (bootstrap aggregating) by features.
@@ -33,22 +33,43 @@
  * @param <V> Type of upstream values.
  */
 public class BaggingUpstreamTransformer<K, V> implements UpstreamTransformer<K, V> {
+    /** Serial version uid. */
+    private static final long serialVersionUID = -913152523469994149L;
+
     /** Ratio of subsample to entire upstream size */
     private double subsampleRatio;
 
+    /** Seed used for generating poisson distribution. */
+    private long seed;
+
+    /**
+     * Get builder of {@link BaggingUpstreamTransformer} for a model with a specified index in ensemble.
+     *
+     * @param subsampleRatio Subsample ratio.
+     * @param mdlIdx Index of model in ensemble.
+     * @param <K> Type of upstream keys.
+     * @param <V> Type of upstream values.
+     * @return Builder of {@link BaggingUpstreamTransformer}.
+     */
+    public static <K, V> UpstreamTransformerBuilder<K, V> builder(double subsampleRatio, int mdlIdx) {
+        return env -> new BaggingUpstreamTransformer<>(env.randomNumbersGenerator().nextLong() + mdlIdx, subsampleRatio);
+    }
+
     /**
      * Construct instance of this transformer with a given subsample ratio.
      *
+     * @param seed Seed used for generating poisson distribution which in turn used to make subsamples.
      * @param subsampleRatio Subsample ratio.
      */
-    public BaggingUpstreamTransformer(double subsampleRatio) {
+    public BaggingUpstreamTransformer(long seed, double subsampleRatio) {
         this.subsampleRatio = subsampleRatio;
+        this.seed = seed;
     }
 
     /** {@inheritDoc} */
-    @Override public Stream<UpstreamEntry<K, V>> transform(Random rnd, Stream<UpstreamEntry<K, V>> upstream) {
+    @Override public Stream<UpstreamEntry<K, V>> transform(Stream<UpstreamEntry<K, V>> upstream) {
         PoissonDistribution poisson = new PoissonDistribution(
-            new Well19937c(rnd.nextLong()),
+            new Well19937c(seed),
             subsampleRatio,
             PoissonDistribution.DEFAULT_EPSILON,
             PoissonDistribution.DEFAULT_MAX_ITERATIONS);
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/tree/DecisionTree.java b/modules/ml/src/main/java/org/apache/ignite/ml/tree/DecisionTree.java
index 482c9389..510d26e 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/tree/DecisionTree.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/tree/DecisionTree.java
@@ -24,6 +24,7 @@
 import org.apache.ignite.ml.dataset.DatasetBuilder;
 import org.apache.ignite.ml.dataset.primitive.builder.context.EmptyContextBuilder;
 import org.apache.ignite.ml.dataset.primitive.context.EmptyContext;
+import org.apache.ignite.ml.environment.LearningEnvironmentBuilder;
 import org.apache.ignite.ml.math.functions.IgniteBiFunction;
 import org.apache.ignite.ml.math.primitives.vector.Vector;
 import org.apache.ignite.ml.trainers.DatasetTrainer;
@@ -76,6 +77,7 @@
     @Override public <K, V> DecisionTreeNode fit(DatasetBuilder<K, V> datasetBuilder,
         IgniteBiFunction<K, V, Vector> featureExtractor, IgniteBiFunction<K, V, Double> lbExtractor) {
         try (Dataset<EmptyContext, DecisionTreeData> dataset = datasetBuilder.build(
+            envBuilder,
             new EmptyContextBuilder<>(),
             new DecisionTreeDataBuilder<>(featureExtractor, lbExtractor, usingIdx)
         )) {
@@ -108,6 +110,11 @@
         return true;
     }
 
+    /** {@inheritDoc} */
+    @Override public DecisionTree<T> withEnvironmentBuilder(LearningEnvironmentBuilder envBuilder) {
+        return (DecisionTree<T>)super.withEnvironmentBuilder(envBuilder);
+    }
+
     /** */
     public <K,V> DecisionTreeNode fit(Dataset<EmptyContext, DecisionTreeData> dataset) {
         return split(dataset, e -> true, 0, getImpurityMeasureCalculator(dataset));
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/tree/DecisionTreeClassificationTrainer.java b/modules/ml/src/main/java/org/apache/ignite/ml/tree/DecisionTreeClassificationTrainer.java
index 58552f4..321e65f 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/tree/DecisionTreeClassificationTrainer.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/tree/DecisionTreeClassificationTrainer.java
@@ -23,6 +23,7 @@
 import java.util.Set;
 import org.apache.ignite.ml.dataset.Dataset;
 import org.apache.ignite.ml.dataset.primitive.context.EmptyContext;
+import org.apache.ignite.ml.environment.LearningEnvironmentBuilder;
 import org.apache.ignite.ml.tree.data.DecisionTreeData;
 import org.apache.ignite.ml.tree.impurity.ImpurityMeasureCalculator;
 import org.apache.ignite.ml.tree.impurity.gini.GiniImpurityMeasure;
@@ -129,4 +130,9 @@
 
         return new GiniImpurityMeasureCalculator(encoder, usingIdx);
     }
+
+    /** {@inheritDoc} */
+    @Override public DecisionTreeClassificationTrainer withEnvironmentBuilder(LearningEnvironmentBuilder envBuilder) {
+        return (DecisionTreeClassificationTrainer)super.withEnvironmentBuilder(envBuilder);
+    }
 }
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/tree/DecisionTreeRegressionTrainer.java b/modules/ml/src/main/java/org/apache/ignite/ml/tree/DecisionTreeRegressionTrainer.java
index ea57bcc..2b259f2 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/tree/DecisionTreeRegressionTrainer.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/tree/DecisionTreeRegressionTrainer.java
@@ -19,6 +19,7 @@
 
 import org.apache.ignite.ml.dataset.Dataset;
 import org.apache.ignite.ml.dataset.primitive.context.EmptyContext;
+import org.apache.ignite.ml.environment.LearningEnvironmentBuilder;
 import org.apache.ignite.ml.tree.data.DecisionTreeData;
 import org.apache.ignite.ml.tree.impurity.ImpurityMeasureCalculator;
 import org.apache.ignite.ml.tree.impurity.mse.MSEImpurityMeasure;
@@ -69,4 +70,9 @@
 
         return new MSEImpurityMeasureCalculator(usingIdx);
     }
+
+    /** {@inheritDoc} */
+    @Override public DecisionTreeRegressionTrainer withEnvironmentBuilder(LearningEnvironmentBuilder envBuilder) {
+        return (DecisionTreeRegressionTrainer)super.withEnvironmentBuilder(envBuilder);
+    }
 }
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/tree/boosting/GDBBinaryClassifierOnTreesTrainer.java b/modules/ml/src/main/java/org/apache/ignite/ml/tree/boosting/GDBBinaryClassifierOnTreesTrainer.java
index b99dc2f..b19652d 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/tree/boosting/GDBBinaryClassifierOnTreesTrainer.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/tree/boosting/GDBBinaryClassifierOnTreesTrainer.java
@@ -19,6 +19,7 @@
 
 import org.apache.ignite.ml.composition.boosting.GDBBinaryClassifierTrainer;
 import org.apache.ignite.ml.composition.boosting.GDBLearningStrategy;
+import org.apache.ignite.ml.environment.LearningEnvironmentBuilder;
 import org.apache.ignite.ml.tree.DecisionTreeRegressionTrainer;
 import org.jetbrains.annotations.NotNull;
 
@@ -61,6 +62,11 @@
         return new GDBOnTreesLearningStrategy(usingIdx);
     }
 
+    /** {@inheritDoc} */
+    @Override public GDBBinaryClassifierOnTreesTrainer withEnvironmentBuilder(LearningEnvironmentBuilder envBuilder) {
+        return (GDBBinaryClassifierOnTreesTrainer)super.withEnvironmentBuilder(envBuilder);
+    }
+
     /**
      * Set useIndex parameter and returns trainer instance.
      *
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/tree/boosting/GDBOnTreesLearningStrategy.java b/modules/ml/src/main/java/org/apache/ignite/ml/tree/boosting/GDBOnTreesLearningStrategy.java
index caac168..71e840c 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/tree/boosting/GDBOnTreesLearningStrategy.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/tree/boosting/GDBOnTreesLearningStrategy.java
@@ -70,6 +70,7 @@
             externalLbToInternalMapping, loss, datasetBuilder, featureExtractor, lbExtractor);
 
         try (Dataset<EmptyContext, DecisionTreeData> dataset = datasetBuilder.build(
+            envBuilder,
             new EmptyContextBuilder<>(),
             new DecisionTreeDataBuilder<>(featureExtractor, lbExtractor, useIdx)
         )) {
@@ -95,7 +96,7 @@
                 long startTs = System.currentTimeMillis();
                 models.add(decisionTreeTrainer.fit(dataset));
                 double learningTime = (double)(System.currentTimeMillis() - startTs) / 1000.0;
-                environment.logger(getClass()).log(MLLogger.VerboseLevel.LOW, "One model training time was %.2fs", learningTime);
+                trainerEnvironment.logger(getClass()).log(MLLogger.VerboseLevel.LOW, "One model training time was %.2fs", learningTime);
             }
         }
         catch (Exception e) {
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/tree/boosting/GDBRegressionOnTreesTrainer.java b/modules/ml/src/main/java/org/apache/ignite/ml/tree/boosting/GDBRegressionOnTreesTrainer.java
index b6c0b48..9c588ce 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/tree/boosting/GDBRegressionOnTreesTrainer.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/tree/boosting/GDBRegressionOnTreesTrainer.java
@@ -19,6 +19,7 @@
 
 import org.apache.ignite.ml.composition.boosting.GDBLearningStrategy;
 import org.apache.ignite.ml.composition.boosting.GDBRegressionTrainer;
+import org.apache.ignite.ml.environment.LearningEnvironmentBuilder;
 import org.apache.ignite.ml.tree.DecisionTreeRegressionTrainer;
 import org.jetbrains.annotations.NotNull;
 
@@ -120,4 +121,9 @@
     @Override protected GDBLearningStrategy getLearningStrategy() {
         return new GDBOnTreesLearningStrategy(usingIdx);
     }
+
+    /** {@inheritDoc} */
+    @Override public GDBRegressionOnTreesTrainer withEnvironmentBuilder(LearningEnvironmentBuilder envBuilder) {
+        return (GDBRegressionOnTreesTrainer)super.withEnvironmentBuilder(envBuilder);
+    }
 }
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/tree/data/DecisionTreeDataBuilder.java b/modules/ml/src/main/java/org/apache/ignite/ml/tree/data/DecisionTreeDataBuilder.java
index 4436b07..1378120 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/tree/data/DecisionTreeDataBuilder.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/tree/data/DecisionTreeDataBuilder.java
@@ -21,6 +21,7 @@
 import java.util.Iterator;
 import org.apache.ignite.ml.dataset.PartitionDataBuilder;
 import org.apache.ignite.ml.dataset.UpstreamEntry;
+import org.apache.ignite.ml.environment.LearningEnvironment;
 import org.apache.ignite.ml.math.functions.IgniteBiFunction;
 import org.apache.ignite.ml.math.primitives.vector.Vector;
 
@@ -60,7 +61,11 @@
     }
 
     /** {@inheritDoc} */
-    @Override public DecisionTreeData build(Iterator<UpstreamEntry<K, V>> upstreamData, long upstreamDataSize, C ctx) {
+    @Override public DecisionTreeData build(
+        LearningEnvironment envBuilder,
+        Iterator<UpstreamEntry<K, V>> upstreamData,
+        long upstreamDataSize,
+        C ctx) {
         double[][] features = new double[Math.toIntExact(upstreamDataSize)][];
         double[] labels = new double[Math.toIntExact(upstreamDataSize)];
 
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/tree/randomforest/RandomForestTrainer.java b/modules/ml/src/main/java/org/apache/ignite/ml/tree/randomforest/RandomForestTrainer.java
index 72a97c4..3ee90cb 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/tree/randomforest/RandomForestTrainer.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/tree/randomforest/RandomForestTrainer.java
@@ -114,6 +114,7 @@
         IgniteBiFunction<K, V, Vector> featureExtractor, IgniteBiFunction<K, V, Double> lbExtractor) {
         List<TreeRoot> models = null;
         try (Dataset<EmptyContext, BootstrappedDatasetPartition> dataset = datasetBuilder.build(
+            envBuilder,
             new EmptyContextBuilder<>(),
             new BootstrappedDatasetBuilder<>(featureExtractor, lbExtractor, amountOfTrees, subSampleSize))) {
 
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/regressions/logistic/binomial/package-info.java b/modules/ml/src/main/java/org/apache/ignite/ml/util/plugin/MLPlugin.java
similarity index 77%
copy from modules/ml/src/main/java/org/apache/ignite/ml/regressions/logistic/binomial/package-info.java
copy to modules/ml/src/main/java/org/apache/ignite/ml/util/plugin/MLPlugin.java
index d32b1ee..81c42e2 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/regressions/logistic/binomial/package-info.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/util/plugin/MLPlugin.java
@@ -15,8 +15,16 @@
  * limitations under the License.
  */
 
+package org.apache.ignite.ml.util.plugin;
+
+import org.apache.ignite.plugin.IgnitePlugin;
+
 /**
- * <!-- Package description. -->
- * Contains binomial logistic regression.
+ * ML plugin.
  */
-package org.apache.ignite.ml.regressions.logistic.binomial;
\ No newline at end of file
+class MLPlugin implements IgnitePlugin {
+    /**
+     * Creates a new instance of ML inference plugin.
+     */
+    MLPlugin() {}
+}
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/util/plugin/MLPluginConfiguration.java b/modules/ml/src/main/java/org/apache/ignite/ml/util/plugin/MLPluginConfiguration.java
new file mode 100644
index 0000000..58fe601
--- /dev/null
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/util/plugin/MLPluginConfiguration.java
@@ -0,0 +1,77 @@
+/*
+ * 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.ml.util.plugin;
+
+import org.apache.ignite.plugin.PluginConfiguration;
+
+/**
+ * Configuration of ML plugin that defines which ML inference services should be start up on Ignite startup.
+ */
+public class MLPluginConfiguration implements PluginConfiguration {
+    /** Model storage should be created on startup. */
+    private boolean withMdlStorage;
+
+    /** Model descriptor storage should be created on startup. */
+    private boolean withMdlDescStorage;
+
+    /** Number of backups in model storage cache. */
+    private Integer mdlStorageBackups;
+
+    /** Number of backups in model descriptor storage cache. */
+    private Integer mdlDescStorageBackups;
+
+    /** */
+    public boolean isWithMdlStorage() {
+        return withMdlStorage;
+    }
+
+    /** */
+    public void setWithMdlStorage(boolean withMdlStorage) {
+        this.withMdlStorage = withMdlStorage;
+    }
+
+    /** */
+    public boolean isWithMdlDescStorage() {
+        return withMdlDescStorage;
+    }
+
+    /** */
+    public void setWithMdlDescStorage(boolean withMdlDescStorage) {
+        this.withMdlDescStorage = withMdlDescStorage;
+    }
+
+    /** */
+    public Integer getMdlStorageBackups() {
+        return mdlStorageBackups;
+    }
+
+    /** */
+    public void setMdlStorageBackups(Integer mdlStorageBackups) {
+        this.mdlStorageBackups = mdlStorageBackups;
+    }
+
+    /** */
+    public Integer getMdlDescStorageBackups() {
+        return mdlDescStorageBackups;
+    }
+
+    /** */
+    public void setMdlDescStorageBackups(Integer mdlDescStorageBackups) {
+        this.mdlDescStorageBackups = mdlDescStorageBackups;
+    }
+}
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/util/plugin/MLPluginProvider.java b/modules/ml/src/main/java/org/apache/ignite/ml/util/plugin/MLPluginProvider.java
new file mode 100644
index 0000000..de039fb
--- /dev/null
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/util/plugin/MLPluginProvider.java
@@ -0,0 +1,195 @@
+/*
+ * 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.ml.util.plugin;
+
+import java.io.Serializable;
+import java.util.UUID;
+import org.apache.ignite.Ignite;
+import org.apache.ignite.IgniteLogger;
+import org.apache.ignite.cache.CacheAtomicityMode;
+import org.apache.ignite.cache.CacheMode;
+import org.apache.ignite.cluster.ClusterNode;
+import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.ml.inference.storage.descriptor.ModelDescriptorStorageFactory;
+import org.apache.ignite.ml.inference.storage.model.ModelStorageFactory;
+import org.apache.ignite.plugin.CachePluginContext;
+import org.apache.ignite.plugin.CachePluginProvider;
+import org.apache.ignite.plugin.ExtensionRegistry;
+import org.apache.ignite.plugin.IgnitePlugin;
+import org.apache.ignite.plugin.PluginConfiguration;
+import org.apache.ignite.plugin.PluginContext;
+import org.apache.ignite.plugin.PluginProvider;
+import org.apache.ignite.plugin.PluginValidationException;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * Machine learning inference plugin provider.
+ */
+public class MLPluginProvider implements PluginProvider<MLPluginConfiguration> {
+    /** Plugin name. */
+    private static final String ML_INFERENCE_PLUGIN_NAME = "ml-inference-plugin";
+
+    /** Plugin version/ */
+    private static final String ML_INFERENCE_PLUGIN_VERSION = "1.0.0";
+
+    /** Default number of model storage backups. */
+    private static final int MODEL_STORAGE_DEFAULT_BACKUPS = 1;
+
+    /** Default number of model descriptor storage backups. */
+    private static final int MODEL_DESCRIPTOR_STORAGE_DEFAULT_BACKUPS = 1;
+
+    /** Plugin configuration. */
+    private MLPluginConfiguration cfg;
+
+    /** Ignite instance. */
+    private Ignite ignite;
+
+    /** Ignite logger. */
+    private IgniteLogger log;
+
+    /** {@inheritDoc} */
+    @Override public String name() {
+        return ML_INFERENCE_PLUGIN_NAME;
+    }
+
+    /** {@inheritDoc} */
+    @Override public String version() {
+        return ML_INFERENCE_PLUGIN_VERSION;
+    }
+
+    /** {@inheritDoc} */
+    @Override public String copyright() {
+        return null;
+    }
+
+    /** {@inheritDoc} */
+    @SuppressWarnings("unchecked")
+    @Override public <T extends IgnitePlugin> T plugin() {
+        return (T)new MLPlugin();
+    }
+
+    /** {@inheritDoc} */
+    @Override public void initExtensions(PluginContext ctx, ExtensionRegistry registry) {
+        IgniteConfiguration igniteCfg = ctx.igniteConfiguration();
+
+        this.ignite = ctx.grid();
+        this.log = ctx.log(this.getClass());
+
+        if (igniteCfg.getPluginConfigurations() != null) {
+            for (PluginConfiguration pluginCfg : igniteCfg.getPluginConfigurations()) {
+                if (pluginCfg instanceof MLPluginConfiguration) {
+                    cfg = (MLPluginConfiguration)pluginCfg;
+                    break;
+                }
+            }
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override public <T> @Nullable T createComponent(PluginContext ctx, Class<T> cls) {
+        return null;
+    }
+
+    /** {@inheritDoc} */
+    @Override public CachePluginProvider createCacheProvider(CachePluginContext ctx) {
+        return null;
+    }
+
+    /** {@inheritDoc} */
+    @Override public void start(PluginContext ctx) {
+        // Do nothing.
+    }
+
+    /** {@inheritDoc} */
+    @Override public void stop(boolean cancel) {
+        // Do nothing.
+    }
+
+    /** {@inheritDoc} */
+    @Override public void onIgniteStart() {
+        if (ignite == null || log == null)
+            throw new RuntimeException("Plugin provider has not been initialized");
+
+        if (cfg != null) {
+            if (cfg.isWithMdlStorage())
+                startModelStorage(cfg);
+
+            if (cfg.isWithMdlDescStorage())
+                startModelDescriptorStorage(cfg);
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override public void onIgniteStop(boolean cancel) {
+
+    }
+
+    /** {@inheritDoc} */
+    @Nullable @Override public Serializable provideDiscoveryData(UUID nodeId) {
+        return null;
+    }
+
+    /** {@inheritDoc} */
+    @Override public void receiveDiscoveryData(UUID nodeId, Serializable data) {
+        // Do nothing.
+    }
+
+    /** {@inheritDoc} */
+    @Override public void validateNewNode(ClusterNode node) throws PluginValidationException {
+        // Do nothing.
+    }
+
+    /**
+     * Starts model storage.
+     */
+    private void startModelStorage(MLPluginConfiguration cfg) {
+        CacheConfiguration<String, byte[]> storageCfg = new CacheConfiguration<>();
+
+        storageCfg.setName(ModelStorageFactory.MODEL_STORAGE_CACHE_NAME);
+        storageCfg.setCacheMode(CacheMode.PARTITIONED);
+        storageCfg.setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL);
+
+        if (cfg.getMdlStorageBackups() == null)
+            storageCfg.setBackups(MODEL_STORAGE_DEFAULT_BACKUPS);
+        else
+            storageCfg.setBackups(cfg.getMdlStorageBackups());
+
+        ignite.getOrCreateCache(storageCfg);
+
+        log.info("ML model storage is ready");
+    }
+
+    /**
+     * Starts model descriptor storage.
+     */
+    private void startModelDescriptorStorage(MLPluginConfiguration cfg) {
+        CacheConfiguration<String, byte[]> storageCfg = new CacheConfiguration<>();
+
+        storageCfg.setName(ModelDescriptorStorageFactory.MODEL_DESCRIPTOR_STORAGE_CACHE_NAME);
+        storageCfg.setCacheMode(CacheMode.PARTITIONED);
+        storageCfg.setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL);
+
+        if (cfg.getMdlDescStorageBackups() == null)
+            storageCfg.setBackups(MODEL_DESCRIPTOR_STORAGE_DEFAULT_BACKUPS);
+
+        ignite.getOrCreateCache(storageCfg);
+
+        log.info("ML model descriptor storage is ready");
+    }
+}
diff --git a/modules/ml/src/main/resources/META-INF/services/org.apache.ignite.plugin.PluginProvider b/modules/ml/src/main/resources/META-INF/services/org.apache.ignite.plugin.PluginProvider
new file mode 100644
index 0000000..03cd54b
--- /dev/null
+++ b/modules/ml/src/main/resources/META-INF/services/org.apache.ignite.plugin.PluginProvider
@@ -0,0 +1 @@
+org.apache.ignite.ml.util.plugin.MLPluginProvider
\ No newline at end of file
diff --git a/modules/ml/src/test/java/org/apache/ignite/ml/TestUtils.java b/modules/ml/src/test/java/org/apache/ignite/ml/TestUtils.java
index 4b472cc..1103ef0 100644
--- a/modules/ml/src/test/java/org/apache/ignite/ml/TestUtils.java
+++ b/modules/ml/src/test/java/org/apache/ignite/ml/TestUtils.java
@@ -18,6 +18,7 @@
 package org.apache.ignite.ml;
 
 import java.util.stream.IntStream;
+import org.apache.ignite.ml.environment.LearningEnvironmentBuilder;
 import org.apache.ignite.ml.math.primitives.matrix.Matrix;
 import org.apache.ignite.ml.math.primitives.vector.Vector;
 import org.junit.Assert;
@@ -325,4 +326,82 @@
 
         }
     }
+
+    /**
+     * Gets test learning environment builder.
+     *
+     * @return test learning environment builder.
+     */
+    public static LearningEnvironmentBuilder testEnvBuilder() {
+        return testEnvBuilder(123L);
+    }
+
+    /**
+     * Gets test learning environment builder with a given seed.
+     *
+     * @param seed Seed.
+     * @return test learning environment builder.
+     */
+    public static LearningEnvironmentBuilder testEnvBuilder(long seed) {
+        return LearningEnvironmentBuilder.defaultBuilder().withRNGSeed(seed);
+    }
+
+    /**
+     * Simple wrapper class which adds {@link AutoCloseable} to given type.
+     *
+     * @param <T> Type to wrap.
+     */
+    public static class DataWrapper<T> implements AutoCloseable {
+        /**
+         * Value to wrap.
+         */
+        T val;
+
+        /**
+         * Wrap given value in {@link AutoCloseable}.
+         *
+         * @param val Value to wrap.
+         * @param <T> Type of value to wrap.
+         * @return Value wrapped as {@link AutoCloseable}.
+         */
+        public static <T> DataWrapper<T> of(T val) {
+            return new DataWrapper<>(val);
+        }
+
+        /**
+         * Construct instance of this class from given value.
+         *
+         * @param val Value to wrap.
+         */
+        public DataWrapper(T val) {
+            this.val = val;
+        }
+
+        /**
+         * Get wrapped value.
+         *
+         * @return Wrapped value.
+         */
+        public T val() {
+            return val;
+        }
+
+        /** {@inheritDoc} */
+        @Override public void close() throws Exception {
+            if (val instanceof AutoCloseable)
+                ((AutoCloseable)val).close();
+        }
+    }
+
+    /**
+     * Return model which returns given constant.
+     *
+     * @param v Constant value.
+     * @param <T> Type of input.
+     * @param <V> Type of output.
+     * @return Model which returns given constant.
+     */
+    public static <T, V> Model<T, V> constantModel(V v) {
+        return t -> v;
+    }
 }
diff --git a/modules/ml/src/test/java/org/apache/ignite/ml/common/CollectionsTest.java b/modules/ml/src/test/java/org/apache/ignite/ml/common/CollectionsTest.java
index 745eac9..e951145 100644
--- a/modules/ml/src/test/java/org/apache/ignite/ml/common/CollectionsTest.java
+++ b/modules/ml/src/test/java/org/apache/ignite/ml/common/CollectionsTest.java
@@ -34,16 +34,13 @@
 import org.apache.ignite.ml.math.primitives.vector.Vector;
 import org.apache.ignite.ml.math.primitives.vector.impl.DenseVector;
 import org.apache.ignite.ml.math.primitives.vector.impl.VectorizedViewMatrix;
-import org.apache.ignite.ml.regressions.linear.LinearRegressionModel;
-import org.apache.ignite.ml.regressions.logistic.binomial.LogisticRegressionModel;
-import org.apache.ignite.ml.regressions.logistic.multiclass.LogRegressionMultiClassModel;
+import org.apache.ignite.ml.regressions.logistic.LogisticRegressionModel;
 import org.apache.ignite.ml.structures.Dataset;
 import org.apache.ignite.ml.structures.DatasetRow;
 import org.apache.ignite.ml.structures.FeatureMetadata;
 import org.apache.ignite.ml.structures.LabeledVector;
 import org.apache.ignite.ml.structures.LabeledVectorSet;
-import org.apache.ignite.ml.svm.SVMLinearBinaryClassificationModel;
-import org.apache.ignite.ml.svm.SVMLinearMultiClassClassificationModel;
+import org.apache.ignite.ml.svm.SVMLinearClassificationModel;
 import org.junit.Test;
 
 import static org.junit.Assert.assertEquals;
@@ -92,17 +89,7 @@
 
         test(new KNNClassificationModel(null).withK(1), new KNNClassificationModel(null).withK(2));
 
-        LogRegressionMultiClassModel mdl = new LogRegressionMultiClassModel();
-        mdl.add(1, new LogisticRegressionModel(new DenseVector(), 1.0));
-        test(mdl, new LogRegressionMultiClassModel());
-
-        test(new LinearRegressionModel(null, 1.0), new LinearRegressionModel(null, 0.5));
-
-        SVMLinearMultiClassClassificationModel mdl1 = new SVMLinearMultiClassClassificationModel();
-        mdl1.add(1, new SVMLinearBinaryClassificationModel(new DenseVector(), 1.0));
-        test(mdl1, new SVMLinearMultiClassClassificationModel());
-
-        test(new SVMLinearBinaryClassificationModel(null, 1.0), new SVMLinearBinaryClassificationModel(null, 0.5));
+        test(new SVMLinearClassificationModel(null, 1.0), new SVMLinearClassificationModel(null, 0.5));
 
         test(new ANNClassificationModel(new LabeledVectorSet<>(), new ANNClassificationTrainer.CentroidStat()),
             new ANNClassificationModel(new LabeledVectorSet<>(1, 1, true), new ANNClassificationTrainer.CentroidStat()));
diff --git a/modules/ml/src/test/java/org/apache/ignite/ml/common/LocalModelsTest.java b/modules/ml/src/test/java/org/apache/ignite/ml/common/LocalModelsTest.java
index ca3f0b5..c5b2ffe 100644
--- a/modules/ml/src/test/java/org/apache/ignite/ml/common/LocalModelsTest.java
+++ b/modules/ml/src/test/java/org/apache/ignite/ml/common/LocalModelsTest.java
@@ -43,12 +43,10 @@
 import org.apache.ignite.ml.math.primitives.vector.VectorUtils;
 import org.apache.ignite.ml.math.primitives.vector.impl.DenseVector;
 import org.apache.ignite.ml.regressions.linear.LinearRegressionModel;
-import org.apache.ignite.ml.regressions.logistic.binomial.LogisticRegressionModel;
-import org.apache.ignite.ml.regressions.logistic.multiclass.LogRegressionMultiClassModel;
+import org.apache.ignite.ml.regressions.logistic.LogisticRegressionModel;
 import org.apache.ignite.ml.structures.LabeledVector;
 import org.apache.ignite.ml.structures.LabeledVectorSet;
-import org.apache.ignite.ml.svm.SVMLinearBinaryClassificationModel;
-import org.apache.ignite.ml.svm.SVMLinearMultiClassClassificationModel;
+import org.apache.ignite.ml.svm.SVMLinearClassificationModel;
 import org.junit.Assert;
 import org.junit.Test;
 
@@ -99,36 +97,11 @@
     @Test
     public void importExportSVMBinaryClassificationModelTest() throws IOException {
         executeModelTest(mdlFilePath -> {
-            SVMLinearBinaryClassificationModel mdl = new SVMLinearBinaryClassificationModel(new DenseVector(new double[]{1, 2}), 3);
-            Exporter<SVMLinearBinaryClassificationModel, String> exporter = new FileExporter<>();
+            SVMLinearClassificationModel mdl = new SVMLinearClassificationModel(new DenseVector(new double[] {1, 2}), 3);
+            Exporter<SVMLinearClassificationModel, String> exporter = new FileExporter<>();
             mdl.saveModel(exporter, mdlFilePath);
 
-            SVMLinearBinaryClassificationModel load = exporter.load(mdlFilePath);
-
-            Assert.assertNotNull(load);
-            Assert.assertEquals("", mdl, load);
-
-            return null;
-        });
-    }
-
-    /** */
-    @Test
-    public void importExportSVMMultiClassClassificationModelTest() throws IOException {
-        executeModelTest(mdlFilePath -> {
-            SVMLinearBinaryClassificationModel binaryMdl1 = new SVMLinearBinaryClassificationModel(new DenseVector(new double[]{1, 2}), 3);
-            SVMLinearBinaryClassificationModel binaryMdl2 = new SVMLinearBinaryClassificationModel(new DenseVector(new double[]{2, 3}), 4);
-            SVMLinearBinaryClassificationModel binaryMdl3 = new SVMLinearBinaryClassificationModel(new DenseVector(new double[]{3, 4}), 5);
-
-            SVMLinearMultiClassClassificationModel mdl = new SVMLinearMultiClassClassificationModel();
-            mdl.add(1, binaryMdl1);
-            mdl.add(2, binaryMdl2);
-            mdl.add(3, binaryMdl3);
-
-            Exporter<SVMLinearMultiClassClassificationModel, String> exporter = new FileExporter<>();
-            mdl.saveModel(exporter, mdlFilePath);
-
-            SVMLinearMultiClassClassificationModel load = exporter.load(mdlFilePath);
+            SVMLinearClassificationModel load = exporter.load(mdlFilePath);
 
             Assert.assertNotNull(load);
             Assert.assertEquals("", mdl, load);
@@ -155,23 +128,6 @@
     }
 
     /** */
-    @Test
-    public void importExportLogRegressionMultiClassModelTest() throws IOException {
-        executeModelTest(mdlFilePath -> {
-            LogRegressionMultiClassModel mdl = new LogRegressionMultiClassModel();
-            Exporter<LogRegressionMultiClassModel, String> exporter = new FileExporter<>();
-            mdl.saveModel(exporter, mdlFilePath);
-
-            LogRegressionMultiClassModel load = exporter.load(mdlFilePath);
-
-            Assert.assertNotNull(load);
-            Assert.assertEquals("", mdl, load);
-
-            return null;
-        });
-    }
-
-    /** */
     private void executeModelTest(Function<String, Void> code) throws IOException {
         Path mdlPath = Files.createTempFile(null, null);
 
diff --git a/modules/ml/src/test/java/org/apache/ignite/ml/composition/boosting/convergence/mean/MeanAbsValueConvergenceCheckerTest.java b/modules/ml/src/test/java/org/apache/ignite/ml/composition/boosting/convergence/mean/MeanAbsValueConvergenceCheckerTest.java
index 0b42db8..c218a74 100644
--- a/modules/ml/src/test/java/org/apache/ignite/ml/composition/boosting/convergence/mean/MeanAbsValueConvergenceCheckerTest.java
+++ b/modules/ml/src/test/java/org/apache/ignite/ml/composition/boosting/convergence/mean/MeanAbsValueConvergenceCheckerTest.java
@@ -17,6 +17,7 @@
 
 package org.apache.ignite.ml.composition.boosting.convergence.mean;
 
+import org.apache.ignite.ml.TestUtils;
 import org.apache.ignite.ml.composition.boosting.convergence.ConvergenceChecker;
 import org.apache.ignite.ml.composition.boosting.convergence.ConvergenceCheckerTest;
 import org.apache.ignite.ml.dataset.impl.local.LocalDataset;
@@ -25,6 +26,7 @@
 import org.apache.ignite.ml.dataset.primitive.FeatureMatrixWithLabelsOnHeapDataBuilder;
 import org.apache.ignite.ml.dataset.primitive.builder.context.EmptyContextBuilder;
 import org.apache.ignite.ml.dataset.primitive.context.EmptyContext;
+import org.apache.ignite.ml.environment.LearningEnvironmentBuilder;
 import org.apache.ignite.ml.math.primitives.vector.VectorUtils;
 import org.junit.Assert;
 import org.junit.Test;
@@ -39,11 +41,14 @@
             new MeanAbsValueConvergenceCheckerFactory(0.1), datasetBuilder);
 
         double error = checker.computeError(VectorUtils.of(1, 2), 4.0, notConvergedMdl);
+        LearningEnvironmentBuilder envBuilder = TestUtils.testEnvBuilder();
+
         Assert.assertEquals(1.9, error, 0.01);
-        Assert.assertFalse(checker.isConverged(datasetBuilder, notConvergedMdl));
-        Assert.assertTrue(checker.isConverged(datasetBuilder, convergedMdl));
+        Assert.assertFalse(checker.isConverged(envBuilder, datasetBuilder, notConvergedMdl));
+        Assert.assertTrue(checker.isConverged(envBuilder, datasetBuilder, convergedMdl));
 
         try(LocalDataset<EmptyContext, FeatureMatrixWithLabelsOnHeapData> dataset = datasetBuilder.build(
+            envBuilder,
             new EmptyContextBuilder<>(), new FeatureMatrixWithLabelsOnHeapDataBuilder<>(fExtr, lbExtr))) {
 
             double onDSError = checker.computeMeanErrorOnDataset(dataset, notConvergedMdl);
@@ -62,6 +67,7 @@
             new MeanAbsValueConvergenceCheckerFactory(0.1), datasetBuilder);
 
         try(LocalDataset<EmptyContext, FeatureMatrixWithLabelsOnHeapData> dataset = datasetBuilder.build(
+            TestUtils.testEnvBuilder(),
             new EmptyContextBuilder<>(), new FeatureMatrixWithLabelsOnHeapDataBuilder<>(fExtr, lbExtr))) {
 
             double onDSError = checker.computeMeanErrorOnDataset(dataset, notConvergedMdl);
diff --git a/modules/ml/src/test/java/org/apache/ignite/ml/composition/boosting/convergence/median/MedianOfMedianConvergenceCheckerTest.java b/modules/ml/src/test/java/org/apache/ignite/ml/composition/boosting/convergence/median/MedianOfMedianConvergenceCheckerTest.java
index d6880b4..0476a37 100644
--- a/modules/ml/src/test/java/org/apache/ignite/ml/composition/boosting/convergence/median/MedianOfMedianConvergenceCheckerTest.java
+++ b/modules/ml/src/test/java/org/apache/ignite/ml/composition/boosting/convergence/median/MedianOfMedianConvergenceCheckerTest.java
@@ -17,6 +17,7 @@
 
 package org.apache.ignite.ml.composition.boosting.convergence.median;
 
+import org.apache.ignite.ml.TestUtils;
 import org.apache.ignite.ml.composition.boosting.convergence.ConvergenceChecker;
 import org.apache.ignite.ml.composition.boosting.convergence.ConvergenceCheckerTest;
 import org.apache.ignite.ml.dataset.impl.local.LocalDataset;
@@ -25,6 +26,7 @@
 import org.apache.ignite.ml.dataset.primitive.FeatureMatrixWithLabelsOnHeapDataBuilder;
 import org.apache.ignite.ml.dataset.primitive.builder.context.EmptyContextBuilder;
 import org.apache.ignite.ml.dataset.primitive.context.EmptyContext;
+import org.apache.ignite.ml.environment.LearningEnvironmentBuilder;
 import org.apache.ignite.ml.math.primitives.vector.VectorUtils;
 import org.junit.Assert;
 import org.junit.Test;
@@ -42,10 +44,14 @@
 
         double error = checker.computeError(VectorUtils.of(1, 2), 4.0, notConvergedMdl);
         Assert.assertEquals(1.9, error, 0.01);
-        Assert.assertFalse(checker.isConverged(datasetBuilder, notConvergedMdl));
-        Assert.assertTrue(checker.isConverged(datasetBuilder, convergedMdl));
+
+        LearningEnvironmentBuilder envBuilder = TestUtils.testEnvBuilder();
+
+        Assert.assertFalse(checker.isConverged(envBuilder, datasetBuilder, notConvergedMdl));
+        Assert.assertTrue(checker.isConverged(envBuilder, datasetBuilder, convergedMdl));
 
         try(LocalDataset<EmptyContext, FeatureMatrixWithLabelsOnHeapData> dataset = datasetBuilder.build(
+            envBuilder,
             new EmptyContextBuilder<>(), new FeatureMatrixWithLabelsOnHeapDataBuilder<>(fExtr, lbExtr))) {
 
             double onDSError = checker.computeMeanErrorOnDataset(dataset, notConvergedMdl);
diff --git a/modules/ml/src/test/java/org/apache/ignite/ml/dataset/impl/cache/CacheBasedDatasetBuilderTest.java b/modules/ml/src/test/java/org/apache/ignite/ml/dataset/impl/cache/CacheBasedDatasetBuilderTest.java
index 1cf6dbf..815bd86 100644
--- a/modules/ml/src/test/java/org/apache/ignite/ml/dataset/impl/cache/CacheBasedDatasetBuilderTest.java
+++ b/modules/ml/src/test/java/org/apache/ignite/ml/dataset/impl/cache/CacheBasedDatasetBuilderTest.java
@@ -26,6 +26,7 @@
 import org.apache.ignite.cluster.ClusterNode;
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.internal.util.IgniteUtils;
+import org.apache.ignite.ml.TestUtils;
 import org.apache.ignite.ml.dataset.UpstreamEntry;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
 
@@ -66,8 +67,9 @@
         CacheBasedDatasetBuilder<Integer, String> builder = new CacheBasedDatasetBuilder<>(ignite, upstreamCache);
 
         CacheBasedDataset<Integer, String, Long, AutoCloseable> dataset = builder.build(
-            (upstream, upstreamSize) -> upstreamSize,
-            (upstream, upstreamSize, ctx) -> null
+            TestUtils.testEnvBuilder(),
+            (env, upstream, upstreamSize) -> upstreamSize,
+            (env, upstream, upstreamSize, ctx) -> null
         );
 
         Affinity<Integer> upstreamAffinity = ignite.affinity(upstreamCache.getName());
@@ -105,14 +107,15 @@
         );
 
         CacheBasedDataset<Integer, Integer, Long, AutoCloseable> dataset = builder.build(
-            (upstream, upstreamSize) -> {
+            TestUtils.testEnvBuilder(),
+            (env, upstream, upstreamSize) -> {
                 UpstreamEntry<Integer, Integer> entry = upstream.next();
                 assertEquals(Integer.valueOf(2), entry.getKey());
                 assertEquals(Integer.valueOf(2), entry.getValue());
                 assertFalse(upstream.hasNext());
                 return 0L;
             },
-            (upstream, upstreamSize, ctx) -> {
+            (env, upstream, upstreamSize, ctx) -> {
                 UpstreamEntry<Integer, Integer> entry = upstream.next();
                 assertEquals(Integer.valueOf(2), entry.getKey());
                 assertEquals(Integer.valueOf(2), entry.getValue());
diff --git a/modules/ml/src/test/java/org/apache/ignite/ml/dataset/impl/cache/CacheBasedDatasetTest.java b/modules/ml/src/test/java/org/apache/ignite/ml/dataset/impl/cache/CacheBasedDatasetTest.java
index a892530..7e31b07 100644
--- a/modules/ml/src/test/java/org/apache/ignite/ml/dataset/impl/cache/CacheBasedDatasetTest.java
+++ b/modules/ml/src/test/java/org/apache/ignite/ml/dataset/impl/cache/CacheBasedDatasetTest.java
@@ -38,6 +38,7 @@
 import org.apache.ignite.internal.util.IgniteUtils;
 import org.apache.ignite.internal.util.typedef.G;
 import org.apache.ignite.lang.IgnitePredicate;
+import org.apache.ignite.ml.TestUtils;
 import org.apache.ignite.ml.dataset.primitive.data.SimpleDatasetData;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
 
@@ -83,8 +84,9 @@
         CacheBasedDatasetBuilder<Integer, String> builder = new CacheBasedDatasetBuilder<>(ignite, upstreamCache);
 
         CacheBasedDataset<Integer, String, Long, SimpleDatasetData> dataset = builder.build(
-            (upstream, upstreamSize) -> upstreamSize,
-            (upstream, upstreamSize, ctx) -> new SimpleDatasetData(new double[0], 0)
+            TestUtils.testEnvBuilder(),
+            (env, upstream, upstreamSize) -> upstreamSize,
+            (env, upstream, upstreamSize, ctx) -> new SimpleDatasetData(new double[0], 0)
         );
 
         assertEquals("Upstream cache name from dataset",
@@ -138,8 +140,9 @@
         CacheBasedDatasetBuilder<Integer, String> builder = new CacheBasedDatasetBuilder<>(ignite, upstreamCache);
 
         CacheBasedDataset<Integer, String, Long, SimpleDatasetData> dataset = builder.build(
-            (upstream, upstreamSize) -> upstreamSize,
-            (upstream, upstreamSize, ctx) -> new SimpleDatasetData(new double[0], 0)
+            TestUtils.testEnvBuilder(),
+            (env, upstream, upstreamSize) -> upstreamSize,
+            (env, upstream, upstreamSize, ctx) -> new SimpleDatasetData(new double[0], 0)
         );
 
         assertTrue("Before computation all partitions should not be reserved",
diff --git a/modules/ml/src/test/java/org/apache/ignite/ml/dataset/impl/cache/util/ComputeUtilsTest.java b/modules/ml/src/test/java/org/apache/ignite/ml/dataset/impl/cache/util/ComputeUtilsTest.java
index cee8f4f..202b6bc 100644
--- a/modules/ml/src/test/java/org/apache/ignite/ml/dataset/impl/cache/util/ComputeUtilsTest.java
+++ b/modules/ml/src/test/java/org/apache/ignite/ml/dataset/impl/cache/util/ComputeUtilsTest.java
@@ -32,8 +32,9 @@
 import org.apache.ignite.cluster.ClusterNode;
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.internal.util.IgniteUtils;
+import org.apache.ignite.ml.TestUtils;
 import org.apache.ignite.ml.dataset.UpstreamEntry;
-import org.apache.ignite.ml.dataset.UpstreamTransformerChain;
+import org.apache.ignite.ml.dataset.UpstreamTransformerBuilder;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
 
 /**
@@ -179,18 +180,18 @@
                     ignite,
                     upstreamCacheName,
                     (k, v) -> true,
-                    UpstreamTransformerChain.empty(),
+                    UpstreamTransformerBuilder.identity(),
                     datasetCacheName,
                     datasetId,
-                    0,
-                    (upstream, upstreamSize, ctx) -> {
+                    (env, upstream, upstreamSize, ctx) -> {
                         cnt.incrementAndGet();
 
                         assertEquals(1, upstreamSize);
 
                         UpstreamEntry<Integer, Integer> e = upstream.next();
                         return new TestPartitionData(e.getKey() + e.getValue());
-                    }
+                    },
+                    TestUtils.testEnvBuilder().buildForWorker(part)
                 ),
                 0
             );
@@ -229,15 +230,16 @@
             ignite,
             upstreamCacheName,
             (k, v) -> true,
-            UpstreamTransformerChain.empty(),
+            UpstreamTransformerBuilder.identity(),
             datasetCacheName,
-            (upstream, upstreamSize) -> {
+            (env, upstream, upstreamSize) -> {
 
                 assertEquals(1, upstreamSize);
 
                 UpstreamEntry<Integer, Integer> e = upstream.next();
                 return e.getKey() + e.getValue();
             },
+            TestUtils.testEnvBuilder(),
             0
         );
 
diff --git a/modules/ml/src/test/java/org/apache/ignite/ml/dataset/impl/local/LocalDatasetBuilderTest.java b/modules/ml/src/test/java/org/apache/ignite/ml/dataset/impl/local/LocalDatasetBuilderTest.java
index 8dc9354..6088140 100644
--- a/modules/ml/src/test/java/org/apache/ignite/ml/dataset/impl/local/LocalDatasetBuilderTest.java
+++ b/modules/ml/src/test/java/org/apache/ignite/ml/dataset/impl/local/LocalDatasetBuilderTest.java
@@ -21,6 +21,7 @@
 import java.util.HashMap;
 import java.util.Map;
 import java.util.concurrent.atomic.AtomicLong;
+import org.apache.ignite.ml.TestUtils;
 import org.apache.ignite.ml.dataset.PartitionContextBuilder;
 import org.apache.ignite.ml.dataset.PartitionDataBuilder;
 import org.junit.Test;
@@ -47,7 +48,7 @@
 
         AtomicLong cnt = new AtomicLong();
 
-        dataset.compute((partData, partIdx) -> {
+        dataset.compute((partData, env) -> {
            cnt.incrementAndGet();
 
            int[] arr = partData.data;
@@ -55,7 +56,7 @@
            assertEquals(10, arr.length);
 
            for (int i = 0; i < 10; i++)
-               assertEquals(partIdx * 10 + i, arr[i]);
+               assertEquals(env.partition() * 10 + i, arr[i]);
         });
 
         assertEquals(10, cnt.intValue());
@@ -74,7 +75,7 @@
 
         AtomicLong cnt = new AtomicLong();
 
-        dataset.compute((partData, partIdx) -> {
+        dataset.compute((partData, env) -> {
             cnt.incrementAndGet();
 
             int[] arr = partData.data;
@@ -82,7 +83,7 @@
             assertEquals(5, arr.length);
 
             for (int i = 0; i < 5; i++)
-                assertEquals((partIdx * 5 + i) * 2, arr[i]);
+                assertEquals((env.partition() * 5 + i) * 2, arr[i]);
         });
 
         assertEquals(10, cnt.intValue());
@@ -91,10 +92,10 @@
     /** */
     private LocalDataset<Serializable, TestPartitionData> buildDataset(
         LocalDatasetBuilder<Integer, Integer> builder) {
-        PartitionContextBuilder<Integer, Integer, Serializable> partCtxBuilder = (upstream, upstreamSize) -> null;
+        PartitionContextBuilder<Integer, Integer, Serializable> partCtxBuilder = (env, upstream, upstreamSize) -> null;
 
         PartitionDataBuilder<Integer, Integer, Serializable, TestPartitionData> partDataBuilder
-            = (upstream, upstreamSize, ctx) -> {
+            = (env, upstream, upstreamSize, ctx) -> {
             int[] arr = new int[Math.toIntExact(upstreamSize)];
 
             int ptr = 0;
@@ -105,6 +106,7 @@
         };
 
         return builder.build(
+            TestUtils.testEnvBuilder(),
             partCtxBuilder.andThen(x -> null),
             partDataBuilder.andThen((x, y) -> x)
         );
diff --git a/modules/ml/src/test/java/org/apache/ignite/ml/dataset/primitive/SimpleDatasetTest.java b/modules/ml/src/test/java/org/apache/ignite/ml/dataset/primitive/SimpleDatasetTest.java
index eaa03d2..33c0677 100644
--- a/modules/ml/src/test/java/org/apache/ignite/ml/dataset/primitive/SimpleDatasetTest.java
+++ b/modules/ml/src/test/java/org/apache/ignite/ml/dataset/primitive/SimpleDatasetTest.java
@@ -19,6 +19,7 @@
 
 import java.util.HashMap;
 import java.util.Map;
+import org.apache.ignite.ml.TestUtils;
 import org.apache.ignite.ml.dataset.DatasetFactory;
 import org.apache.ignite.ml.math.primitives.vector.VectorUtils;
 import org.junit.Test;
@@ -43,6 +44,7 @@
         try (SimpleDataset<?> dataset = DatasetFactory.createSimpleDataset(
             dataPoints,
             2,
+            TestUtils.testEnvBuilder(),
             (k, v) -> VectorUtils.of(v.getAge(), v.getSalary())
         )) {
             assertArrayEquals("Mean values.", new double[] {37.75, 66000.0}, dataset.mean(), 0);
diff --git a/modules/ml/src/test/java/org/apache/ignite/ml/dataset/primitive/SimpleLabeledDatasetTest.java b/modules/ml/src/test/java/org/apache/ignite/ml/dataset/primitive/SimpleLabeledDatasetTest.java
index f7b0f13..36e540b 100644
--- a/modules/ml/src/test/java/org/apache/ignite/ml/dataset/primitive/SimpleLabeledDatasetTest.java
+++ b/modules/ml/src/test/java/org/apache/ignite/ml/dataset/primitive/SimpleLabeledDatasetTest.java
@@ -19,6 +19,7 @@
 
 import java.util.HashMap;
 import java.util.Map;
+import org.apache.ignite.ml.TestUtils;
 import org.apache.ignite.ml.dataset.DatasetFactory;
 import org.apache.ignite.ml.math.primitives.vector.VectorUtils;
 import org.junit.Test;
@@ -47,14 +48,16 @@
         // Creates a local simple dataset containing features and providing standard dataset API.
         try (SimpleLabeledDataset<?> dataset = DatasetFactory.createSimpleLabeledDataset(
             dataPoints,
+            TestUtils.testEnvBuilder(),
             2,
             (k, v) -> VectorUtils.of(v.getAge(), v.getSalary()),
             (k, v) -> new double[] {k, v.getAge(), v.getSalary()}
         )) {
-            assertNull(dataset.compute((data, partIdx) -> {
-                actualFeatures[partIdx] = data.getFeatures();
-                actualLabels[partIdx] = data.getLabels();
-                actualRows[partIdx] = data.getRows();
+            assertNull(dataset.compute((data, env) -> {
+                int part = env.partition();
+                actualFeatures[part] = data.getFeatures();
+                actualLabels[part] = data.getLabels();
+                actualRows[part] = data.getRows();
                 return null;
             }, (k, v) -> null));
         }
diff --git a/modules/ml/src/test/java/org/apache/ignite/ml/environment/LearningEnvironmentBuilderTest.java b/modules/ml/src/test/java/org/apache/ignite/ml/environment/LearningEnvironmentBuilderTest.java
index 56f262b..7769092 100644
--- a/modules/ml/src/test/java/org/apache/ignite/ml/environment/LearningEnvironmentBuilderTest.java
+++ b/modules/ml/src/test/java/org/apache/ignite/ml/environment/LearningEnvironmentBuilderTest.java
@@ -39,7 +39,7 @@
     /** */
     @Test
     public void basic() {
-        LearningEnvironment env = LearningEnvironment.DEFAULT;
+        LearningEnvironment env = LearningEnvironment.DEFAULT_TRAINER_ENV;
 
         assertNotNull("Strategy", env.parallelismStrategy());
         assertNotNull("Logger", env.logger());
@@ -49,42 +49,44 @@
     /** */
     @Test
     public void withParallelismStrategy() {
-        assertTrue(LearningEnvironment.builder().withParallelismStrategy(NoParallelismStrategy.INSTANCE).build()
+        assertTrue(LearningEnvironmentBuilder.defaultBuilder().withParallelismStrategyDependency(part -> NoParallelismStrategy.INSTANCE)
+            .buildForTrainer()
             .parallelismStrategy() instanceof NoParallelismStrategy);
 
-        assertTrue(LearningEnvironment.builder().withParallelismStrategy(new DefaultParallelismStrategy()).build()
+        assertTrue(LearningEnvironmentBuilder.defaultBuilder().withParallelismStrategyDependency(part -> new DefaultParallelismStrategy())
+            .buildForTrainer()
             .parallelismStrategy() instanceof DefaultParallelismStrategy);
     }
 
     /** */
     @Test
     public void withParallelismStrategyType() {
-        assertTrue(LearningEnvironment.builder().withParallelismStrategy(NO_PARALLELISM).build()
+        assertTrue(LearningEnvironmentBuilder.defaultBuilder().withParallelismStrategyType(NO_PARALLELISM).buildForTrainer()
             .parallelismStrategy() instanceof NoParallelismStrategy);
 
-        assertTrue(LearningEnvironment.builder().withParallelismStrategy(ON_DEFAULT_POOL).build()
+        assertTrue(LearningEnvironmentBuilder.defaultBuilder().withParallelismStrategyType(ON_DEFAULT_POOL).buildForTrainer()
             .parallelismStrategy() instanceof DefaultParallelismStrategy);
     }
 
     /** */
     @Test
     public void withLoggingFactory() {
-        assertTrue(LearningEnvironment.builder().withLoggingFactory(ConsoleLogger.factory(MLLogger.VerboseLevel.HIGH))
-            .build().logger() instanceof ConsoleLogger);
+        assertTrue(LearningEnvironmentBuilder.defaultBuilder().withLoggingFactoryDependency(part -> ConsoleLogger.factory(MLLogger.VerboseLevel.HIGH))
+            .buildForTrainer().logger() instanceof ConsoleLogger);
 
-        assertTrue(LearningEnvironment.builder().withLoggingFactory(ConsoleLogger.factory(MLLogger.VerboseLevel.HIGH))
-            .build().logger(this.getClass()) instanceof ConsoleLogger);
+        assertTrue(LearningEnvironmentBuilder.defaultBuilder().withLoggingFactoryDependency(part -> ConsoleLogger.factory(MLLogger.VerboseLevel.HIGH))
+            .buildForTrainer().logger(this.getClass()) instanceof ConsoleLogger);
 
-        assertTrue(LearningEnvironment.builder().withLoggingFactory(NoOpLogger.factory())
-            .build().logger() instanceof NoOpLogger);
+        assertTrue(LearningEnvironmentBuilder.defaultBuilder().withLoggingFactoryDependency(part -> NoOpLogger.factory())
+            .buildForTrainer().logger() instanceof NoOpLogger);
 
-        assertTrue(LearningEnvironment.builder().withLoggingFactory(NoOpLogger.factory())
-            .build().logger(this.getClass()) instanceof NoOpLogger);
+        assertTrue(LearningEnvironmentBuilder.defaultBuilder().withLoggingFactoryDependency(part -> NoOpLogger.factory())
+            .buildForTrainer().logger(this.getClass()) instanceof NoOpLogger);
 
-        assertTrue(LearningEnvironment.builder().withLoggingFactory(CustomMLLogger.factory(new NullLogger()))
-            .build().logger() instanceof CustomMLLogger);
+        assertTrue(LearningEnvironmentBuilder.defaultBuilder().withLoggingFactoryDependency(part -> CustomMLLogger.factory(new NullLogger()))
+            .buildForTrainer().logger() instanceof CustomMLLogger);
 
-        assertTrue(LearningEnvironment.builder().withLoggingFactory(CustomMLLogger.factory(new NullLogger()))
-            .build().logger(this.getClass()) instanceof CustomMLLogger);
+        assertTrue(LearningEnvironmentBuilder.defaultBuilder().withLoggingFactoryDependency(part -> CustomMLLogger.factory(new NullLogger()))
+            .buildForTrainer().logger(this.getClass()) instanceof CustomMLLogger);
     }
 }
diff --git a/modules/ml/src/test/java/org/apache/ignite/ml/environment/LearningEnvironmentTest.java b/modules/ml/src/test/java/org/apache/ignite/ml/environment/LearningEnvironmentTest.java
index 73192f0..4b44196 100644
--- a/modules/ml/src/test/java/org/apache/ignite/ml/environment/LearningEnvironmentTest.java
+++ b/modules/ml/src/test/java/org/apache/ignite/ml/environment/LearningEnvironmentTest.java
@@ -17,17 +17,31 @@
 
 package org.apache.ignite.ml.environment;
 
+import java.util.Map;
+import java.util.Random;
 import java.util.stream.Collectors;
 import java.util.stream.IntStream;
+import org.apache.ignite.ml.Model;
+import org.apache.ignite.ml.TestUtils;
+import org.apache.ignite.ml.dataset.Dataset;
+import org.apache.ignite.ml.dataset.DatasetBuilder;
+import org.apache.ignite.ml.dataset.PartitionDataBuilder;
 import org.apache.ignite.ml.dataset.feature.FeatureMeta;
+import org.apache.ignite.ml.dataset.primitive.builder.context.EmptyContextBuilder;
+import org.apache.ignite.ml.dataset.primitive.context.EmptyContext;
 import org.apache.ignite.ml.environment.logging.ConsoleLogger;
 import org.apache.ignite.ml.environment.logging.MLLogger;
 import org.apache.ignite.ml.environment.parallelism.DefaultParallelismStrategy;
 import org.apache.ignite.ml.environment.parallelism.ParallelismStrategy;
+import org.apache.ignite.ml.math.functions.IgniteBiFunction;
+import org.apache.ignite.ml.math.primitives.vector.Vector;
+import org.apache.ignite.ml.math.primitives.vector.VectorUtils;
+import org.apache.ignite.ml.trainers.DatasetTrainer;
 import org.apache.ignite.ml.tree.randomforest.RandomForestRegressionTrainer;
 import org.apache.ignite.ml.tree.randomforest.data.FeaturesCountSelectionStrategies;
 import org.junit.Test;
 
+import static org.apache.ignite.ml.TestUtils.constantModel;
 import static org.junit.Assert.assertEquals;
 
 /**
@@ -48,13 +62,115 @@
             .withSubSampleSize(0.3)
             .withSeed(0);
 
-        LearningEnvironment environment = LearningEnvironment.builder()
-            .withParallelismStrategy(ParallelismStrategy.Type.ON_DEFAULT_POOL)
-            .withLoggingFactory(ConsoleLogger.factory(MLLogger.VerboseLevel.LOW))
-            .build();
-        trainer.setEnvironment(environment);
-        assertEquals(DefaultParallelismStrategy.class, environment.parallelismStrategy().getClass());
-        assertEquals(ConsoleLogger.class, environment.logger().getClass());
+        LearningEnvironmentBuilder envBuilder = LearningEnvironmentBuilder.defaultBuilder()
+            .withParallelismStrategyType(ParallelismStrategy.Type.ON_DEFAULT_POOL)
+            .withLoggingFactoryDependency(part -> ConsoleLogger.factory(MLLogger.VerboseLevel.LOW));
+
+        trainer.withEnvironmentBuilder(envBuilder);
+
+        assertEquals(DefaultParallelismStrategy.class, trainer.learningEnvironment().parallelismStrategy().getClass());
+        assertEquals(ConsoleLogger.class, trainer.learningEnvironment().logger().getClass());
+    }
+
+    /**
+     * Test random number generator provided by  {@link LearningEnvironment}.
+     * We test that:
+     * 1. Correct random generator is returned for each partition.
+     * 2. Its state is saved between compute calls (for this we do several iterations of compute).
+     */
+    @Test
+    public void testRandomNumbersGenerator() {
+        // We make such builders that provide as functions returning partition index * iteration as random number generator nextInt
+        LearningEnvironmentBuilder envBuilder = TestUtils.testEnvBuilder().withRandomDependency(MockRandom::new);
+        int partitions = 10;
+        int iterations = 2;
+
+        DatasetTrainer<Model<Object, Vector>, Void> trainer = new DatasetTrainer<Model<Object, Vector>, Void>() {
+            /** {@inheritDoc} */
+            @Override public <K, V> Model<Object, Vector> fit(DatasetBuilder<K, V> datasetBuilder,
+                IgniteBiFunction<K, V, Vector> featureExtractor, IgniteBiFunction<K, V, Void> lbExtractor) {
+                Dataset<EmptyContext, TestUtils.DataWrapper<Integer>> ds = datasetBuilder.build(envBuilder,
+                    new EmptyContextBuilder<>(),
+                    (PartitionDataBuilder<K, V, EmptyContext, TestUtils.DataWrapper<Integer>>)(env, upstreamData, upstreamDataSize, ctx) ->
+                        TestUtils.DataWrapper.of(env.partition()));
+
+                Vector v = null;
+                for (int iter = 0; iter < iterations; iter++) {
+                    v = ds.compute((dw, env) -> VectorUtils.fill(-1, partitions).set(env.partition(), env.randomNumbersGenerator().nextInt()),
+                        (v1, v2) -> zipOverridingEmpty(v1, v2, -1));
+                }
+                return constantModel(v);
+            }
+
+            /** {@inheritDoc} */
+            @Override protected boolean checkState(Model<Object, Vector> mdl) {
+                return false;
+            }
+
+            /** {@inheritDoc} */
+            @Override protected <K, V> Model<Object, Vector> updateModel(Model<Object, Vector> mdl,
+                DatasetBuilder<K, V> datasetBuilder,
+                IgniteBiFunction<K, V, Vector> featureExtractor, IgniteBiFunction<K, V, Void> lbExtractor) {
+                return null;
+            }
+        };
+        trainer.withEnvironmentBuilder(envBuilder);
+        Model<Object, Vector> mdl = trainer.fit(getCacheMock(partitions), partitions, null, null);
+
+        Vector exp = VectorUtils.zeroes(partitions);
+        for (int i = 0; i < partitions; i++)
+            exp.set(i, i * iterations);
+
+
+        Vector res = mdl.apply(null);
+        assertEquals(exp, res);
+    }
+
+    /**
+     * For given two vectors {@code v2, v2} produce vector {@code v} where each component of {@code v}
+     * is produced from corresponding components {@code c1, c2} of {@code v1, v2} respectfully in following way
+     * {@code c = c1 != empty ? c1 : c2}. For example, zipping [2, -1, -1], [-1, 3, -1] will result in [2, 3, -1].
+     *
+     * @param v1 First vector.
+     * @param v2 Second vector.
+     * @param empty Value treated as empty.
+     * @return Result of zipping as described above.
+     */
+    private static Vector zipOverridingEmpty(Vector v1, Vector v2, double empty) {
+        return v1 != null ? (v2 != null ? VectorUtils.zipWith(v1, v2, (d1, d2) -> d1 != empty ? d1 : d2) : v1) : v2;
+    }
+
+    /** Get cache mock */
+    private Map<Integer, Integer> getCacheMock(int partsCnt) {
+        return IntStream.range(0, partsCnt).boxed().collect(Collectors.toMap(x -> x, x -> x));
+    }
+
+    /** Mock random numners generator. */
+    private static class MockRandom extends Random {
+        /** Serial version uuid. */
+        private static final long serialVersionUID = -7738558243461112988L;
+
+        /** Start value. */
+        private int startVal;
+
+        /** Iteration. */
+        private int iter;
+
+        /**
+         * Constructs instance of this class with a specified start value.
+         *
+         * @param startVal Start value.
+         */
+        MockRandom(int startVal) {
+            this.startVal = startVal;
+            iter = 0;
+        }
+
+        /** {@inheritDoc} */
+        @Override public int nextInt() {
+            iter++;
+            return startVal * iter;
+        }
     }
 }
 
diff --git a/modules/ml/src/test/java/org/apache/ignite/ml/inference/InferenceTestSuite.java b/modules/ml/src/test/java/org/apache/ignite/ml/inference/InferenceTestSuite.java
index f2ead5a..7546b16 100644
--- a/modules/ml/src/test/java/org/apache/ignite/ml/inference/InferenceTestSuite.java
+++ b/modules/ml/src/test/java/org/apache/ignite/ml/inference/InferenceTestSuite.java
@@ -20,6 +20,7 @@
 import org.apache.ignite.ml.inference.builder.IgniteDistributedInfModelBuilderTest;
 import org.apache.ignite.ml.inference.builder.SingleInfModelBuilderTest;
 import org.apache.ignite.ml.inference.builder.ThreadedInfModelBuilderTest;
+import org.apache.ignite.ml.inference.storage.model.DefaultModelStorageTest;
 import org.apache.ignite.ml.inference.util.DirectorySerializerTest;
 import org.junit.runner.RunWith;
 import org.junit.runners.Suite;
@@ -32,7 +33,8 @@
     IgniteDistributedInfModelBuilderTest.class,
     SingleInfModelBuilderTest.class,
     ThreadedInfModelBuilderTest.class,
-    DirectorySerializerTest.class
+    DirectorySerializerTest.class,
+    DefaultModelStorageTest.class
 })
 public class InferenceTestSuite {
 }
diff --git a/modules/ml/src/test/java/org/apache/ignite/ml/inference/storage/model/AbstractModelStorageTest.java b/modules/ml/src/test/java/org/apache/ignite/ml/inference/storage/model/AbstractModelStorageTest.java
new file mode 100644
index 0000000..84e2a85
--- /dev/null
+++ b/modules/ml/src/test/java/org/apache/ignite/ml/inference/storage/model/AbstractModelStorageTest.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.ml.inference.storage.model;
+
+import java.util.Set;
+import org.junit.Test;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Base tests for all implementation of {@link ModelStorage}.
+ */
+public abstract class AbstractModelStorageTest {
+    /**
+     * Returns model storage to be tested.
+     *
+     * @return Model storage to be tested.
+     */
+    abstract ModelStorage getModelStorage();
+
+    /** */
+    @Test
+    public void testPutGetRemoveFile() {
+        ModelStorage mdlStorage = getModelStorage();
+
+        byte[] data = new byte[]{1, 2, 3, 4, 5};
+
+        mdlStorage.mkdirs("/");
+        mdlStorage.putFile("/test", data);
+
+        assertTrue(mdlStorage.exists("/test"));
+        assertArrayEquals(data, mdlStorage.getFile("/test"));
+
+        mdlStorage.remove("/test");
+
+        assertFalse(mdlStorage.exists("/test"));
+    }
+
+    /** */
+    @Test
+    public void testListDirectory() {
+        ModelStorage mdlStorage = getModelStorage();
+
+        mdlStorage.mkdirs("/a/b");
+        mdlStorage.mkdirs("/a/c");
+        mdlStorage.putFile("/a/test", new byte[0]);
+
+        Set<String> aFiles = mdlStorage.listFiles("/a");
+        Set<String> bFiles = mdlStorage.listFiles("/a/b");
+        Set<String> cFiles = mdlStorage.listFiles("/a/c");
+
+        assertEquals(3, aFiles.size());
+        assertTrue(bFiles.isEmpty());
+        assertTrue(cFiles.isEmpty());
+
+        assertTrue(aFiles.contains("/a/b"));
+        assertTrue(aFiles.contains("/a/c"));
+        assertTrue(aFiles.contains("/a/test"));
+    }
+
+    /** */
+    @Test
+    public void testIsDirectory() {
+        ModelStorage mdlStorage = getModelStorage();
+
+        mdlStorage.mkdirs("/a");
+
+        assertTrue(mdlStorage.exists("/a"));
+        assertTrue(mdlStorage.isDirectory("/a"));
+        assertFalse(mdlStorage.isFile("/a"));
+    }
+
+    /** */
+    @Test
+    public void testIsFile() {
+        ModelStorage mdlStorage = getModelStorage();
+
+        mdlStorage.mkdirs("/");
+        mdlStorage.putFile("/test", new byte[0]);
+
+        assertTrue(mdlStorage.exists("/test"));
+        assertTrue(mdlStorage.isFile("/test"));
+        assertFalse(mdlStorage.isDirectory("/test"));
+    }
+
+    /** */
+    @Test
+    public void testRemoveDirectory() {
+        ModelStorage mdlStorage = getModelStorage();
+
+        mdlStorage.mkdirs("/a/b/c");
+        mdlStorage.mkdirs("/a/b/d");
+        mdlStorage.mkdirs("/a/c");
+        mdlStorage.putFile("/a/b/c/test", new byte[0]);
+        mdlStorage.putFile("/a/b/test", new byte[0]);
+
+        mdlStorage.remove("/a/b");
+
+        assertFalse(mdlStorage.exists("/a/b"));
+        assertFalse(mdlStorage.exists("/a/b/c"));
+        assertFalse(mdlStorage.exists("/a/b/d"));
+        assertFalse(mdlStorage.exists("/a/b/test"));
+        assertFalse(mdlStorage.exists("/a/b/c/test"));
+
+        assertTrue(mdlStorage.exists("/a"));
+        assertTrue(mdlStorage.exists("/a/c"));
+    }
+
+    /** */
+    @Test(expected = IllegalArgumentException.class)
+    public void testPutFileIntoNonExistingDirectory() {
+        ModelStorage mdlStorage = getModelStorage();
+
+        mdlStorage.putFile("/test", new byte[0]);
+    }
+
+    /** */
+    @Test(expected = IllegalArgumentException.class)
+    public void testMakeDirInNonExistingDirectory() {
+        ModelStorage mdlStorage = getModelStorage();
+
+        mdlStorage.mkdir("/test");
+    }
+}
diff --git a/modules/ml/src/test/java/org/apache/ignite/ml/inference/storage/model/DefaultModelStorageTest.java b/modules/ml/src/test/java/org/apache/ignite/ml/inference/storage/model/DefaultModelStorageTest.java
new file mode 100644
index 0000000..2c2a678
--- /dev/null
+++ b/modules/ml/src/test/java/org/apache/ignite/ml/inference/storage/model/DefaultModelStorageTest.java
@@ -0,0 +1,143 @@
+/*
+ * 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.ml.inference.storage.model;
+
+import java.util.concurrent.locks.Lock;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+
+/**
+ * Tests for {@link DefaultModelStorage}.
+ */
+public class DefaultModelStorageTest extends AbstractModelStorageTest {
+    /** {@inheritDoc} */
+    @Override ModelStorage getModelStorage() {
+        ModelStorageProvider provider = new LocalModelStorageProvider();
+        return new DefaultModelStorage(provider);
+    }
+
+    /** */
+    @Test
+    public void testSynchronize() {
+        Lock[] locks = new Lock[10];
+        for (int i = 0; i < locks.length; i++)
+            locks[i] = mock(Lock.class);
+
+        DefaultModelStorage.synchronize(() -> {}, locks);
+
+        for (Lock lock : locks) {
+            verify(lock, times(1)).lock();
+            verify(lock, times(1)).unlock();
+            verifyNoMoreInteractions(lock);
+        }
+    }
+
+    /** */
+    @Test
+    public void testSynchronizeWithExceptionInTask() {
+        Lock[] locks = new Lock[10];
+        for (int i = 0; i < locks.length; i++)
+            locks[i] = mock(Lock.class);
+
+        RuntimeException ex = new RuntimeException();
+
+        try {
+            DefaultModelStorage.synchronize(() -> { throw ex; }, locks);
+            fail();
+        }
+        catch (RuntimeException e) {
+            assertEquals(ex, e);
+        }
+
+        for (Lock lock : locks) {
+            verify(lock, times(1)).lock();
+            verify(lock, times(1)).unlock();
+            verifyNoMoreInteractions(lock);
+        }
+    }
+
+    /** */
+    @Test
+    public void testSynchronizeWithExceptionInLock() {
+        Lock[] locks = new Lock[10];
+        for (int i = 0; i < locks.length; i++)
+            locks[i] = mock(Lock.class);
+
+        RuntimeException ex = new RuntimeException();
+
+        doThrow(ex).when(locks[5]).lock();
+
+        try {
+            DefaultModelStorage.synchronize(() -> {}, locks);
+            fail();
+        }
+        catch (RuntimeException e) {
+            assertEquals(ex, e);
+        }
+
+        for (int i = 0; i < locks.length; i++) {
+            if (i <= 4) {
+                verify(locks[i], times(1)).lock();
+                verify(locks[i], times(1)).unlock();
+            }
+            else if (i > 5) {
+                verify(locks[i], times(0)).lock();
+                verify(locks[i], times(0)).unlock();
+            }
+            else {
+                verify(locks[i], times(1)).lock();
+                verify(locks[i], times(0)).unlock();
+            }
+
+            verifyNoMoreInteractions(locks[i]);
+        }
+    }
+
+    /** */
+    @Test
+    public void testSynchronizeWithExceptionInUnlock() {
+        Lock[] locks = new Lock[10];
+        for (int i = 0; i < locks.length; i++)
+            locks[i] = mock(Lock.class);
+
+        RuntimeException ex = new RuntimeException();
+
+        doThrow(ex).when(locks[5]).unlock();
+
+        try {
+            DefaultModelStorage.synchronize(() -> {}, locks);
+            fail();
+        }
+        catch (RuntimeException e) {
+            assertEquals(ex, e);
+        }
+
+        for (Lock lock : locks) {
+            verify(lock, times(1)).lock();
+            verify(lock, times(1)).unlock();
+            verifyNoMoreInteractions(lock);
+        }
+    }
+}
diff --git a/modules/ml/src/test/java/org/apache/ignite/ml/math/isolve/lsqr/LSQROnHeapTest.java b/modules/ml/src/test/java/org/apache/ignite/ml/math/isolve/lsqr/LSQROnHeapTest.java
index b720695..b743a37 100644
--- a/modules/ml/src/test/java/org/apache/ignite/ml/math/isolve/lsqr/LSQROnHeapTest.java
+++ b/modules/ml/src/test/java/org/apache/ignite/ml/math/isolve/lsqr/LSQROnHeapTest.java
@@ -20,6 +20,7 @@
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Map;
+import org.apache.ignite.ml.TestUtils;
 import org.apache.ignite.ml.common.TrainerTest;
 import org.apache.ignite.ml.dataset.DatasetBuilder;
 import org.apache.ignite.ml.dataset.impl.local.LocalDatasetBuilder;
@@ -47,6 +48,7 @@
 
         LSQROnHeap<Integer, double[]> lsqr = new LSQROnHeap<>(
             datasetBuilder,
+            TestUtils.testEnvBuilder(),
             new SimpleLabeledDatasetDataBuilder<>(
                 (k, v) -> VectorUtils.of(Arrays.copyOf(v, v.length - 1)),
                 (k, v) -> new double[]{v[3]}
@@ -80,6 +82,7 @@
 
         LSQROnHeap<Integer, double[]> lsqr = new LSQROnHeap<>(
             datasetBuilder,
+            TestUtils.testEnvBuilder(),
             new SimpleLabeledDatasetDataBuilder<>(
                 (k, v) -> VectorUtils.of(Arrays.copyOf(v, v.length - 1)),
                 (k, v) -> new double[]{v[3]}
@@ -113,6 +116,7 @@
 
         try (LSQROnHeap<Integer, double[]> lsqr = new LSQROnHeap<>(
             datasetBuilder,
+            TestUtils.testEnvBuilder(),
             new SimpleLabeledDatasetDataBuilder<>(
                 (k, v) -> VectorUtils.of(Arrays.copyOf(v, v.length - 1)),
                 (k, v) -> new double[]{v[4]}
diff --git a/modules/ml/src/test/java/org/apache/ignite/ml/multiclass/OneVsRestTrainerTest.java b/modules/ml/src/test/java/org/apache/ignite/ml/multiclass/OneVsRestTrainerTest.java
index 9842d92..61f9fc4 100644
--- a/modules/ml/src/test/java/org/apache/ignite/ml/multiclass/OneVsRestTrainerTest.java
+++ b/modules/ml/src/test/java/org/apache/ignite/ml/multiclass/OneVsRestTrainerTest.java
@@ -28,8 +28,8 @@
 import org.apache.ignite.ml.nn.UpdatesStrategy;
 import org.apache.ignite.ml.optimization.updatecalculators.SimpleGDParameterUpdate;
 import org.apache.ignite.ml.optimization.updatecalculators.SimpleGDUpdateCalculator;
-import org.apache.ignite.ml.regressions.logistic.binomial.LogisticRegressionModel;
-import org.apache.ignite.ml.regressions.logistic.binomial.LogisticRegressionSGDTrainer;
+import org.apache.ignite.ml.regressions.logistic.LogisticRegressionModel;
+import org.apache.ignite.ml.regressions.logistic.LogisticRegressionSGDTrainer;
 import org.junit.Assert;
 import org.junit.Test;
 
diff --git a/modules/ml/src/test/java/org/apache/ignite/ml/pipeline/PipelineMdlTest.java b/modules/ml/src/test/java/org/apache/ignite/ml/pipeline/PipelineMdlTest.java
index e59d515..8445900 100644
--- a/modules/ml/src/test/java/org/apache/ignite/ml/pipeline/PipelineMdlTest.java
+++ b/modules/ml/src/test/java/org/apache/ignite/ml/pipeline/PipelineMdlTest.java
@@ -20,7 +20,7 @@
 import org.apache.ignite.ml.TestUtils;
 import org.apache.ignite.ml.math.primitives.vector.Vector;
 import org.apache.ignite.ml.math.primitives.vector.impl.DenseVector;
-import org.apache.ignite.ml.regressions.logistic.binomial.LogisticRegressionModel;
+import org.apache.ignite.ml.regressions.logistic.LogisticRegressionModel;
 import org.junit.Test;
 
 /**
diff --git a/modules/ml/src/test/java/org/apache/ignite/ml/pipeline/PipelineTest.java b/modules/ml/src/test/java/org/apache/ignite/ml/pipeline/PipelineTest.java
index d517ce6..fec6220 100644
--- a/modules/ml/src/test/java/org/apache/ignite/ml/pipeline/PipelineTest.java
+++ b/modules/ml/src/test/java/org/apache/ignite/ml/pipeline/PipelineTest.java
@@ -29,7 +29,7 @@
 import org.apache.ignite.ml.optimization.updatecalculators.SimpleGDUpdateCalculator;
 import org.apache.ignite.ml.preprocessing.minmaxscaling.MinMaxScalerTrainer;
 import org.apache.ignite.ml.preprocessing.normalization.NormalizationTrainer;
-import org.apache.ignite.ml.regressions.logistic.binomial.LogisticRegressionSGDTrainer;
+import org.apache.ignite.ml.regressions.logistic.LogisticRegressionSGDTrainer;
 import org.junit.Test;
 
 /**
diff --git a/modules/ml/src/test/java/org/apache/ignite/ml/preprocessing/binarization/BinarizationTrainerTest.java b/modules/ml/src/test/java/org/apache/ignite/ml/preprocessing/binarization/BinarizationTrainerTest.java
index 4b7fa33..b611104 100644
--- a/modules/ml/src/test/java/org/apache/ignite/ml/preprocessing/binarization/BinarizationTrainerTest.java
+++ b/modules/ml/src/test/java/org/apache/ignite/ml/preprocessing/binarization/BinarizationTrainerTest.java
@@ -19,6 +19,7 @@
 
 import java.util.HashMap;
 import java.util.Map;
+import org.apache.ignite.ml.TestUtils;
 import org.apache.ignite.ml.common.TrainerTest;
 import org.apache.ignite.ml.dataset.DatasetBuilder;
 import org.apache.ignite.ml.dataset.impl.local.LocalDatasetBuilder;
@@ -51,6 +52,7 @@
         assertEquals(10., binarizationTrainer.getThreshold(), 0);
 
         BinarizationPreprocessor<Integer, double[]> preprocessor = binarizationTrainer.fit(
+            TestUtils.testEnvBuilder(),
             datasetBuilder,
             (k, v) -> VectorUtils.of(v)
         );
@@ -75,6 +77,7 @@
         assertEquals(10., binarizationTrainer.getThreshold(), 0);
 
         IgniteBiFunction<Integer, double[], Vector> preprocessor = binarizationTrainer.fit(
+            TestUtils.testEnvBuilder(),
             data,
             parts,
             (k, v) -> VectorUtils.of(v)
diff --git a/modules/ml/src/test/java/org/apache/ignite/ml/preprocessing/encoding/EncoderTrainerTest.java b/modules/ml/src/test/java/org/apache/ignite/ml/preprocessing/encoding/EncoderTrainerTest.java
index 7c7eabe..f9d56a9 100644
--- a/modules/ml/src/test/java/org/apache/ignite/ml/preprocessing/encoding/EncoderTrainerTest.java
+++ b/modules/ml/src/test/java/org/apache/ignite/ml/preprocessing/encoding/EncoderTrainerTest.java
@@ -19,6 +19,7 @@
 
 import java.util.HashMap;
 import java.util.Map;
+import org.apache.ignite.ml.TestUtils;
 import org.apache.ignite.ml.common.TrainerTest;
 import org.apache.ignite.ml.dataset.DatasetBuilder;
 import org.apache.ignite.ml.dataset.impl.local.LocalDatasetBuilder;
@@ -51,6 +52,7 @@
             .withEncodedFeature(1);
 
         EncoderPreprocessor<Integer, String[]> preprocessor = strEncoderTrainer.fit(
+            TestUtils.testEnvBuilder(),
             datasetBuilder,
             (k, v) -> v
         );
@@ -77,6 +79,7 @@
             .withEncodedFeature(1);
 
         EncoderPreprocessor<Integer, Object[]> preprocessor = strEncoderTrainer.fit(
+            TestUtils.testEnvBuilder(),
             datasetBuilder,
             (k, v) -> v
         );
@@ -103,6 +106,7 @@
             .withEncodedFeature(1);
 
         EncoderPreprocessor<Integer, Object[]> preprocessor = strEncoderTrainer.fit(
+            TestUtils.testEnvBuilder(),
             datasetBuilder,
             (k, v) -> v
         );
@@ -136,6 +140,7 @@
             .withEncodedFeature(1);
 
         EncoderPreprocessor<Integer, String[]> preprocessor = strEncoderTrainer.fit(
+            TestUtils.testEnvBuilder(),
             datasetBuilder,
             (k, v) -> v
         );
diff --git a/modules/ml/src/test/java/org/apache/ignite/ml/preprocessing/imputing/ImputerTrainerTest.java b/modules/ml/src/test/java/org/apache/ignite/ml/preprocessing/imputing/ImputerTrainerTest.java
index 9c11d13..f8a5e78 100644
--- a/modules/ml/src/test/java/org/apache/ignite/ml/preprocessing/imputing/ImputerTrainerTest.java
+++ b/modules/ml/src/test/java/org/apache/ignite/ml/preprocessing/imputing/ImputerTrainerTest.java
@@ -19,6 +19,7 @@
 
 import java.util.HashMap;
 import java.util.Map;
+import org.apache.ignite.ml.TestUtils;
 import org.apache.ignite.ml.common.TrainerTest;
 import org.apache.ignite.ml.dataset.DatasetBuilder;
 import org.apache.ignite.ml.dataset.impl.local.LocalDatasetBuilder;
@@ -47,6 +48,7 @@
             .withImputingStrategy(ImputingStrategy.MOST_FREQUENT);
 
         ImputerPreprocessor<Integer, Vector> preprocessor = imputerTrainer.fit(
+            TestUtils.testEnvBuilder(),
             datasetBuilder,
             (k, v) -> v
         );
diff --git a/modules/ml/src/test/java/org/apache/ignite/ml/preprocessing/maxabsscaling/MaxAbsScalerTrainerTest.java b/modules/ml/src/test/java/org/apache/ignite/ml/preprocessing/maxabsscaling/MaxAbsScalerTrainerTest.java
index 844468e..fc3433b 100644
--- a/modules/ml/src/test/java/org/apache/ignite/ml/preprocessing/maxabsscaling/MaxAbsScalerTrainerTest.java
+++ b/modules/ml/src/test/java/org/apache/ignite/ml/preprocessing/maxabsscaling/MaxAbsScalerTrainerTest.java
@@ -19,6 +19,7 @@
 
 import java.util.HashMap;
 import java.util.Map;
+import org.apache.ignite.ml.TestUtils;
 import org.apache.ignite.ml.common.TrainerTest;
 import org.apache.ignite.ml.dataset.DatasetBuilder;
 import org.apache.ignite.ml.dataset.impl.local.LocalDatasetBuilder;
@@ -46,6 +47,7 @@
         MaxAbsScalerTrainer<Integer, Vector> standardizationTrainer = new MaxAbsScalerTrainer<>();
 
         MaxAbsScalerPreprocessor<Integer, Vector> preprocessor = standardizationTrainer.fit(
+            TestUtils.testEnvBuilder(),
             datasetBuilder,
             (k, v) -> v
         );
diff --git a/modules/ml/src/test/java/org/apache/ignite/ml/preprocessing/minmaxscaling/MinMaxScalerTrainerTest.java b/modules/ml/src/test/java/org/apache/ignite/ml/preprocessing/minmaxscaling/MinMaxScalerTrainerTest.java
index 4c0a99f..8716324 100644
--- a/modules/ml/src/test/java/org/apache/ignite/ml/preprocessing/minmaxscaling/MinMaxScalerTrainerTest.java
+++ b/modules/ml/src/test/java/org/apache/ignite/ml/preprocessing/minmaxscaling/MinMaxScalerTrainerTest.java
@@ -19,6 +19,7 @@
 
 import java.util.HashMap;
 import java.util.Map;
+import org.apache.ignite.ml.TestUtils;
 import org.apache.ignite.ml.common.TrainerTest;
 import org.apache.ignite.ml.dataset.DatasetBuilder;
 import org.apache.ignite.ml.dataset.impl.local.LocalDatasetBuilder;
@@ -46,6 +47,7 @@
         MinMaxScalerTrainer<Integer, Vector> standardizationTrainer = new MinMaxScalerTrainer<>();
 
         MinMaxScalerPreprocessor<Integer, Vector> preprocessor = standardizationTrainer.fit(
+            TestUtils.testEnvBuilder(),
             datasetBuilder,
             (k, v) -> v
         );
diff --git a/modules/ml/src/test/java/org/apache/ignite/ml/preprocessing/normalization/NormalizationTrainerTest.java b/modules/ml/src/test/java/org/apache/ignite/ml/preprocessing/normalization/NormalizationTrainerTest.java
index 9d39354..d8a8191 100644
--- a/modules/ml/src/test/java/org/apache/ignite/ml/preprocessing/normalization/NormalizationTrainerTest.java
+++ b/modules/ml/src/test/java/org/apache/ignite/ml/preprocessing/normalization/NormalizationTrainerTest.java
@@ -19,6 +19,7 @@
 
 import java.util.HashMap;
 import java.util.Map;
+import org.apache.ignite.ml.TestUtils;
 import org.apache.ignite.ml.common.TrainerTest;
 import org.apache.ignite.ml.dataset.DatasetBuilder;
 import org.apache.ignite.ml.dataset.impl.local.LocalDatasetBuilder;
@@ -50,6 +51,7 @@
         assertEquals(3., normalizationTrainer.p(), 0);
 
         NormalizationPreprocessor<Integer, double[]> preprocessor = normalizationTrainer.fit(
+            TestUtils.testEnvBuilder(),
             datasetBuilder,
             (k, v) -> VectorUtils.of(v)
         );
diff --git a/modules/ml/src/test/java/org/apache/ignite/ml/preprocessing/standardscaling/StandardScalerTrainerTest.java b/modules/ml/src/test/java/org/apache/ignite/ml/preprocessing/standardscaling/StandardScalerTrainerTest.java
index 6f10b37..839cb20 100644
--- a/modules/ml/src/test/java/org/apache/ignite/ml/preprocessing/standardscaling/StandardScalerTrainerTest.java
+++ b/modules/ml/src/test/java/org/apache/ignite/ml/preprocessing/standardscaling/StandardScalerTrainerTest.java
@@ -19,6 +19,7 @@
 
 import java.util.HashMap;
 import java.util.Map;
+import org.apache.ignite.ml.TestUtils;
 import org.apache.ignite.ml.common.TrainerTest;
 import org.apache.ignite.ml.dataset.DatasetBuilder;
 import org.apache.ignite.ml.dataset.impl.local.LocalDatasetBuilder;
@@ -62,6 +63,7 @@
         double[] expectedMeans = new double[] {0.5, 1.75, 4.5, 0.875};
 
         StandardScalerPreprocessor<Integer, Vector> preprocessor = standardizationTrainer.fit(
+            TestUtils.testEnvBuilder(),
             datasetBuilder,
             (k, v) -> v
         );
@@ -75,6 +77,7 @@
         double[] expectedSigmas = new double[] {0.5, 1.47901995, 14.51723114, 0.93374247};
 
         StandardScalerPreprocessor<Integer, Vector> preprocessor = standardizationTrainer.fit(
+            TestUtils.testEnvBuilder(),
             datasetBuilder,
             (k, v) -> v
         );
diff --git a/modules/ml/src/test/java/org/apache/ignite/ml/regressions/RegressionsTestSuite.java b/modules/ml/src/test/java/org/apache/ignite/ml/regressions/RegressionsTestSuite.java
index 021b567..2fa69ef 100644
--- a/modules/ml/src/test/java/org/apache/ignite/ml/regressions/RegressionsTestSuite.java
+++ b/modules/ml/src/test/java/org/apache/ignite/ml/regressions/RegressionsTestSuite.java
@@ -20,7 +20,6 @@
 import org.apache.ignite.ml.regressions.linear.LinearRegressionLSQRTrainerTest;
 import org.apache.ignite.ml.regressions.linear.LinearRegressionModelTest;
 import org.apache.ignite.ml.regressions.linear.LinearRegressionSGDTrainerTest;
-import org.apache.ignite.ml.regressions.logistic.LogRegMultiClassTrainerTest;
 import org.apache.ignite.ml.regressions.logistic.LogisticRegressionModelTest;
 import org.apache.ignite.ml.regressions.logistic.LogisticRegressionSGDTrainerTest;
 import org.junit.runner.RunWith;
@@ -35,8 +34,7 @@
     LinearRegressionLSQRTrainerTest.class,
     LinearRegressionSGDTrainerTest.class,
     LogisticRegressionModelTest.class,
-    LogisticRegressionSGDTrainerTest.class,
-    LogRegMultiClassTrainerTest.class
+    LogisticRegressionSGDTrainerTest.class
 })
 public class RegressionsTestSuite {
     // No-op.
diff --git a/modules/ml/src/test/java/org/apache/ignite/ml/regressions/linear/LinearRegressionModelTest.java b/modules/ml/src/test/java/org/apache/ignite/ml/regressions/linear/LinearRegressionModelTest.java
index 66871b0..36d0fc7 100644
--- a/modules/ml/src/test/java/org/apache/ignite/ml/regressions/linear/LinearRegressionModelTest.java
+++ b/modules/ml/src/test/java/org/apache/ignite/ml/regressions/linear/LinearRegressionModelTest.java
@@ -21,8 +21,6 @@
 import org.apache.ignite.ml.math.exceptions.CardinalityException;
 import org.apache.ignite.ml.math.primitives.vector.Vector;
 import org.apache.ignite.ml.math.primitives.vector.impl.DenseVector;
-import org.apache.ignite.ml.regressions.logistic.binomial.LogisticRegressionModel;
-import org.apache.ignite.ml.regressions.logistic.multiclass.LogRegressionMultiClassModel;
 import org.junit.Test;
 
 import static org.junit.Assert.assertTrue;
@@ -40,9 +38,9 @@
         Vector weights = new DenseVector(new double[]{2.0, 3.0});
         LinearRegressionModel mdl = new LinearRegressionModel(weights, 1.0);
 
-        assertTrue(mdl.toString().length() > 0);
-        assertTrue(mdl.toString(true).length() > 0);
-        assertTrue(mdl.toString(false).length() > 0);
+        assertTrue(!mdl.toString().isEmpty());
+        assertTrue(!mdl.toString(true).isEmpty());
+        assertTrue(!mdl.toString(false).isEmpty());
 
         Vector observation = new DenseVector(new double[]{1.0, 1.0});
         TestUtils.assertEquals(1.0 + 2.0 * 1.0 + 3.0 * 1.0, mdl.apply(observation), PRECISION);
@@ -61,21 +59,6 @@
     }
 
     /** */
-    @Test
-    public void testPredictWithMultiClasses() {
-        Vector weights1 = new DenseVector(new double[]{10.0, 0.0});
-        Vector weights2 = new DenseVector(new double[]{0.0, 10.0});
-        Vector weights3 = new DenseVector(new double[]{-1.0, -1.0});
-        LogRegressionMultiClassModel mdl = new LogRegressionMultiClassModel();
-        mdl.add(1, new LogisticRegressionModel(weights1, 0.0).withRawLabels(true));
-        mdl.add(2, new LogisticRegressionModel(weights2, 0.0).withRawLabels(true));
-        mdl.add(2, new LogisticRegressionModel(weights3, 0.0).withRawLabels(true));
-
-        Vector observation = new DenseVector(new double[]{1.0, 1.0});
-        TestUtils.assertEquals( 1.0, mdl.apply(observation), PRECISION);
-    }
-
-    /** */
     @Test(expected = CardinalityException.class)
     public void testPredictOnAnObservationWithWrongCardinality() {
         Vector weights = new DenseVector(new double[]{2.0, 3.0});
diff --git a/modules/ml/src/test/java/org/apache/ignite/ml/regressions/logistic/LogRegMultiClassTrainerTest.java b/modules/ml/src/test/java/org/apache/ignite/ml/regressions/logistic/LogRegMultiClassTrainerTest.java
deleted file mode 100644
index c99bf02..0000000
--- a/modules/ml/src/test/java/org/apache/ignite/ml/regressions/logistic/LogRegMultiClassTrainerTest.java
+++ /dev/null
@@ -1,141 +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.ml.regressions.logistic;
-
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import org.apache.ignite.ml.TestUtils;
-import org.apache.ignite.ml.common.TrainerTest;
-import org.apache.ignite.ml.math.primitives.vector.Vector;
-import org.apache.ignite.ml.math.primitives.vector.VectorUtils;
-import org.apache.ignite.ml.nn.UpdatesStrategy;
-import org.apache.ignite.ml.optimization.SmoothParametrized;
-import org.apache.ignite.ml.optimization.updatecalculators.SimpleGDParameterUpdate;
-import org.apache.ignite.ml.optimization.updatecalculators.SimpleGDUpdateCalculator;
-import org.apache.ignite.ml.regressions.logistic.multiclass.LogRegressionMultiClassModel;
-import org.apache.ignite.ml.regressions.logistic.multiclass.LogRegressionMultiClassTrainer;
-import org.junit.Assert;
-import org.junit.Test;
-
-/**
- * Tests for {@link LogRegressionMultiClassTrainer}.
- */
-public class LogRegMultiClassTrainerTest extends TrainerTest {
-    /**
-     * Test trainer on 4 sets grouped around of square vertices.
-     */
-    @Test
-    public void testTrainWithTheLinearlySeparableCase() {
-        Map<Integer, double[]> cacheMock = new HashMap<>();
-
-        for (int i = 0; i < fourSetsInSquareVertices.length; i++)
-            cacheMock.put(i, fourSetsInSquareVertices[i]);
-
-        final UpdatesStrategy<SmoothParametrized, SimpleGDParameterUpdate> stgy = new UpdatesStrategy<>(
-            new SimpleGDUpdateCalculator(0.2),
-            SimpleGDParameterUpdate::sumLocal,
-            SimpleGDParameterUpdate::avg
-        );
-
-        LogRegressionMultiClassTrainer<?> trainer = new LogRegressionMultiClassTrainer<>()
-            .withUpdatesStgy(stgy)
-            .withAmountOfIterations(1000)
-            .withAmountOfLocIterations(10)
-            .withBatchSize(100)
-            .withSeed(123L);
-
-        Assert.assertEquals(trainer.getAmountOfIterations(), 1000);
-        Assert.assertEquals(trainer.getAmountOfLocIterations(), 10);
-        Assert.assertEquals(trainer.getBatchSize(), 100, PRECISION);
-        Assert.assertEquals(trainer.seed(), 123L);
-        Assert.assertEquals(trainer.getUpdatesStgy(), stgy);
-
-        LogRegressionMultiClassModel mdl = trainer.fit(
-            cacheMock,
-            parts,
-            (k, v) -> VectorUtils.of(Arrays.copyOfRange(v, 1, v.length)),
-            (k, v) -> v[0]
-        );
-
-        Assert.assertTrue(mdl.toString().length() > 0);
-        Assert.assertTrue(mdl.toString(true).length() > 0);
-        Assert.assertTrue(mdl.toString(false).length() > 0);
-
-        TestUtils.assertEquals(1, mdl.apply(VectorUtils.of(10, 10)), PRECISION);
-        TestUtils.assertEquals(1, mdl.apply(VectorUtils.of(-10, 10)), PRECISION);
-        TestUtils.assertEquals(2, mdl.apply(VectorUtils.of(-10, -10)), PRECISION);
-        TestUtils.assertEquals(3, mdl.apply(VectorUtils.of(10, -10)), PRECISION);
-    }
-
-    /** */
-    @Test
-    public void testUpdate() {
-        Map<Integer, double[]> cacheMock = new HashMap<>();
-
-        for (int i = 0; i < fourSetsInSquareVertices.length; i++)
-            cacheMock.put(i, fourSetsInSquareVertices[i]);
-
-        LogRegressionMultiClassTrainer<?> trainer = new LogRegressionMultiClassTrainer<>()
-            .withUpdatesStgy(new UpdatesStrategy<>(
-                new SimpleGDUpdateCalculator(0.2),
-                SimpleGDParameterUpdate::sumLocal,
-                SimpleGDParameterUpdate::avg
-            ))
-            .withAmountOfIterations(1000)
-            .withAmountOfLocIterations(10)
-            .withBatchSize(100)
-            .withSeed(123L);
-
-        LogRegressionMultiClassModel originalMdl = trainer.fit(
-            cacheMock,
-            parts,
-            (k, v) -> VectorUtils.of(Arrays.copyOfRange(v, 1, v.length)),
-            (k, v) -> v[0]
-        );
-
-        LogRegressionMultiClassModel updatedOnSameDS = trainer.update(
-            originalMdl,
-            cacheMock,
-            parts,
-            (k, v) -> VectorUtils.of(Arrays.copyOfRange(v, 1, v.length)),
-            (k, v) -> v[0]
-        );
-
-        LogRegressionMultiClassModel updatedOnEmptyDS = trainer.update(
-            originalMdl,
-            new HashMap<Integer, double[]>(),
-            parts,
-            (k, v) -> VectorUtils.of(Arrays.copyOfRange(v, 1, v.length)),
-            (k, v) -> v[0]
-        );
-
-        List<Vector> vectors = Arrays.asList(
-            VectorUtils.of(10, 10),
-            VectorUtils.of(-10, 10),
-            VectorUtils.of(-10, -10),
-            VectorUtils.of(10, -10)
-        );
-
-        for (Vector vec : vectors) {
-            TestUtils.assertEquals(originalMdl.apply(vec), updatedOnSameDS.apply(vec), PRECISION);
-            TestUtils.assertEquals(originalMdl.apply(vec), updatedOnEmptyDS.apply(vec), PRECISION);
-        }
-    }
-}
diff --git a/modules/ml/src/test/java/org/apache/ignite/ml/regressions/logistic/LogisticRegressionModelTest.java b/modules/ml/src/test/java/org/apache/ignite/ml/regressions/logistic/LogisticRegressionModelTest.java
index e8aaacd..4fae638 100644
--- a/modules/ml/src/test/java/org/apache/ignite/ml/regressions/logistic/LogisticRegressionModelTest.java
+++ b/modules/ml/src/test/java/org/apache/ignite/ml/regressions/logistic/LogisticRegressionModelTest.java
@@ -21,7 +21,6 @@
 import org.apache.ignite.ml.math.exceptions.CardinalityException;
 import org.apache.ignite.ml.math.primitives.vector.Vector;
 import org.apache.ignite.ml.math.primitives.vector.impl.DenseVector;
-import org.apache.ignite.ml.regressions.logistic.binomial.LogisticRegressionModel;
 import org.junit.Test;
 
 import static org.junit.Assert.assertEquals;
diff --git a/modules/ml/src/test/java/org/apache/ignite/ml/regressions/logistic/LogisticRegressionSGDTrainerTest.java b/modules/ml/src/test/java/org/apache/ignite/ml/regressions/logistic/LogisticRegressionSGDTrainerTest.java
index d9b6f7a..c343ab9 100644
--- a/modules/ml/src/test/java/org/apache/ignite/ml/regressions/logistic/LogisticRegressionSGDTrainerTest.java
+++ b/modules/ml/src/test/java/org/apache/ignite/ml/regressions/logistic/LogisticRegressionSGDTrainerTest.java
@@ -27,8 +27,6 @@
 import org.apache.ignite.ml.nn.UpdatesStrategy;
 import org.apache.ignite.ml.optimization.updatecalculators.SimpleGDParameterUpdate;
 import org.apache.ignite.ml.optimization.updatecalculators.SimpleGDUpdateCalculator;
-import org.apache.ignite.ml.regressions.logistic.binomial.LogisticRegressionModel;
-import org.apache.ignite.ml.regressions.logistic.binomial.LogisticRegressionSGDTrainer;
 import org.junit.Test;
 
 /**
@@ -50,7 +48,7 @@
                 SimpleGDParameterUpdate::sumLocal, SimpleGDParameterUpdate::avg))
             .withMaxIterations(100000)
             .withLocIterations(100)
-            .withBatchSize(10)
+            .withBatchSize(14)
             .withSeed(123L);
 
         LogisticRegressionModel mdl = trainer.fit(
diff --git a/modules/ml/src/test/java/org/apache/ignite/ml/selection/scoring/evaluator/EvaluatorTest.java b/modules/ml/src/test/java/org/apache/ignite/ml/selection/scoring/evaluator/EvaluatorTest.java
index 6f7aa36..1abf7f0 100644
--- a/modules/ml/src/test/java/org/apache/ignite/ml/selection/scoring/evaluator/EvaluatorTest.java
+++ b/modules/ml/src/test/java/org/apache/ignite/ml/selection/scoring/evaluator/EvaluatorTest.java
@@ -48,6 +48,7 @@
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
 import org.apache.ignite.thread.IgniteThread;
 
+import static org.apache.ignite.ml.TestUtils.testEnvBuilder;
 import static org.junit.Assert.assertArrayEquals;
 
 /**
@@ -288,19 +289,24 @@
                 .withEncoderType(EncoderType.STRING_ENCODER)
                 .withEncodedFeature(1)
                 .withEncodedFeature(6) // <--- Changed index here
-                .fit(ignite,
+                .fit(
+                    testEnvBuilder(123L),
+                    ignite,
                     cache,
                     featureExtractor
                 );
 
             IgniteBiFunction<Integer, Object[], Vector> imputingPreprocessor = new ImputerTrainer<Integer, Object[]>()
-                .fit(ignite,
+                .fit(
+                    testEnvBuilder(124L),
+                    ignite,
                     cache,
                     strEncoderPreprocessor
                 );
 
             IgniteBiFunction<Integer, Object[], Vector> minMaxScalerPreprocessor = new MinMaxScalerTrainer<Integer, Object[]>()
                 .fit(
+                    testEnvBuilder(125L),
                     ignite,
                     cache,
                     imputingPreprocessor
@@ -309,6 +315,7 @@
             return new NormalizationTrainer<Integer, Object[]>()
                 .withP(2)
                 .fit(
+                    testEnvBuilder(126L),
                     ignite,
                     cache,
                     minMaxScalerPreprocessor
diff --git a/modules/ml/src/test/java/org/apache/ignite/ml/svm/SVMBinaryTrainerTest.java b/modules/ml/src/test/java/org/apache/ignite/ml/svm/SVMBinaryTrainerTest.java
index d6f77c0..ccde0d7 100644
--- a/modules/ml/src/test/java/org/apache/ignite/ml/svm/SVMBinaryTrainerTest.java
+++ b/modules/ml/src/test/java/org/apache/ignite/ml/svm/SVMBinaryTrainerTest.java
@@ -27,7 +27,7 @@
 import org.junit.Test;
 
 /**
- * Tests for {@link SVMLinearBinaryClassificationTrainer}.
+ * Tests for {@link SVMLinearClassificationTrainer}.
  */
 public class SVMBinaryTrainerTest extends TrainerTest {
     /**
@@ -40,10 +40,10 @@
         for (int i = 0; i < twoLinearlySeparableClasses.length; i++)
             cacheMock.put(i, twoLinearlySeparableClasses[i]);
 
-        SVMLinearBinaryClassificationTrainer trainer = new SVMLinearBinaryClassificationTrainer()
+        SVMLinearClassificationTrainer trainer = new SVMLinearClassificationTrainer()
             .withSeed(1234L);
 
-        SVMLinearBinaryClassificationModel mdl = trainer.fit(
+        SVMLinearClassificationModel mdl = trainer.fit(
             cacheMock,
             parts,
             (k, v) -> VectorUtils.of(Arrays.copyOfRange(v, 1, v.length)),
@@ -62,18 +62,18 @@
         for (int i = 0; i < twoLinearlySeparableClasses.length; i++)
             cacheMock.put(i, twoLinearlySeparableClasses[i]);
 
-        SVMLinearBinaryClassificationTrainer trainer = new SVMLinearBinaryClassificationTrainer()
+        SVMLinearClassificationTrainer trainer = new SVMLinearClassificationTrainer()
             .withAmountOfIterations(1000)
             .withSeed(1234L);
 
-        SVMLinearBinaryClassificationModel originalMdl = trainer.fit(
+        SVMLinearClassificationModel originalMdl = trainer.fit(
             cacheMock,
             parts,
             (k, v) -> VectorUtils.of(Arrays.copyOfRange(v, 1, v.length)),
             (k, v) -> v[0]
         );
 
-        SVMLinearBinaryClassificationModel updatedOnSameDS = trainer.update(
+        SVMLinearClassificationModel updatedOnSameDS = trainer.update(
             originalMdl,
             cacheMock,
             parts,
@@ -81,7 +81,7 @@
             (k, v) -> v[0]
         );
 
-        SVMLinearBinaryClassificationModel updatedOnEmptyDS = trainer.update(
+        SVMLinearClassificationModel updatedOnEmptyDS = trainer.update(
             originalMdl,
             new HashMap<Integer, double[]>(),
             parts,
diff --git a/modules/ml/src/test/java/org/apache/ignite/ml/svm/SVMModelTest.java b/modules/ml/src/test/java/org/apache/ignite/ml/svm/SVMModelTest.java
index 9c452f9..3bac790 100644
--- a/modules/ml/src/test/java/org/apache/ignite/ml/svm/SVMModelTest.java
+++ b/modules/ml/src/test/java/org/apache/ignite/ml/svm/SVMModelTest.java
@@ -36,7 +36,7 @@
     @Test
     public void testPredictWithRawLabels() {
         Vector weights = new DenseVector(new double[]{2.0, 3.0});
-        SVMLinearBinaryClassificationModel mdl = new SVMLinearBinaryClassificationModel(weights, 1.0).withRawLabels(true);
+        SVMLinearClassificationModel mdl = new SVMLinearClassificationModel(weights, 1.0).withRawLabels(true);
 
         Vector observation = new DenseVector(new double[]{1.0, 1.0});
         TestUtils.assertEquals(1.0 + 2.0 * 1.0 + 3.0 * 1.0, mdl.apply(observation), PRECISION);
@@ -55,36 +55,16 @@
 
         Assert.assertTrue(mdl.isKeepingRawLabels());
 
-        Assert.assertTrue(mdl.toString().length() > 0);
-        Assert.assertTrue(mdl.toString(true).length() > 0);
-        Assert.assertTrue(mdl.toString(false).length() > 0);
-    }
-
-
-    /** */
-    @Test
-    public void testPredictWithMultiClasses() {
-        Vector weights1 = new DenseVector(new double[]{10.0, 0.0});
-        Vector weights2 = new DenseVector(new double[]{0.0, 10.0});
-        Vector weights3 = new DenseVector(new double[]{-1.0, -1.0});
-        SVMLinearMultiClassClassificationModel mdl = new SVMLinearMultiClassClassificationModel();
-        mdl.add(1, new SVMLinearBinaryClassificationModel(weights1, 0.0).withRawLabels(true));
-        mdl.add(2, new SVMLinearBinaryClassificationModel(weights2, 0.0).withRawLabels(true));
-        mdl.add(2, new SVMLinearBinaryClassificationModel(weights3, 0.0).withRawLabels(true));
-
-        Assert.assertTrue(mdl.toString().length() > 0);
-        Assert.assertTrue(mdl.toString(true).length() > 0);
-        Assert.assertTrue(mdl.toString(false).length() > 0);
-
-        Vector observation = new DenseVector(new double[]{1.0, 1.0});
-        TestUtils.assertEquals( 1.0, mdl.apply(observation), PRECISION);
+        Assert.assertTrue(!mdl.toString().isEmpty());
+        Assert.assertTrue(!mdl.toString(true).isEmpty());
+        Assert.assertTrue(!mdl.toString(false).isEmpty());
     }
 
     /** */
     @Test
     public void testPredictWithErasedLabels() {
         Vector weights = new DenseVector(new double[]{1.0, 1.0});
-        SVMLinearBinaryClassificationModel mdl = new SVMLinearBinaryClassificationModel(weights, 1.0);
+        SVMLinearClassificationModel mdl = new SVMLinearClassificationModel(weights, 1.0);
 
         Vector observation = new DenseVector(new double[]{1.0, 1.0});
         TestUtils.assertEquals(1.0, mdl.apply(observation), PRECISION);
@@ -101,7 +81,7 @@
         observation = new DenseVector(new double[]{-1.0, -2.0});
         TestUtils.assertEquals(0.0, mdl.apply(observation), PRECISION);
 
-        final SVMLinearBinaryClassificationModel mdlWithNewData = mdl.withIntercept(-2.0).withWeights(new DenseVector(new double[] {-2.0, -2.0}));
+        final SVMLinearClassificationModel mdlWithNewData = mdl.withIntercept(-2.0).withWeights(new DenseVector(new double[] {-2.0, -2.0}));
         System.out.println("The SVM model is " + mdlWithNewData);
 
         observation = new DenseVector(new double[]{-1.0, -2.0});
@@ -113,7 +93,7 @@
     @Test
     public void testPredictWithErasedLabelsAndChangedThreshold() {
         Vector weights = new DenseVector(new double[]{1.0, 1.0});
-        SVMLinearBinaryClassificationModel mdl = new SVMLinearBinaryClassificationModel(weights, 1.0).withThreshold(5);
+        SVMLinearClassificationModel mdl = new SVMLinearClassificationModel(weights, 1.0).withThreshold(5);
 
         Vector observation = new DenseVector(new double[]{1.0, 1.0});
         TestUtils.assertEquals(0.0, mdl.apply(observation), PRECISION);
@@ -129,7 +109,7 @@
     public void testPredictOnAnObservationWithWrongCardinality() {
         Vector weights = new DenseVector(new double[]{2.0, 3.0});
 
-        SVMLinearBinaryClassificationModel mdl = new SVMLinearBinaryClassificationModel(weights, 1.0);
+        SVMLinearClassificationModel mdl = new SVMLinearClassificationModel(weights, 1.0);
 
         Vector observation = new DenseVector(new double[]{1.0});
 
diff --git a/modules/ml/src/test/java/org/apache/ignite/ml/svm/SVMMultiClassTrainerTest.java b/modules/ml/src/test/java/org/apache/ignite/ml/svm/SVMMultiClassTrainerTest.java
deleted file mode 100644
index 7c4809f..0000000
--- a/modules/ml/src/test/java/org/apache/ignite/ml/svm/SVMMultiClassTrainerTest.java
+++ /dev/null
@@ -1,100 +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.ml.svm;
-
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.Map;
-import org.apache.ignite.ml.TestUtils;
-import org.apache.ignite.ml.common.TrainerTest;
-import org.apache.ignite.ml.math.primitives.vector.Vector;
-import org.apache.ignite.ml.math.primitives.vector.VectorUtils;
-import org.junit.Test;
-
-/**
- * Tests for {@link SVMLinearBinaryClassificationTrainer}.
- */
-public class SVMMultiClassTrainerTest extends TrainerTest {
-    /**
-     * Test trainer on 4 sets grouped around of square vertices.
-     */
-    @Test
-    public void testTrainWithTheLinearlySeparableCase() {
-        Map<Integer, double[]> cacheMock = new HashMap<>();
-
-        for (int i = 0; i < twoLinearlySeparableClasses.length; i++)
-            cacheMock.put(i, twoLinearlySeparableClasses[i]);
-
-        SVMLinearMultiClassClassificationTrainer trainer = new SVMLinearMultiClassClassificationTrainer()
-            .withLambda(0.3)
-            .withAmountOfLocIterations(10)
-            .withAmountOfIterations(20)
-            .withSeed(1234L);
-
-        SVMLinearMultiClassClassificationModel mdl = trainer.fit(
-            cacheMock,
-            parts,
-            (k, v) -> VectorUtils.of(Arrays.copyOfRange(v, 1, v.length)),
-            (k, v) -> v[0]
-        );
-        TestUtils.assertEquals(0, mdl.apply(VectorUtils.of(100, 10)), PRECISION);
-        TestUtils.assertEquals(1, mdl.apply(VectorUtils.of(10, 100)), PRECISION);
-    }
-
-    /** */
-    @Test
-    public void testUpdate() {
-        Map<Integer, double[]> cacheMock = new HashMap<>();
-
-        for (int i = 0; i < twoLinearlySeparableClasses.length; i++)
-            cacheMock.put(i, twoLinearlySeparableClasses[i]);
-
-        SVMLinearMultiClassClassificationTrainer trainer = new SVMLinearMultiClassClassificationTrainer()
-            .withLambda(0.3)
-            .withAmountOfLocIterations(10)
-            .withAmountOfIterations(100)
-            .withSeed(1234L);
-
-        SVMLinearMultiClassClassificationModel originalMdl = trainer.fit(
-            cacheMock,
-            parts,
-            (k, v) -> VectorUtils.of(Arrays.copyOfRange(v, 1, v.length)),
-            (k, v) -> v[0]
-        );
-
-        SVMLinearMultiClassClassificationModel updatedOnSameDS = trainer.update(
-            originalMdl,
-            cacheMock,
-            parts,
-            (k, v) -> VectorUtils.of(Arrays.copyOfRange(v, 1, v.length)),
-            (k, v) -> v[0]
-        );
-
-        SVMLinearMultiClassClassificationModel updatedOnEmptyDS = trainer.update(
-            originalMdl,
-            new HashMap<Integer, double[]>(),
-            parts,
-            (k, v) -> VectorUtils.of(Arrays.copyOfRange(v, 1, v.length)),
-            (k, v) -> v[0]
-        );
-
-        Vector v = VectorUtils.of(100, 10);
-        TestUtils.assertEquals(originalMdl.apply(v), updatedOnSameDS.apply(v), PRECISION);
-        TestUtils.assertEquals(originalMdl.apply(v), updatedOnEmptyDS.apply(v), PRECISION);
-    }
-}
diff --git a/modules/ml/src/test/java/org/apache/ignite/ml/svm/SVMTestSuite.java b/modules/ml/src/test/java/org/apache/ignite/ml/svm/SVMTestSuite.java
index df7263f..a2aea6e 100644
--- a/modules/ml/src/test/java/org/apache/ignite/ml/svm/SVMTestSuite.java
+++ b/modules/ml/src/test/java/org/apache/ignite/ml/svm/SVMTestSuite.java
@@ -27,7 +27,6 @@
 @Suite.SuiteClasses({
     SVMModelTest.class,
     SVMBinaryTrainerTest.class,
-    SVMMultiClassTrainerTest.class,
 })
 public class SVMTestSuite {
     // No-op.
diff --git a/modules/ml/src/test/java/org/apache/ignite/ml/trainers/BaggingTest.java b/modules/ml/src/test/java/org/apache/ignite/ml/trainers/BaggingTest.java
index a82374b..31fe8b3 100644
--- a/modules/ml/src/test/java/org/apache/ignite/ml/trainers/BaggingTest.java
+++ b/modules/ml/src/test/java/org/apache/ignite/ml/trainers/BaggingTest.java
@@ -28,6 +28,8 @@
 import org.apache.ignite.ml.composition.predictionsaggregator.OnMajorityPredictionsAggregator;
 import org.apache.ignite.ml.dataset.Dataset;
 import org.apache.ignite.ml.dataset.DatasetBuilder;
+import org.apache.ignite.ml.environment.LearningEnvironment;
+import org.apache.ignite.ml.environment.LearningEnvironmentBuilder;
 import org.apache.ignite.ml.math.functions.IgniteBiFunction;
 import org.apache.ignite.ml.math.functions.IgniteTriFunction;
 import org.apache.ignite.ml.math.primitives.vector.Vector;
@@ -35,8 +37,8 @@
 import org.apache.ignite.ml.nn.UpdatesStrategy;
 import org.apache.ignite.ml.optimization.updatecalculators.SimpleGDParameterUpdate;
 import org.apache.ignite.ml.optimization.updatecalculators.SimpleGDUpdateCalculator;
-import org.apache.ignite.ml.regressions.logistic.binomial.LogisticRegressionModel;
-import org.apache.ignite.ml.regressions.logistic.binomial.LogisticRegressionSGDTrainer;
+import org.apache.ignite.ml.regressions.logistic.LogisticRegressionModel;
+import org.apache.ignite.ml.regressions.logistic.LogisticRegressionSGDTrainer;
 import org.junit.Test;
 
 /**
@@ -75,11 +77,15 @@
                 .withBatchSize(10)
                 .withSeed(123L);
 
+        trainer.withEnvironmentBuilder(TestUtils.testEnvBuilder());
+
         DatasetTrainer<ModelsComposition, Double> baggedTrainer =
             TrainerTransformers.makeBagged(
                 trainer,
                 10,
                 0.7,
+                2,
+                2,
                 new OnMajorityPredictionsAggregator());
 
         ModelsComposition mdl = baggedTrainer.fit(
@@ -98,14 +104,20 @@
      *
      * @param counter Function specifying which data we should count.
      */
-    protected void count(IgniteTriFunction<Long, CountData, Integer, Long> counter) {
+    protected void count(IgniteTriFunction<Long, CountData, LearningEnvironment, Long> counter) {
         Map<Integer, Double[]> cacheMock = getCacheMock();
 
         CountTrainer countTrainer = new CountTrainer(counter);
 
         double subsampleRatio = 0.3;
 
-        ModelsComposition model = TrainerTransformers.makeBagged(countTrainer, 100, subsampleRatio, new MeanValuePredictionsAggregator())
+        ModelsComposition model = TrainerTransformers.makeBagged(
+            countTrainer,
+            100,
+            subsampleRatio,
+            2,
+            2,
+            new MeanValuePredictionsAggregator())
             .fit(cacheMock, parts, null, null);
 
         Double res = model.apply(null);
@@ -155,14 +167,14 @@
         /**
          * Function specifying which entries to count.
          */
-        private final IgniteTriFunction<Long, CountData, Integer, Long> counter;
+        private final IgniteTriFunction<Long, CountData, LearningEnvironment, Long> counter;
 
         /**
          * Construct instance of this class.
          *
          * @param counter Function specifying which entries to count.
          */
-        public CountTrainer(IgniteTriFunction<Long, CountData, Integer, Long> counter) {
+        public CountTrainer(IgniteTriFunction<Long, CountData, LearningEnvironment, Long> counter) {
             this.counter = counter;
         }
 
@@ -172,8 +184,9 @@
             IgniteBiFunction<K, V, Vector> featureExtractor,
             IgniteBiFunction<K, V, Double> lbExtractor) {
             Dataset<Long, CountData> dataset = datasetBuilder.build(
-                (upstreamData, upstreamDataSize) -> upstreamDataSize,
-                (upstreamData, upstreamDataSize, ctx) -> new CountData(upstreamDataSize)
+                TestUtils.testEnvBuilder(),
+                (env, upstreamData, upstreamDataSize) -> upstreamDataSize,
+                (env, upstreamData, upstreamDataSize, ctx) -> new CountData(upstreamDataSize)
             );
 
             Long cnt = dataset.computeWithCtx(counter, BaggingTest::plusOfNullables);
@@ -193,6 +206,11 @@
             IgniteBiFunction<K, V, Vector> featureExtractor, IgniteBiFunction<K, V, Double> lbExtractor) {
             return fit(datasetBuilder, featureExtractor, lbExtractor);
         }
+
+        /** {@inheritDoc} */
+        @Override public CountTrainer withEnvironmentBuilder(LearningEnvironmentBuilder envBuilder) {
+            return (CountTrainer)super.withEnvironmentBuilder(envBuilder);
+        }
     }
 
     /** Data for count trainer. */
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/ApiParity/CacheConfigurationParityTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/ApiParity/CacheConfigurationParityTest.cs
index 32509c2..8031494 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/ApiParity/CacheConfigurationParityTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/ApiParity/CacheConfigurationParityTest.cs
@@ -60,7 +60,9 @@
             "EvictionPolicyFactory",  // IGNITE-6649,
             "isSqlOnheapCacheEnabled",  // IGNITE-7379,
             "SqlOnheapCacheMaxSize", // IGNITE-7379,
-            "isEventsDisabled"  // IGNITE-7346
+            "isEventsDisabled",  // IGNITE-7346
+            "DiskPageCompression", // IGNITE-10332
+            "DiskPageCompressionLevel" // IGNITE-10332
         };
 
         /// <summary>
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/ApiParity/DataStorageMetricsParityTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/ApiParity/DataStorageMetricsParityTest.cs
index 58c974e..c24df71 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/ApiParity/DataStorageMetricsParityTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/ApiParity/DataStorageMetricsParityTest.cs
@@ -41,7 +41,10 @@
             "TotalAllocatedSize",
             "UsedCheckpointBufferPages",
             "UsedCheckpointBufferSize",
-            "CheckpointBufferSize"
+            "CheckpointBufferSize",
+            // IGNITE-10332
+            "StorageSize",
+            "SparseStorageSize"
         };
 
         /// <summary>
diff --git a/modules/web-console/backend/app/settings.js b/modules/web-console/backend/app/settings.js
index 1c75041..233566b 100644
--- a/modules/web-console/backend/app/settings.js
+++ b/modules/web-console/backend/app/settings.js
@@ -53,6 +53,14 @@
         const dfltHost = packaged ? '0.0.0.0' : '127.0.0.1';
         const dfltPort = packaged ? 80 : 3000;
 
+        // We need this function because nconf() can return String or Boolean.
+        // And in JS we cannot compare String with Boolean.
+        const _isTrue = (confParam) => {
+            const v = nconf.get(confParam);
+
+            return v === 'true' || v === true;
+        };
+
         return {
             agent: {
                 dists: nconf.get('agent:dists') || dfltAgentDists
@@ -62,7 +70,7 @@
                 host: nconf.get('server:host') || dfltHost,
                 port: _normalizePort(nconf.get('server:port') || dfltPort),
                 // eslint-disable-next-line eqeqeq
-                SSLOptions: nconf.get('server:ssl') == 'true' && {
+                SSLOptions: _isTrue('server:ssl') && {
                     enable301Redirects: true,
                     trustXFPHeader: true,
                     key: fs.readFileSync(nconf.get('server:key')),
@@ -70,7 +78,7 @@
                     passphrase: nconf.get('server:keyPassphrase')
                 },
                 // eslint-disable-next-line eqeqeq
-                disableSignup: nconf.get('server:disable:signup') == 'true'
+                disableSignup: _isTrue('server:disable:signup')
             },
             mail,
             mongoUrl: nconf.get('mongodb:url') || 'mongodb://127.0.0.1/console',
diff --git a/modules/web-console/docker/compose/docker-compose.yml b/modules/web-console/docker/compose/docker-compose.yml
index 109bfca..15f2ae4 100644
--- a/modules/web-console/docker/compose/docker-compose.yml
+++ b/modules/web-console/docker/compose/docker-compose.yml
@@ -15,7 +15,7 @@
 # limitations under the License.
 #
 
-version: 1
+version: '3'
 
 services:
   mongodb:
@@ -50,7 +50,6 @@
     image: apacheignite/web-console-frontend
     depends_on:
       - mongodb
-      - testenv
     ports:
       # Proxy HTTP nginx port (HOST_PORT:DOCKER_PORT)
       - 80:80
diff --git a/modules/web-console/frontend/app/components/page-configure/components/modal-import-models/service.js b/modules/web-console/frontend/app/components/page-configure/components/modal-import-models/service.js
index e17721db..c45abaa 100644
--- a/modules/web-console/frontend/app/components/page-configure/components/modal-import-models/service.js
+++ b/modules/web-console/frontend/app/components/page-configure/components/modal-import-models/service.js
@@ -16,15 +16,23 @@
  */
 
 export default class ModalImportModels {
-    static $inject = ['$modal', '$uiRouter', 'AgentManager'];
+    static $inject = ['$modal', '$q', '$uiRouter', 'AgentManager'];
 
-    constructor($modal, $uiRouter, AgentManager) {
+    deferred;
+
+    constructor($modal, $q, $uiRouter, AgentManager) {
         this.$modal = $modal;
+        this.$q = $q;
         this.$uiRouter = $uiRouter;
         this.AgentManager = AgentManager;
     }
 
     _goToDynamicState() {
+        if (this.deferred)
+            return this.deferred.promise;
+
+        this.deferred = this.$q.defer();
+
         if (this._state)
             this.$uiRouter.stateRegistry.deregister(this._state);
 
@@ -36,7 +44,6 @@
             },
             onExit: () => {
                 this.AgentManager.stopWatch();
-
                 this._modal && this._modal.hide();
             }
         });
@@ -45,21 +52,34 @@
     }
 
     _open() {
+        const self = this;
+
         this._modal = this.$modal({
             template: `
                 <modal-import-models
-                    on-hide='$ctrl.$state.go("^")'
+                    on-hide='$ctrl.onHide()'
                     cluster-id='$ctrl.$state.params.clusterID'
                 ></modal-import-models>
             `,
-            controller: ['$state', function($state) {this.$state = $state;}],
+            controller: ['$state', function($state) {
+                this.$state = $state;
+
+                this.onHide = () => {
+                    self.deferred.resolve(true);
+
+                    this.$state.go('^');
+                };
+            }],
             controllerAs: '$ctrl',
+            backdrop: 'static',
             show: false
         });
 
         return this.AgentManager.startAgentWatch('Back', this.$uiRouter.globals.current.name)
             .then(() => this._modal.$promise)
-            .then(() => this._modal.show());
+            .then(() => this._modal.show())
+            .then(() => this.deferred.promise)
+            .finally(() => this.deferred = null);
     }
 
     open() {
diff --git a/modules/web-console/frontend/app/components/ui-grid/controller.js b/modules/web-console/frontend/app/components/ui-grid/controller.js
index f53416b..ec7101b 100644
--- a/modules/web-console/frontend/app/components/ui-grid/controller.js
+++ b/modules/web-console/frontend/app/components/ui-grid/controller.js
@@ -18,6 +18,8 @@
 import debounce from 'lodash/debounce';
 import headerTemplate from 'app/primitives/ui-grid-header/index.tpl.pug';
 
+import ResizeObserver from 'resize-observer-polyfill';
+
 export default class IgniteUiGrid {
     /** @type {import('ui-grid').IGridOptions} */
     grid;
@@ -129,6 +131,9 @@
                 this.$timeout(() => {
                     if (this.selectedRowsId) this.applyIncomingSelectionRowsId(this.selectedRowsId);
                 });
+
+                this.resizeObserver = new ResizeObserver(() => api.core.handleWindowResize());
+                this.resizeObserver.observe(this.$element[0]);
             }
         };
 
@@ -153,6 +158,11 @@
             this.adjustHeight();
     }
 
+    $onDestroy() {
+        if (this.resizeObserver)
+            this.resizeObserver.disconnect();
+    }
+
     applyIncomingSelectionRows = (selected = []) => {
         this.gridApi.selection.clearSelectedRows({ ignore: true });
 
diff --git a/modules/web-console/frontend/app/components/ui-grid/style.scss b/modules/web-console/frontend/app/components/ui-grid/style.scss
index dba5d35..da31f67 100644
--- a/modules/web-console/frontend/app/components/ui-grid/style.scss
+++ b/modules/web-console/frontend/app/components/ui-grid/style.scss
@@ -18,6 +18,7 @@
 .ignite-grid-table,
 ignite-grid-table {
 	@import 'public/stylesheets/variables';
+    display: block;
 
     .ui-grid.ui-grid--ignite.ui-grid--thin {
         // Start section row height.
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 dad625d..ef0d423 100644
--- a/modules/web-console/frontend/app/modules/agent/AgentManager.service.js
+++ b/modules/web-console/frontend/app/modules/agent/AgentManager.service.js
@@ -552,7 +552,7 @@
                 if (err instanceof CancellationError)
                     return;
 
-                return err;
+                throw err;
             });
     }
 
diff --git a/modules/web-console/frontend/app/types/index.ts b/modules/web-console/frontend/app/types/index.ts
index 333c00b..df6a169 100644
--- a/modules/web-console/frontend/app/types/index.ts
+++ b/modules/web-console/frontend/app/types/index.ts
@@ -23,11 +23,12 @@
 
 export interface IIgniteNg1StateDeclaration extends Ng1StateDeclaration {
     /**
-     * Whether to store state as last visited in local storage or not.
-     * true - will be saved
-     * false (default) - won't be saved
+     * Whether to store state as last visited in local storage or not:
+     * `true` - will be saved
+     * `false` (default) - won't be saved
      * @type {boolean}
      */
     unsaved?: boolean,
-    tfMetaTags: ITfMetatagsConfig
+    tfMetaTags: ITfMetatagsConfig,
+    permission?: string
 }
diff --git a/modules/web-console/frontend/app/vendor.js b/modules/web-console/frontend/app/vendor.js
index 6961e96..90808be 100644
--- a/modules/web-console/frontend/app/vendor.js
+++ b/modules/web-console/frontend/app/vendor.js
@@ -28,6 +28,8 @@
 import '@uirouter/angularjs';
 import '@uirouter/angularjs/lib/legacy/stateEvents';
 
+import 'resize-observer-polyfill';
+
 import 'tf-metatags';
 import 'angular-translate';
 import 'angular-smart-table';
diff --git a/modules/web-console/frontend/package.json b/modules/web-console/frontend/package.json
index 9059a5f..e8f4ae2 100644
--- a/modules/web-console/frontend/package.json
+++ b/modules/web-console/frontend/package.json
@@ -68,6 +68,7 @@
     "nvd3": "1.8.6",
     "outdent": "0.5.0",
     "pako": "1.0.6",
+    "resize-observer-polyfill": "1.5.0",
     "roboto-font": "0.1.0",
     "rxjs": "5.5.11",
     "socket.io-client": "1.7.3",
@@ -129,7 +130,7 @@
     "mocha": "3.4.2",
     "mocha-teamcity-reporter": "1.1.1",
     "node-fetch": "1.7.3",
-    "node-sass": "4.9.3",
+    "node-sass": "4.10.0",
     "progress": "2.0.0",
     "progress-bar-webpack-plugin": "1.11.0",
     "pug-html-loader": "1.1.0",
diff --git a/modules/yardstick/src/main/java/org/apache/ignite/yardstick/cache/IgniteGetAllTxBenchmark.java b/modules/yardstick/src/main/java/org/apache/ignite/yardstick/cache/IgniteGetAllTxBenchmark.java
new file mode 100644
index 0000000..d4e71ed
--- /dev/null
+++ b/modules/yardstick/src/main/java/org/apache/ignite/yardstick/cache/IgniteGetAllTxBenchmark.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.yardstick.cache;
+
+import java.util.Map;
+import java.util.Set;
+import org.apache.ignite.IgniteCache;
+import org.apache.ignite.internal.util.typedef.internal.U;
+
+/**
+ * Ignite benchmark that performs getAll operations.
+ */
+public class IgniteGetAllTxBenchmark extends IgniteGetBenchmark {
+    /** {@inheritDoc} */
+    @Override public boolean test(Map<Object, Object> ctx) throws Exception {
+        Set<Integer> keys = U.newHashSet(args.batch());
+
+        while (keys.size() < args.batch()) {
+            int key = nextRandom(args.range());
+
+            keys.add(key);
+        }
+
+        IgniteCache<Integer, Object> cache = cacheForOperation();
+
+        cache.getAll(keys);
+
+        return true;
+    }
+
+    /** {@inheritDoc} */
+    @Override protected IgniteCache<Integer, Object> cache() {
+        return ignite().cache("tx");
+    }
+}
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 abe1877..284f642 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
@@ -192,6 +192,9 @@
     /** */
     private final ZookeeperDiscoveryStatistics stats;
 
+    /** Last listener future. */
+    private IgniteFuture<?> lastCustomEvtLsnrFut;
+
     /**
      * @param spi Discovery SPI.
      * @param igniteInstanceName Instance name.
@@ -2752,6 +2755,8 @@
     private boolean processBulkJoin(ZkDiscoveryEventsData evtsData, ZkDiscoveryNodeJoinEventData evtData)
         throws Exception
     {
+        waitForLastListenerFuture();
+
         boolean evtProcessed = false;
 
         for (int i = 0; i < evtData.joinedNodes.size(); i++) {
@@ -3430,6 +3435,8 @@
 
         if (msg != null && msg.isMutable())
             fut.get();
+        else
+            lastCustomEvtLsnrFut = fut;
     }
 
     /**
@@ -3987,6 +3994,20 @@
     }
 
     /**
+     * Wait for all the listeners from previous discovery message to be completed.
+     */
+    private void waitForLastListenerFuture() {
+        if (lastCustomEvtLsnrFut != null) {
+            try {
+                lastCustomEvtLsnrFut.get();
+            }
+            finally {
+                lastCustomEvtLsnrFut = null;
+            }
+        }
+    }
+
+    /**
      *
      */
     private class ReconnectClosure implements Runnable {
diff --git a/modules/zookeeper/src/test/java/org/apache/ignite/spi/discovery/zk/internal/ZookeeperDiscoverySpiTest.java b/modules/zookeeper/src/test/java/org/apache/ignite/spi/discovery/zk/internal/ZookeeperDiscoverySpiTest.java
index b932531..60f5fd7 100644
--- a/modules/zookeeper/src/test/java/org/apache/ignite/spi/discovery/zk/internal/ZookeeperDiscoverySpiTest.java
+++ b/modules/zookeeper/src/test/java/org/apache/ignite/spi/discovery/zk/internal/ZookeeperDiscoverySpiTest.java
@@ -52,6 +52,8 @@
 import org.apache.curator.framework.CuratorFramework;
 import org.apache.curator.framework.CuratorFrameworkFactory;
 import org.apache.curator.retry.RetryNTimes;
+import org.apache.ignite.failure.FailureHandler;
+import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.spi.discovery.tcp.ipfinder.zk.curator.TestingCluster;
 import org.apache.ignite.spi.discovery.tcp.ipfinder.zk.curator.TestingZooKeeperServer;
 import org.apache.ignite.Ignite;
@@ -445,6 +447,11 @@
         System.clearProperty(ZookeeperDiscoveryImpl.IGNITE_ZOOKEEPER_DISCOVERY_SPI_ACK_TIMEOUT);
     }
 
+    /** {@inheritDoc} */
+    @Override protected FailureHandler getFailureHandler(String igniteInstanceName) {
+        return new NoOpFailureHandler();
+    }
+
     /**
      *
      */