You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by sd...@apache.org on 2023/01/27 12:02:53 UTC

[ignite-3] branch main updated: IGNITE-18570 Use network serialization for Meta Storage API (#1544)

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

sdanilov pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/ignite-3.git


The following commit(s) were added to refs/heads/main by this push:
     new d6019ba109 IGNITE-18570 Use network serialization for Meta Storage API (#1544)
d6019ba109 is described below

commit d6019ba1094fd98dbd0407b4f9cf980c1783be65
Author: Alexander Polovtcev <al...@gmail.com>
AuthorDate: Fri Jan 27 14:02:47 2023 +0200

    IGNITE-18570 Use network serialization for Meta Storage API (#1544)
---
 .../distributionzones/DistributionZoneManager.java |  13 +-
 .../distributionzones/DistributionZonesUtil.java   |   4 +-
 ...ibutionZoneManagerConfigurationChangesTest.java |  11 +-
 ...butionZoneManagerLogicalTopologyEventsTest.java |  11 +-
 .../DistributionZoneManagerScaleUpTest.java        |  11 +-
 .../DistributionZoneManagerWatchListenerTest.java  |  11 +-
 modules/metastorage-api/build.gradle               |   5 +-
 .../internal/metastorage/MetaStorageManager.java   |   4 +-
 .../metastorage/dsl/CompoundCondition.java         |  63 +----
 .../ignite/internal/metastorage/dsl/Condition.java |   6 +-
 .../internal/metastorage/dsl/Conditions.java       | 297 +++++++++++++++++++--
 .../apache/ignite/internal/metastorage/dsl/If.java | 154 -----------
 .../ignite/internal/metastorage/dsl/Iif.java       |  70 +++++
 .../metastorage/dsl/MetaStorageMessageGroup.java   |  60 +++++
 .../ignite/internal/metastorage/dsl/Operation.java |  84 +-----
 .../internal/metastorage/dsl/Operations.java       |  53 +++-
 .../internal/metastorage/dsl/SimpleCondition.java  | 287 ++------------------
 .../ignite/internal/metastorage/dsl/Statement.java |  68 ++---
 .../internal/metastorage/dsl/StatementResult.java  |  82 ++----
 .../internal/metastorage/dsl/Statements.java       |  92 +++++++
 .../ignite/internal/metastorage/dsl/Update.java    |  38 +--
 .../metastorage/impl/ItMetaStorageServiceTest.java |  99 ++-----
 .../metastorage/command/InvokeCommand.java         |  12 +-
 .../command/MetastorageCommandsMessageGroup.java   |  28 --
 .../metastorage/command/MultiInvokeCommand.java    |   4 +-
 .../command/info/CompoundConditionInfo.java        |  59 ----
 .../metastorage/command/info/ConditionInfo.java    |  30 ---
 .../internal/metastorage/command/info/IfInfo.java  |  51 ----
 .../metastorage/command/info/OperationInfo.java    |  60 -----
 .../command/info/SimpleConditionInfo.java          |  65 -----
 .../metastorage/command/info/StatementInfo.java    |  59 ----
 .../command/info/StatementResultInfo.java          |  36 ---
 .../metastorage/command/info/UpdateInfo.java       |  45 ----
 .../metastorage/impl/MetaStorageManagerImpl.java   |   4 +-
 .../metastorage/impl/MetaStorageService.java       |  10 +-
 .../metastorage/impl/MetaStorageServiceImpl.java   | 129 +--------
 .../server/raft/MetaStorageWriteHandler.java       | 187 ++++++-------
 .../server/AbstractKeyValueStorageTest.java        | 118 ++++----
 modules/network-api/build.gradle                   |   3 +-
 .../internal/network/netty/OutboundEncoder.java    |  12 +-
 .../raft/RebalanceRaftGroupEventsListener.java     |   6 +-
 .../ignite/internal/utils/RebalanceUtil.java       |  10 +-
 42 files changed, 864 insertions(+), 1587 deletions(-)

diff --git a/modules/distribution-zones/src/main/java/org/apache/ignite/internal/distributionzones/DistributionZoneManager.java b/modules/distribution-zones/src/main/java/org/apache/ignite/internal/distributionzones/DistributionZoneManager.java
index 0855973f9f..c87065548e 100644
--- a/modules/distribution-zones/src/main/java/org/apache/ignite/internal/distributionzones/DistributionZoneManager.java
+++ b/modules/distribution-zones/src/main/java/org/apache/ignite/internal/distributionzones/DistributionZoneManager.java
@@ -35,6 +35,7 @@ import static org.apache.ignite.internal.distributionzones.DistributionZonesUtil
 import static org.apache.ignite.internal.metastorage.dsl.Conditions.notExists;
 import static org.apache.ignite.internal.metastorage.dsl.Conditions.value;
 import static org.apache.ignite.internal.metastorage.dsl.Operations.ops;
+import static org.apache.ignite.internal.metastorage.dsl.Statements.iif;
 import static org.apache.ignite.internal.util.ByteUtils.bytesToLong;
 import static org.apache.ignite.internal.util.ByteUtils.fromBytes;
 import static org.apache.ignite.internal.util.ByteUtils.toBytes;
@@ -85,7 +86,7 @@ import org.apache.ignite.internal.metastorage.WatchEvent;
 import org.apache.ignite.internal.metastorage.WatchListener;
 import org.apache.ignite.internal.metastorage.dsl.CompoundCondition;
 import org.apache.ignite.internal.metastorage.dsl.Condition;
-import org.apache.ignite.internal.metastorage.dsl.If;
+import org.apache.ignite.internal.metastorage.dsl.Iif;
 import org.apache.ignite.internal.metastorage.dsl.StatementResult;
 import org.apache.ignite.internal.metastorage.dsl.Update;
 import org.apache.ignite.internal.schema.configuration.TableChange;
@@ -598,7 +599,7 @@ public class DistributionZoneManager implements IgniteComponent {
 
             Update dataNodesAndTriggerKeyUpd = updateDataNodesAndTriggerKeys(zoneId, revision, dataNodes);
 
-            If iif = If.iif(triggerKeyCondition, dataNodesAndTriggerKeyUpd, ops().yield(false));
+            Iif iif = iif(triggerKeyCondition, dataNodesAndTriggerKeyUpd, ops().yield(false));
 
             metaStorageManager.invoke(iif).thenAccept(res -> {
                 if (res.getAsBoolean()) {
@@ -628,7 +629,7 @@ public class DistributionZoneManager implements IgniteComponent {
 
             Update removeKeysUpd = deleteDataNodesAndUpdateTriggerKeys(zoneId, revision);
 
-            If iif = If.iif(triggerKeyCondition, removeKeysUpd, ops().yield(false));
+            Iif iif = iif(triggerKeyCondition, removeKeysUpd, ops().yield(false));
 
             metaStorageManager.invoke(iif).thenAccept(res -> {
                 if (res.getAsBoolean()) {
@@ -693,7 +694,7 @@ public class DistributionZoneManager implements IgniteComponent {
                 updateCondition = value(zonesLogicalTopologyVersionKey()).eq(ByteUtils.longToBytes(newTopology.version() - 1));
             }
 
-            If iff = If.iif(
+            Iif iff = iif(
                     updateCondition,
                     updateLogicalTopologyAndVersion(topologyFromCmg, newTopology.version()),
                     ops().yield(false)
@@ -752,7 +753,7 @@ public class DistributionZoneManager implements IgniteComponent {
                                         ? notExists(zonesLogicalTopologyVersionKey()) :
                                         value(zonesLogicalTopologyVersionKey()).eq(topVerFromMetaStorage);
 
-                                If iff = If.iif(topologyVersionCondition,
+                                Iif iff = iif(topologyVersionCondition,
                                         updateLogicalTopologyAndVersion(topologyFromCmg, topologyVersionFromCmg),
                                         ops().yield(false)
                                 );
@@ -1042,7 +1043,7 @@ public class DistributionZoneManager implements IgniteComponent {
 
                 Update dataNodesAndTriggerKeyUpd = updateDataNodesAndScaleUpTriggerKey(zoneId, revision, toBytes(newDataNodes));
 
-                If iif = If.iif(
+                Iif iif = iif(
                         triggerScaleUpScaleDownKeysCondition(scaleUpTriggerRevision, scaleDownTriggerRevision, zoneId),
                         dataNodesAndTriggerKeyUpd,
                         ops().yield(false)
diff --git a/modules/distribution-zones/src/main/java/org/apache/ignite/internal/distributionzones/DistributionZonesUtil.java b/modules/distribution-zones/src/main/java/org/apache/ignite/internal/distributionzones/DistributionZonesUtil.java
index 335eaa005e..ea1d8e6177 100644
--- a/modules/distribution-zones/src/main/java/org/apache/ignite/internal/distributionzones/DistributionZonesUtil.java
+++ b/modules/distribution-zones/src/main/java/org/apache/ignite/internal/distributionzones/DistributionZonesUtil.java
@@ -17,9 +17,9 @@
 
 package org.apache.ignite.internal.distributionzones;
 
-import static org.apache.ignite.internal.metastorage.dsl.CompoundCondition.and;
-import static org.apache.ignite.internal.metastorage.dsl.CompoundCondition.or;
+import static org.apache.ignite.internal.metastorage.dsl.Conditions.and;
 import static org.apache.ignite.internal.metastorage.dsl.Conditions.notExists;
+import static org.apache.ignite.internal.metastorage.dsl.Conditions.or;
 import static org.apache.ignite.internal.metastorage.dsl.Conditions.value;
 import static org.apache.ignite.internal.metastorage.dsl.Operations.ops;
 import static org.apache.ignite.internal.metastorage.dsl.Operations.put;
diff --git a/modules/distribution-zones/src/test/java/org/apache/ignite/internal/distributionzones/DistributionZoneManagerConfigurationChangesTest.java b/modules/distribution-zones/src/test/java/org/apache/ignite/internal/distributionzones/DistributionZoneManagerConfigurationChangesTest.java
index d05c7165a2..0d55d7f9fe 100644
--- a/modules/distribution-zones/src/test/java/org/apache/ignite/internal/distributionzones/DistributionZoneManagerConfigurationChangesTest.java
+++ b/modules/distribution-zones/src/test/java/org/apache/ignite/internal/distributionzones/DistributionZoneManagerConfigurationChangesTest.java
@@ -23,7 +23,6 @@ import static org.apache.ignite.internal.distributionzones.DistributionZonesUtil
 import static org.apache.ignite.internal.distributionzones.DistributionZonesUtil.zoneScaleUpChangeTriggerKey;
 import static org.apache.ignite.internal.distributionzones.DistributionZonesUtil.zonesChangeTriggerKey;
 import static org.apache.ignite.internal.distributionzones.DistributionZonesUtil.zonesLogicalTopologyKey;
-import static org.apache.ignite.internal.metastorage.impl.MetaStorageServiceImpl.toIfInfo;
 import static org.apache.ignite.internal.testframework.IgniteTestUtils.waitForCondition;
 import static org.apache.ignite.internal.util.ByteUtils.longToBytes;
 import static org.apache.ignite.internal.util.ByteUtils.toBytes;
@@ -62,9 +61,7 @@ import org.apache.ignite.internal.metastorage.command.MetaStorageCommandsFactory
 import org.apache.ignite.internal.metastorage.command.MultiInvokeCommand;
 import org.apache.ignite.internal.metastorage.command.MultipleEntryResponse;
 import org.apache.ignite.internal.metastorage.command.SingleEntryResponse;
-import org.apache.ignite.internal.metastorage.command.info.StatementResultInfo;
-import org.apache.ignite.internal.metastorage.dsl.If;
-import org.apache.ignite.internal.metastorage.dsl.StatementResult;
+import org.apache.ignite.internal.metastorage.dsl.Iif;
 import org.apache.ignite.internal.metastorage.impl.EntryImpl;
 import org.apache.ignite.internal.metastorage.server.SimpleInMemoryKeyValueStorage;
 import org.apache.ignite.internal.metastorage.server.raft.MetaStorageListener;
@@ -258,11 +255,11 @@ public class DistributionZoneManagerConfigurationChangesTest extends IgniteAbstr
         MetaStorageCommandsFactory commandsFactory = new MetaStorageCommandsFactory();
 
         lenient().doAnswer(invocationClose -> {
-            If iif = invocationClose.getArgument(0);
+            Iif iif = invocationClose.getArgument(0);
 
-            MultiInvokeCommand multiInvokeCommand = commandsFactory.multiInvokeCommand().iif(toIfInfo(iif, commandsFactory)).build();
+            MultiInvokeCommand multiInvokeCommand = commandsFactory.multiInvokeCommand().iif(iif).build();
 
-            return metaStorageService.run(multiInvokeCommand).thenApply(bi -> new StatementResult(((StatementResultInfo) bi).result()));
+            return metaStorageService.run(multiInvokeCommand);
         }).when(metaStorageManager).invoke(any());
 
         lenient().doAnswer(invocationClose -> {
diff --git a/modules/distribution-zones/src/test/java/org/apache/ignite/internal/distributionzones/DistributionZoneManagerLogicalTopologyEventsTest.java b/modules/distribution-zones/src/test/java/org/apache/ignite/internal/distributionzones/DistributionZoneManagerLogicalTopologyEventsTest.java
index 80f90f754f..984f35e2a0 100644
--- a/modules/distribution-zones/src/test/java/org/apache/ignite/internal/distributionzones/DistributionZoneManagerLogicalTopologyEventsTest.java
+++ b/modules/distribution-zones/src/test/java/org/apache/ignite/internal/distributionzones/DistributionZoneManagerLogicalTopologyEventsTest.java
@@ -22,7 +22,6 @@ import static org.apache.ignite.configuration.annotation.ConfigurationType.DISTR
 import static org.apache.ignite.internal.cluster.management.topology.LogicalTopologyImpl.LOGICAL_TOPOLOGY_KEY;
 import static org.apache.ignite.internal.distributionzones.DistributionZonesUtil.zonesLogicalTopologyKey;
 import static org.apache.ignite.internal.distributionzones.DistributionZonesUtil.zonesLogicalTopologyVersionKey;
-import static org.apache.ignite.internal.metastorage.impl.MetaStorageServiceImpl.toIfInfo;
 import static org.apache.ignite.internal.testframework.IgniteTestUtils.waitForCondition;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -60,9 +59,7 @@ import org.apache.ignite.internal.metastorage.command.GetCommand;
 import org.apache.ignite.internal.metastorage.command.MetaStorageCommandsFactory;
 import org.apache.ignite.internal.metastorage.command.MultiInvokeCommand;
 import org.apache.ignite.internal.metastorage.command.SingleEntryResponse;
-import org.apache.ignite.internal.metastorage.command.info.StatementResultInfo;
-import org.apache.ignite.internal.metastorage.dsl.If;
-import org.apache.ignite.internal.metastorage.dsl.StatementResult;
+import org.apache.ignite.internal.metastorage.dsl.Iif;
 import org.apache.ignite.internal.metastorage.impl.EntryImpl;
 import org.apache.ignite.internal.metastorage.server.SimpleInMemoryKeyValueStorage;
 import org.apache.ignite.internal.metastorage.server.raft.MetaStorageListener;
@@ -248,11 +245,11 @@ public class DistributionZoneManagerLogicalTopologyEventsTest {
         MetaStorageCommandsFactory commandsFactory = new MetaStorageCommandsFactory();
 
         lenient().doAnswer(invocationClose -> {
-            If iif = invocationClose.getArgument(0);
+            Iif iif = invocationClose.getArgument(0);
 
-            MultiInvokeCommand multiInvokeCommand = commandsFactory.multiInvokeCommand().iif(toIfInfo(iif, commandsFactory)).build();
+            MultiInvokeCommand multiInvokeCommand = commandsFactory.multiInvokeCommand().iif(iif).build();
 
-            return metaStorageService.run(multiInvokeCommand).thenApply(bi -> new StatementResult(((StatementResultInfo) bi).result()));
+            return metaStorageService.run(multiInvokeCommand);
         }).when(metaStorageManager).invoke(any());
 
         lenient().doAnswer(invocationClose -> {
diff --git a/modules/distribution-zones/src/test/java/org/apache/ignite/internal/distributionzones/DistributionZoneManagerScaleUpTest.java b/modules/distribution-zones/src/test/java/org/apache/ignite/internal/distributionzones/DistributionZoneManagerScaleUpTest.java
index e5cd7a8f13..d66caacba7 100644
--- a/modules/distribution-zones/src/test/java/org/apache/ignite/internal/distributionzones/DistributionZoneManagerScaleUpTest.java
+++ b/modules/distribution-zones/src/test/java/org/apache/ignite/internal/distributionzones/DistributionZoneManagerScaleUpTest.java
@@ -25,7 +25,6 @@ import static org.apache.ignite.internal.distributionzones.DistributionZonesUtil
 import static org.apache.ignite.internal.distributionzones.DistributionZonesUtil.zoneScaleUpChangeTriggerKey;
 import static org.apache.ignite.internal.distributionzones.DistributionZonesUtil.zonesChangeTriggerKey;
 import static org.apache.ignite.internal.distributionzones.DistributionZonesUtil.zonesLogicalTopologyKey;
-import static org.apache.ignite.internal.metastorage.impl.MetaStorageServiceImpl.toIfInfo;
 import static org.apache.ignite.internal.testframework.IgniteTestUtils.waitForCondition;
 import static org.apache.ignite.internal.util.ByteUtils.toBytes;
 import static org.junit.jupiter.api.Assertions.assertFalse;
@@ -75,9 +74,7 @@ import org.apache.ignite.internal.metastorage.command.MetaStorageCommandsFactory
 import org.apache.ignite.internal.metastorage.command.MultiInvokeCommand;
 import org.apache.ignite.internal.metastorage.command.MultipleEntryResponse;
 import org.apache.ignite.internal.metastorage.command.SingleEntryResponse;
-import org.apache.ignite.internal.metastorage.command.info.StatementResultInfo;
-import org.apache.ignite.internal.metastorage.dsl.If;
-import org.apache.ignite.internal.metastorage.dsl.StatementResult;
+import org.apache.ignite.internal.metastorage.dsl.Iif;
 import org.apache.ignite.internal.metastorage.impl.EntryImpl;
 import org.apache.ignite.internal.metastorage.server.SimpleInMemoryKeyValueStorage;
 import org.apache.ignite.internal.metastorage.server.raft.MetaStorageListener;
@@ -288,11 +285,11 @@ public class DistributionZoneManagerScaleUpTest {
         MetaStorageCommandsFactory commandsFactory = new MetaStorageCommandsFactory();
 
         lenient().doAnswer(invocationClose -> {
-            If iif = invocationClose.getArgument(0);
+            Iif iif = invocationClose.getArgument(0);
 
-            MultiInvokeCommand multiInvokeCommand = commandsFactory.multiInvokeCommand().iif(toIfInfo(iif, commandsFactory)).build();
+            MultiInvokeCommand multiInvokeCommand = commandsFactory.multiInvokeCommand().iif(iif).build();
 
-            return metaStorageService.run(multiInvokeCommand).thenApply(bi -> new StatementResult(((StatementResultInfo) bi).result()));
+            return metaStorageService.run(multiInvokeCommand);
         }).when(metaStorageManager).invoke(any());
 
         lenient().doAnswer(invocationClose -> {
diff --git a/modules/distribution-zones/src/test/java/org/apache/ignite/internal/distributionzones/DistributionZoneManagerWatchListenerTest.java b/modules/distribution-zones/src/test/java/org/apache/ignite/internal/distributionzones/DistributionZoneManagerWatchListenerTest.java
index 80dc99b4a8..e2631a0a57 100644
--- a/modules/distribution-zones/src/test/java/org/apache/ignite/internal/distributionzones/DistributionZoneManagerWatchListenerTest.java
+++ b/modules/distribution-zones/src/test/java/org/apache/ignite/internal/distributionzones/DistributionZoneManagerWatchListenerTest.java
@@ -25,7 +25,6 @@ import static org.apache.ignite.internal.distributionzones.DistributionZonesUtil
 import static org.apache.ignite.internal.distributionzones.DistributionZonesUtil.zoneScaleUpChangeTriggerKey;
 import static org.apache.ignite.internal.distributionzones.DistributionZonesUtil.zonesChangeTriggerKey;
 import static org.apache.ignite.internal.distributionzones.DistributionZonesUtil.zonesLogicalTopologyKey;
-import static org.apache.ignite.internal.metastorage.impl.MetaStorageServiceImpl.toIfInfo;
 import static org.apache.ignite.internal.testframework.IgniteTestUtils.waitForCondition;
 import static org.apache.ignite.internal.util.ByteUtils.fromBytes;
 import static org.apache.ignite.internal.util.ByteUtils.longToBytes;
@@ -77,9 +76,7 @@ import org.apache.ignite.internal.metastorage.command.MetaStorageCommandsFactory
 import org.apache.ignite.internal.metastorage.command.MultiInvokeCommand;
 import org.apache.ignite.internal.metastorage.command.MultipleEntryResponse;
 import org.apache.ignite.internal.metastorage.command.SingleEntryResponse;
-import org.apache.ignite.internal.metastorage.command.info.StatementResultInfo;
-import org.apache.ignite.internal.metastorage.dsl.If;
-import org.apache.ignite.internal.metastorage.dsl.StatementResult;
+import org.apache.ignite.internal.metastorage.dsl.Iif;
 import org.apache.ignite.internal.metastorage.impl.EntryImpl;
 import org.apache.ignite.internal.metastorage.server.SimpleInMemoryKeyValueStorage;
 import org.apache.ignite.internal.metastorage.server.raft.MetaStorageListener;
@@ -282,11 +279,11 @@ public class DistributionZoneManagerWatchListenerTest extends IgniteAbstractTest
         MetaStorageCommandsFactory commandsFactory = new MetaStorageCommandsFactory();
 
         lenient().doAnswer(invocationClose -> {
-            If iif = invocationClose.getArgument(0);
+            Iif iif = invocationClose.getArgument(0);
 
-            MultiInvokeCommand multiInvokeCommand = commandsFactory.multiInvokeCommand().iif(toIfInfo(iif, commandsFactory)).build();
+            MultiInvokeCommand multiInvokeCommand = commandsFactory.multiInvokeCommand().iif(iif).build();
 
-            return metaStorageService.run(multiInvokeCommand).thenApply(bi -> new StatementResult(((StatementResultInfo) bi).result()));
+            return metaStorageService.run(multiInvokeCommand);
         }).when(metaStorageManager).invoke(any());
 
         lenient().doAnswer(invocationClose -> {
diff --git a/modules/metastorage-api/build.gradle b/modules/metastorage-api/build.gradle
index 0c8e21e6eb..c5aefc2800 100644
--- a/modules/metastorage-api/build.gradle
+++ b/modules/metastorage-api/build.gradle
@@ -22,7 +22,10 @@ apply from: "$rootDir/buildscripts/java-junit5.gradle"
 description = 'ignite-metastorage-api'
 
 dependencies {
-    implementation project(':ignite-core')
+    api project(':ignite-network-api')
 
+    implementation project(':ignite-core')
     implementation libs.jetbrains.annotations
+
+    annotationProcessor project(':ignite-network-annotation-processor')
 }
diff --git a/modules/metastorage-api/src/main/java/org/apache/ignite/internal/metastorage/MetaStorageManager.java b/modules/metastorage-api/src/main/java/org/apache/ignite/internal/metastorage/MetaStorageManager.java
index d42203dcf2..4d43361352 100644
--- a/modules/metastorage-api/src/main/java/org/apache/ignite/internal/metastorage/MetaStorageManager.java
+++ b/modules/metastorage-api/src/main/java/org/apache/ignite/internal/metastorage/MetaStorageManager.java
@@ -23,7 +23,7 @@ import java.util.Set;
 import java.util.concurrent.CompletableFuture;
 import org.apache.ignite.internal.manager.IgniteComponent;
 import org.apache.ignite.internal.metastorage.dsl.Condition;
-import org.apache.ignite.internal.metastorage.dsl.If;
+import org.apache.ignite.internal.metastorage.dsl.Iif;
 import org.apache.ignite.internal.metastorage.dsl.Operation;
 import org.apache.ignite.internal.metastorage.dsl.StatementResult;
 import org.apache.ignite.internal.metastorage.exceptions.CompactedException;
@@ -103,7 +103,7 @@ public interface MetaStorageManager extends IgniteComponent {
     /**
      * Invoke, which supports nested conditional statements.
      */
-    CompletableFuture<StatementResult> invoke(If iif);
+    CompletableFuture<StatementResult> invoke(Iif iif);
 
     /**
      * Registers a watch listener by a key prefix.
diff --git a/modules/metastorage-api/src/main/java/org/apache/ignite/internal/metastorage/dsl/CompoundCondition.java b/modules/metastorage-api/src/main/java/org/apache/ignite/internal/metastorage/dsl/CompoundCondition.java
index 0bb9cedcc0..54bc509497 100644
--- a/modules/metastorage-api/src/main/java/org/apache/ignite/internal/metastorage/dsl/CompoundCondition.java
+++ b/modules/metastorage-api/src/main/java/org/apache/ignite/internal/metastorage/dsl/CompoundCondition.java
@@ -17,81 +17,38 @@
 
 package org.apache.ignite.internal.metastorage.dsl;
 
+import org.apache.ignite.network.annotations.Transferable;
+
 /**
  * Compound condition, which consists two other simple/compound conditions.
  */
-public class CompoundCondition implements Condition {
-    /** Left condition. */
-    private final Condition leftCond;
-
-    /** Right condition. */
-    private final Condition rightCond;
-
-    /** Compound condition type. */
-    private final CompoundConditionType compoundCondType;
-
-    /**
-     * Constructs new compound condition.
-     *
-     * @param leftCond Left condition.
-     * @param rightCond Right condition.
-     * @param compoundCondType Compound condition type.
-     */
-    public CompoundCondition(Condition leftCond, Condition rightCond,
-            CompoundConditionType compoundCondType) {
-        this.leftCond = leftCond;
-        this.rightCond = rightCond;
-        this.compoundCondType = compoundCondType;
-    }
-
+@Transferable(MetaStorageMessageGroup.COMPOUND_CONDITION)
+public interface CompoundCondition extends Condition {
     /**
      * Returns left condition.
      *
      * @return left condition.
      */
-    public Condition leftCondition() {
-        return leftCond;
-    }
+    Condition leftCondition();
 
     /**
      * Returns right condition.
      *
      * @return right condition.
      */
-    public Condition rightCondition() {
-        return rightCond;
-    }
+    Condition rightCondition();
 
     /**
      * Returns compound condition type.
      *
      * @return compound condition type.
      */
-    public CompoundConditionType compoundConditionType() {
-        return compoundCondType;
-    }
+    int compoundConditionType();
 
     /**
-     * Shortcut for create logical AND condition,
-     * which consists two another simple/compound conditions as left and right operands.
-     *
-     * @param leftCond leftCond condition.
-     * @param rightCond right condition.
-     * @return new AND compound condition.
-     */
-    public static CompoundCondition and(Condition leftCond, Condition rightCond) {
-        return new CompoundCondition(leftCond, rightCond, CompoundConditionType.AND);
-    }
-
-    /**
-     * Shortcut for create logical OR condition,
-     * which consists two another simple/compound conditions as left and right operands.
-     *
-     * @param leftCond leftCond condition.
-     * @param rightCond right condition.
-     * @return new OR compound condition.
+     * Returns compound condition type.
      */
-    public static CompoundCondition or(Condition leftCond, Condition rightCond) {
-        return new CompoundCondition(leftCond, rightCond, CompoundConditionType.OR);
+    default CompoundConditionType type() {
+        return CompoundConditionType.values()[compoundConditionType()];
     }
 }
diff --git a/modules/metastorage-api/src/main/java/org/apache/ignite/internal/metastorage/dsl/Condition.java b/modules/metastorage-api/src/main/java/org/apache/ignite/internal/metastorage/dsl/Condition.java
index 9b5c4bc23d..76364137cb 100644
--- a/modules/metastorage-api/src/main/java/org/apache/ignite/internal/metastorage/dsl/Condition.java
+++ b/modules/metastorage-api/src/main/java/org/apache/ignite/internal/metastorage/dsl/Condition.java
@@ -17,11 +17,13 @@
 
 package org.apache.ignite.internal.metastorage.dsl;
 
+import org.apache.ignite.network.NetworkMessage;
+
 /**
  * Interface for boolean conditions.
  *
- * @see If
+ * @see Iif
  * @see SimpleCondition
  * @see CompoundCondition
  */
-public interface Condition {}
+public interface Condition extends NetworkMessage {}
diff --git a/modules/metastorage-api/src/main/java/org/apache/ignite/internal/metastorage/dsl/Conditions.java b/modules/metastorage-api/src/main/java/org/apache/ignite/internal/metastorage/dsl/Conditions.java
index 052d54dee4..763a31eb8c 100644
--- a/modules/metastorage-api/src/main/java/org/apache/ignite/internal/metastorage/dsl/Conditions.java
+++ b/modules/metastorage-api/src/main/java/org/apache/ignite/internal/metastorage/dsl/Conditions.java
@@ -17,6 +17,8 @@
 
 package org.apache.ignite.internal.metastorage.dsl;
 
+import org.apache.ignite.internal.metastorage.dsl.SimpleCondition.RevisionCondition;
+import org.apache.ignite.internal.metastorage.dsl.SimpleCondition.ValueCondition;
 import org.apache.ignite.lang.ByteArray;
 
 /**
@@ -26,56 +28,301 @@ import org.apache.ignite.lang.ByteArray;
  * @see SimpleCondition
  */
 public final class Conditions {
+    private static final MetaStorageMessagesFactory MSG_FACTORY = new MetaStorageMessagesFactory();
+
     /**
-     * Creates condition on entry revision.
+     * Builder for {@link RevisionCondition}.
+     */
+    public static final class RevisionConditionBuilder {
+        private final byte[] key;
+
+        RevisionConditionBuilder(byte[] key) {
+            this.key = key;
+        }
+
+        /**
+         * Produces the condition of type {@link ConditionType#REV_EQUAL}. This condition tests the given revision on equality
+         * with the target entry revision.
+         *
+         * @param rev The revision.
+         * @return The condition of type {@link ConditionType#REV_EQUAL}.
+         */
+        public SimpleCondition eq(long rev) {
+            return MSG_FACTORY.revisionCondition()
+                    .key(key)
+                    .conditionType(ConditionType.REV_EQUAL.ordinal())
+                    .revision(rev)
+                    .build();
+        }
+
+        /**
+         * Produces the condition of type {@link ConditionType#REV_NOT_EQUAL}. This condition tests the given revision on inequality with
+         * the target entry revision.
+         *
+         * @param rev The revision.
+         * @return The condition of type {@link ConditionType#REV_NOT_EQUAL}.
+         */
+        public SimpleCondition ne(long rev) {
+            return MSG_FACTORY.revisionCondition()
+                    .key(key)
+                    .conditionType(ConditionType.REV_NOT_EQUAL.ordinal())
+                    .revision(rev)
+                    .build();
+        }
+
+        /**
+         * Produces the condition of type {@link ConditionType#REV_GREATER}. This condition tests that the target entry revision is greater
+         * than the given revision.
+         *
+         * @param rev The revision.
+         * @return The condition of type {@link ConditionType#REV_GREATER}.
+         */
+        public SimpleCondition gt(long rev) {
+            return MSG_FACTORY.revisionCondition()
+                    .key(key)
+                    .conditionType(ConditionType.REV_GREATER.ordinal())
+                    .revision(rev)
+                    .build();
+        }
+
+        /**
+         * Produces the condition of type {@link ConditionType#REV_GREATER_OR_EQUAL}. This condition tests that the target entry revision is
+         * greater than or equals to the given revision.
+         *
+         * @param rev The revision.
+         * @return The condition of type {@link ConditionType#REV_GREATER_OR_EQUAL}.
+         */
+        public SimpleCondition ge(long rev) {
+            return MSG_FACTORY.revisionCondition()
+                    .key(key)
+                    .conditionType(ConditionType.REV_GREATER_OR_EQUAL.ordinal())
+                    .revision(rev)
+                    .build();
+        }
+
+        /**
+         * Produces the condition of type {@link ConditionType#REV_LESS}. This condition tests that the target entry revision is less
+         * than the given revision.
+         *
+         * @param rev The revision.
+         * @return The condition of type {@link ConditionType#REV_LESS}.
+         */
+        public SimpleCondition lt(long rev) {
+            return MSG_FACTORY.revisionCondition()
+                    .key(key)
+                    .conditionType(ConditionType.REV_LESS.ordinal())
+                    .revision(rev)
+                    .build();
+        }
+
+        /**
+         * Produces the condition of type {@link ConditionType#REV_LESS_OR_EQUAL}. This condition tests that the target entry revision
+         * is less than or equals to the given revision.
+         *
+         * @param rev The revision.
+         * @return The condition of type {@link ConditionType#REV_LESS_OR_EQUAL}.
+         */
+        public SimpleCondition le(long rev) {
+            return MSG_FACTORY.revisionCondition()
+                    .key(key)
+                    .conditionType(ConditionType.REV_LESS_OR_EQUAL.ordinal())
+                    .revision(rev)
+                    .build();
+        }
+    }
+
+    /**
+     * Builder for {@link ValueCondition}.
+     */
+    public static final class ValueConditionBuilder {
+        private final byte[] key;
+
+        ValueConditionBuilder(byte[] key) {
+            this.key = key;
+        }
+
+        /**
+         * Produces the condition of type {@link ConditionType#VAL_EQUAL}. This condition tests the given value on equality with the target
+         * entry value.
+         *
+         * @param val The value.
+         * @return The condition of type {@link ConditionType#VAL_EQUAL}.
+         */
+        public SimpleCondition eq(byte[] val) {
+            return MSG_FACTORY.valueCondition()
+                    .key(key)
+                    .conditionType(ConditionType.VAL_EQUAL.ordinal())
+                    .value(val)
+                    .build();
+        }
+
+        /**
+         * Produces the condition of type {@link ConditionType#VAL_NOT_EQUAL}. This condition tests the given value on inequality with
+         * the target entry value.
+         *
+         * @param val The value.
+         * @return The condition of type {@link ConditionType#VAL_NOT_EQUAL}.
+         */
+        public SimpleCondition ne(byte[] val) {
+            return MSG_FACTORY.valueCondition()
+                    .key(key)
+                    .conditionType(ConditionType.VAL_NOT_EQUAL.ordinal())
+                    .value(val)
+                    .build();
+        }
+
+        /**
+         * Produces the condition of type {@link ConditionType#VAL_GREATER}. This condition tests that the target entry value is greater
+         * than the given value in the lexicographical order.
+         *
+         * @param val The value.
+         * @return The condition of type {@link ConditionType#VAL_GREATER}.
+         */
+        public SimpleCondition gt(byte[] val) {
+            return MSG_FACTORY.valueCondition()
+                    .key(key)
+                    .conditionType(ConditionType.VAL_GREATER.ordinal())
+                    .value(val)
+                    .build();
+        }
+
+        /**
+         * Produces the condition of type {@link ConditionType#VAL_GREATER_OR_EQUAL}. This condition tests that the target entry value is
+         * greater than or equals to the given value in the lexicographical order.
+         *
+         * @param val The value.
+         * @return The condition of type {@link ConditionType#VAL_GREATER_OR_EQUAL}.
+         */
+        public SimpleCondition ge(byte[] val) {
+            return MSG_FACTORY.valueCondition()
+                    .key(key)
+                    .conditionType(ConditionType.VAL_GREATER_OR_EQUAL.ordinal())
+                    .value(val)
+                    .build();
+        }
+
+        /**
+         * Produces the condition of type {@link ConditionType#VAL_LESS}. This condition tests that the target entry value is less than the
+         * given value in the lexicographical order.
+         *
+         * @param val The value.
+         * @return The condition of type {@link ConditionType#VAL_LESS}.
+         */
+        public SimpleCondition lt(byte[] val) {
+            return MSG_FACTORY.valueCondition()
+                    .key(key)
+                    .conditionType(ConditionType.VAL_LESS.ordinal())
+                    .value(val)
+                    .build();
+        }
+
+        /**
+         * Produces the condition of type {@link ConditionType#VAL_LESS_OR_EQUAL}. This condition tests that the target entry value is less
+         * than or equals to the given value in the lexicographical order.
+         *
+         * @param val The value.
+         * @return The condition of type {@link ConditionType#VAL_LESS_OR_EQUAL}.
+         */
+        public SimpleCondition le(byte[] val) {
+            return MSG_FACTORY.valueCondition()
+                    .key(key)
+                    .conditionType(ConditionType.VAL_LESS_OR_EQUAL.ordinal())
+                    .value(val)
+                    .build();
+        }
+    }
+
+    /**
+     * Creates a builder for a value condition.
      *
-     * @param key Identifies an entry which condition will be applied to. Can't be {@code null}.
-     * @return Condition on entry revision.
-     * @see SimpleCondition.RevisionCondition
+     * @param key Key, which identifies an entry, which condition will be applied to.
+     * @return Builder for a value condition.
+     * @see ValueCondition
      */
-    public static SimpleCondition.RevisionConditionBuilder revision(ByteArray key) {
-        return SimpleCondition.revision(key.bytes());
+    public static ValueConditionBuilder value(ByteArray key) {
+        return new ValueConditionBuilder(key.bytes());
     }
 
     /**
-     * Creates condition on entry value.
+     * Produces the condition of type {@link ConditionType#TOMBSTONE}. This condition tests that an entry's value, identified by the
+     * given key, is tombstone.
      *
-     * @param key Identifies an entry, which condition will be applied to. Can't be {@code null}.
-     * @return Condition on entry value.
-     * @see SimpleCondition.ValueCondition
+     * @return The condition of type {@link ConditionType#TOMBSTONE}.
      */
-    public static SimpleCondition.ValueConditionBuilder value(ByteArray key) {
-        return SimpleCondition.value(key.bytes());
+    public static SimpleCondition tombstone(ByteArray key) {
+        return MSG_FACTORY.simpleCondition()
+                .key(key.bytes())
+                .conditionType(ConditionType.TOMBSTONE.ordinal())
+                .build();
     }
 
     /**
-     * Creates condition on an entry existence.
+     * Produces the condition of type {@link ConditionType#KEY_EXISTS}. This condition tests the existence of an entry identified by the
+     * given key.
      *
-     * @param key Identifies an entry, which condition will be applied to. Can't be {@code null}.
-     * @return Condition on entry existence.
+     * @return The condition of type {@link ConditionType#KEY_EXISTS}.
      */
     public static SimpleCondition exists(ByteArray key) {
-        return SimpleCondition.exists(key.bytes());
+        return MSG_FACTORY.simpleCondition()
+                .key(key.bytes())
+                .conditionType(ConditionType.KEY_EXISTS.ordinal())
+                .build();
     }
 
     /**
-     * Creates a condition on an entry not existence.
+     * Produces the condition of type {@link ConditionType#KEY_NOT_EXISTS}. This condition tests the non-existence of an entry
+     * identified by the given key.
      *
-     * @param key Identifies an entry, which condition will be applied to. Can't be {@code null}.
-     * @return Condition on entry not existence.
+     * @return The condition of type {@link ConditionType#KEY_NOT_EXISTS}.
      */
     public static SimpleCondition notExists(ByteArray key) {
-        return SimpleCondition.notExists(key.bytes());
+        return MSG_FACTORY.simpleCondition()
+                .key(key.bytes())
+                .conditionType(ConditionType.KEY_NOT_EXISTS.ordinal())
+                .build();
     }
 
     /**
-     * Creates a condition on an entry's value, which checks whether a value is tombstone or not.
+     * Creates condition on entry revision.
      *
-     * @param key Identifies an entry, which condition will be applied to. Can't be {@code null}.
-     * @return Condition on entry's value is tombstone.
+     * @param key Identifies an entry which condition will be applied to. Can't be {@code null}.
+     * @return Condition on entry revision.
+     * @see SimpleCondition.RevisionCondition
      */
-    public static SimpleCondition tombstone(ByteArray key) {
-        return SimpleCondition.tombstone(key.bytes());
+    public static RevisionConditionBuilder revision(ByteArray key) {
+        return new RevisionConditionBuilder(key.bytes());
+    }
+
+    /**
+     * Shortcut for create logical AND condition,
+     * which consists two another simple/compound conditions as left and right operands.
+     *
+     * @param leftCond leftCond condition.
+     * @param rightCond right condition.
+     * @return new AND compound condition.
+     */
+    public static CompoundCondition and(Condition leftCond, Condition rightCond) {
+        return MSG_FACTORY.compoundCondition()
+                .leftCondition(leftCond)
+                .rightCondition(rightCond)
+                .compoundConditionType(CompoundConditionType.AND.ordinal())
+                .build();
+    }
+
+    /**
+     * Shortcut for create logical OR condition,
+     * which consists two another simple/compound conditions as left and right operands.
+     *
+     * @param leftCond leftCond condition.
+     * @param rightCond right condition.
+     * @return new OR compound condition.
+     */
+    public static CompoundCondition or(Condition leftCond, Condition rightCond) {
+        return MSG_FACTORY.compoundCondition()
+                .leftCondition(leftCond)
+                .rightCondition(rightCond)
+                .compoundConditionType(CompoundConditionType.OR.ordinal())
+                .build();
     }
 
     /**
diff --git a/modules/metastorage-api/src/main/java/org/apache/ignite/internal/metastorage/dsl/If.java b/modules/metastorage-api/src/main/java/org/apache/ignite/internal/metastorage/dsl/If.java
deleted file mode 100644
index 2231ab743a..0000000000
--- a/modules/metastorage-api/src/main/java/org/apache/ignite/internal/metastorage/dsl/If.java
+++ /dev/null
@@ -1,154 +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.metastorage.dsl;
-
-/**
- * Root building block for the compound meta storage invoke command.
- * Contains of boolean condition and 2 branches of execution, like usual programming language's if.
- * Every branch can be either new {@link If} statement (non-terminal) or result terminal statement {@link Update}.
- *
- * <p>The easiest way to construct the needed {@link If} conditional statement is the builtin shortcut methods.
- * For example to create the statement, which implement the following pseudocode:
- * <pre>
- * {@code
- *                {@link CompoundCondition}
- *                           |
- *  {@link SimpleCondition} |  {@link SimpleCondition}
- *                |        |            |
- * if (key1.value == val1 || key2.value != val2):
- *     if (key3.revision == 3):-------------------|
- *         put(key1, rval1)                       |
- *         return 1                               |
- *     else:                                      | {@link If}
- *         put(key1, rval1)    -|                 |
- *         remove(key2, rval2) -| {@link Update}  |
- *         return 2            -|-----------------|
- * else:
- *   put(key2, rval2)
- *   return 3
- * }
- * </pre>
- * you can use the following code with static shortcut methods from the according classes:
- * <pre>
- * {@code
- * iif(or(value(key1).eq(val1), value(key2).ne(val2)),
- *     iif(revision(key3).eq(3),
- *         ops(put(key1, rval1)).yield(1),
- *         ops(put(key1, rval1), remove(key2)).yield(2)),
- *     ops(put(key2, rval2)).yield(3))
- * }
- * </pre>
- */
-public class If {
-    /** Boolean condition. */
-    private final Condition condition;
-
-    /** Execution branch, if condition evaluates to true (aka left branch). */
-    private final Statement andThen;
-
-    /** Execution branch, if condition evaluates to false (aka right branch). */
-    private final Statement orElse;
-
-    /**
-     * Construct new If statement.
-     *
-     * @param condition Boolean condition.
-     * @param andThen Left execution branch.
-     * @param orElse Right execution branch.
-     */
-    public If(Condition condition, Statement andThen, Statement orElse) {
-        this.condition = condition;
-        this.andThen = andThen;
-        this.orElse = orElse;
-    }
-
-    /**
-     * Returns boolean condition.
-     *
-     * @return Boolean condition.
-     */
-    public Condition condition() {
-        return condition;
-    }
-
-    /**
-     * Execution branch, if condition evaluates to true (aka left branch).
-     *
-     * @return Left execution branch.
-     */
-    public Statement andThen() {
-        return andThen;
-    }
-
-    /**
-     * Execution branch, if condition evaluates to false (aka right branch).
-     *
-     * @return Right execution branch.
-     */
-    public Statement orElse() {
-        return orElse;
-    }
-
-    /**
-     * Simple helper for create the new {@link If} statement.
-     *
-     * @param condition Boolean condition.
-     * @param andThen Execution branch, if condition evaluates to true.
-     * @param orElse Execution branch, if condition evaluates to false.
-     * @return new {@link If} statement.
-     */
-    public static If iif(Condition condition, If andThen, If orElse) {
-        return new If(condition, new Statement(andThen), new Statement(orElse));
-    }
-
-    /**
-     * Simple helper for create the new {@link If} statement.
-     *
-     * @param condition Boolean condition.
-     * @param andThen Execution branch, if condition evaluates to true.
-     * @param orElse Execution branch, if condition evaluates to false.
-     * @return new {@link If} statement.
-     */
-    public static If iif(Condition condition, If andThen, Update orElse) {
-        return new If(condition, new Statement(andThen), new Statement(orElse));
-    }
-
-    /**
-     * Simple helper for create the new {@link If} statement.
-     *
-     * @param condition Boolean condition.
-     * @param andThen Execution branch, if condition evaluates to true.
-     * @param orElse Execution branch, if condition evaluates to false.
-     * @return new {@link If} statement.
-     */
-    public static If iif(Condition condition, Update andThen, If orElse) {
-        return new If(condition, new Statement(andThen), new Statement(orElse));
-    }
-
-    /**
-     * Simple helper for create the new {@link If} statement.
-     *
-     * @param condition Boolean condition.
-     * @param andThen Execution branch, if condition evaluates to true.
-     * @param orElse Execution branch, if condition evaluates to false.
-     * @return new {@link If} statement.
-     */
-    public static If iif(Condition condition, Update andThen, Update orElse) {
-        return new If(condition, new Statement(andThen), new Statement(orElse));
-    }
-}
diff --git a/modules/metastorage-api/src/main/java/org/apache/ignite/internal/metastorage/dsl/Iif.java b/modules/metastorage-api/src/main/java/org/apache/ignite/internal/metastorage/dsl/Iif.java
new file mode 100644
index 0000000000..32a836a03e
--- /dev/null
+++ b/modules/metastorage-api/src/main/java/org/apache/ignite/internal/metastorage/dsl/Iif.java
@@ -0,0 +1,70 @@
+/*
+ * 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.metastorage.dsl;
+
+import org.apache.ignite.network.NetworkMessage;
+import org.apache.ignite.network.annotations.Transferable;
+
+/**
+ * Root building block for the compound meta storage invoke command.
+ * Contains of boolean condition and 2 branches of execution, like usual programming language's if.
+ * Every branch can be either new {@link Iif} statement (non-terminal) or result terminal statement {@link Update}.
+ *
+ * <p>The easiest way to construct the needed {@link Iif} conditional statement is the builtin shortcut methods.
+ * For example to create the statement, which implement the following pseudocode:
+ * <pre>
+ * {@code
+ *                {@link CompoundCondition}
+ *                           |
+ *  {@link SimpleCondition} |  {@link SimpleCondition}
+ *                |        |            |
+ * if (key1.value == val1 || key2.value != val2):
+ *     if (key3.revision == 3):-------------------|
+ *         put(key1, rval1)                       |
+ *         return 1                               |
+ *     else:                                      | {@link If}
+ *         put(key1, rval1)    -|                 |
+ *         remove(key2, rval2) -| {@link Update}  |
+ *         return 2            -|-----------------|
+ * else:
+ *   put(key2, rval2)
+ *   return 3
+ * }
+ * </pre>
+ * you can use the following code with static shortcut methods from the according classes:
+ * <pre>
+ * {@code
+ * iif(or(value(key1).eq(val1), value(key2).ne(val2)),
+ *     iif(revision(key3).eq(3),
+ *         ops(put(key1, rval1)).yield(1),
+ *         ops(put(key1, rval1), remove(key2)).yield(2)),
+ *     ops(put(key2, rval2)).yield(3))
+ * }
+ * </pre>
+ */
+@Transferable(MetaStorageMessageGroup.IF)
+public interface Iif extends NetworkMessage {
+    /** Boolean condition. */
+    Condition condition();
+
+    /** Execution branch, if condition evaluates to true (aka left branch). */
+    Statement andThen();
+
+    /** Execution branch, if condition evaluates to false (aka right branch). */
+    Statement orElse();
+}
diff --git a/modules/metastorage-api/src/main/java/org/apache/ignite/internal/metastorage/dsl/MetaStorageMessageGroup.java b/modules/metastorage-api/src/main/java/org/apache/ignite/internal/metastorage/dsl/MetaStorageMessageGroup.java
new file mode 100644
index 0000000000..154a63716e
--- /dev/null
+++ b/modules/metastorage-api/src/main/java/org/apache/ignite/internal/metastorage/dsl/MetaStorageMessageGroup.java
@@ -0,0 +1,60 @@
+/*
+ * 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.metastorage.dsl;
+
+import org.apache.ignite.internal.metastorage.dsl.SimpleCondition.RevisionCondition;
+import org.apache.ignite.internal.metastorage.dsl.SimpleCondition.ValueCondition;
+import org.apache.ignite.internal.metastorage.dsl.Statement.IfStatement;
+import org.apache.ignite.internal.metastorage.dsl.Statement.UpdateStatement;
+import org.apache.ignite.network.annotations.MessageGroup;
+
+/**
+ * Message group for Meta Storage messages.
+ */
+@MessageGroup(groupType = 222, groupName = "MetaStorageMessages")
+public interface MetaStorageMessageGroup {
+    /** Message type for {@link SimpleCondition}. */
+    short SIMPLE_CONDITION = 1;
+
+    /** Message type for {@link RevisionCondition}. */
+    short REVISION_CONDITION = 2;
+
+    /** Message type for {@link ValueCondition}. */
+    short VALUE_CONDITION = 3;
+
+    /** Message type for {@link CompoundCondition}. */
+    short COMPOUND_CONDITION = 4;
+
+    /** Message type for {@link Operation}. */
+    short OPERATION = 5;
+
+    /** Message type for {@link StatementResult}. */
+    short STATEMENT_RESULT = 6;
+
+    /** Message type for {@link Update}. */
+    short UPDATE = 7;
+
+    /** Message type for {@link Iif}. */
+    short IF = 8;
+
+    /** Message type for {@link IfStatement}. */
+    short IF_STATEMENT = 9;
+
+    /** Message type for {@link UpdateStatement}. */
+    short UPDATE_STATEMENT = 10;
+}
diff --git a/modules/metastorage-api/src/main/java/org/apache/ignite/internal/metastorage/dsl/Operation.java b/modules/metastorage-api/src/main/java/org/apache/ignite/internal/metastorage/dsl/Operation.java
index 06c54cd682..f4095ebba5 100644
--- a/modules/metastorage-api/src/main/java/org/apache/ignite/internal/metastorage/dsl/Operation.java
+++ b/modules/metastorage-api/src/main/java/org/apache/ignite/internal/metastorage/dsl/Operation.java
@@ -17,96 +17,34 @@
 
 package org.apache.ignite.internal.metastorage.dsl;
 
-import org.apache.ignite.internal.util.IgniteUtils;
+import org.apache.ignite.network.NetworkMessage;
+import org.apache.ignite.network.annotations.Transferable;
 import org.jetbrains.annotations.Nullable;
 
 /**
  * Defines operation for meta storage conditional update (invoke).
  */
-public final class Operation {
+@Transferable(MetaStorageMessageGroup.OPERATION)
+public interface Operation extends NetworkMessage {
     /**
      * Key identifies an entry which operation will be applied to. Key is {@code null} for {@link OperationType#NO_OP} operation.
      */
-    private final byte @Nullable [] key;
+    byte @Nullable [] key();
 
     /**
      * Value which will be associated with the {@link #key}. Value is not {@code null} only for {@link OperationType#PUT} operation.
      */
-    private final byte @Nullable [] val;
+    byte @Nullable [] value();
 
     /**
-     * Operation type.
+     * Operation type (integer representation).
      *
      * @see OperationType
      */
-    private final OperationType type;
+    int operationType();
 
-    /**
-     * Constructs operation which will be applied to an entry identified by the given key.
-     *
-     * @param type Operation type. Can't be {@code null}.
-     * @param key  Key identifies an entry which operation will be applied to.
-     * @param val  Value will be associated with an entry identified by the {@code key}.
-     */
-    public Operation(OperationType type, byte @Nullable [] key, byte @Nullable [] val) {
-        assert (type == OperationType.NO_OP && key == null && val == null)
-                || (type == OperationType.PUT && key != null && val != null)
-                || (type == OperationType.REMOVE && key != null && val == null)
-                : "Invalid operation parameters: [type=" + type
-                + ", key=" + (key == null ? "null" : IgniteUtils.toHexString(key, 256))
-                + ", val=" + (val == null ? "null" : IgniteUtils.toHexString(val, 256)) + ']';
-
-        this.key = key;
-        this.val = val;
-        this.type = type;
-    }
-
-    /**
-     * Returns a key which identifies an entry which operation will be applied to.
-     *
-     * @return A key which identifies an entry which operation will be applied to.
-     */
-    public byte @Nullable [] key() {
-        return key;
-    }
-
-    /**
-     * Returns a value which will be associated with an entry identified by the {@code key}.
-     *
-     * @return A value which will be associated with an entry identified by the {@code key}.
-     */
-
-    public byte @Nullable [] value() {
-        return val;
-    }
-
-    /**
-     * Returns an operation type.
-     *
-     * @return An operation type.
-     */
-    public OperationType type() {
-        return type;
-    }
-
-    /**
-     * Creates an operation of type <i>remove</i>.
-     */
-    public static Operation remove(byte[] key) {
-        return new Operation(OperationType.REMOVE, key, null);
-    }
-
-    /**
-     * Creates an operation of type <i>put</i>.
-     */
-    public static Operation put(byte[] key, byte[] val) {
-        return new Operation(OperationType.PUT, key, val);
-    }
-
-    /**
-     * Creates an operation of type <i>no-op</i>.
-     */
-    public static Operation noOp() {
-        return new Operation(OperationType.NO_OP, null, null);
+    /** Operation type. */
+    default OperationType type() {
+        return OperationType.values()[operationType()];
     }
 }
diff --git a/modules/metastorage-api/src/main/java/org/apache/ignite/internal/metastorage/dsl/Operations.java b/modules/metastorage-api/src/main/java/org/apache/ignite/internal/metastorage/dsl/Operations.java
index e4f6d26b5a..b077d93ab2 100644
--- a/modules/metastorage-api/src/main/java/org/apache/ignite/internal/metastorage/dsl/Operations.java
+++ b/modules/metastorage-api/src/main/java/org/apache/ignite/internal/metastorage/dsl/Operations.java
@@ -17,7 +17,10 @@
 
 package org.apache.ignite.internal.metastorage.dsl;
 
-import java.util.Arrays;
+import static org.apache.ignite.internal.util.ArrayUtils.BYTE_EMPTY_ARRAY;
+
+import java.nio.ByteBuffer;
+import java.util.List;
 import org.apache.ignite.lang.ByteArray;
 
 /**
@@ -29,11 +32,13 @@ import org.apache.ignite.lang.ByteArray;
  * @see Update
  */
 public final class Operations {
+    private static final MetaStorageMessagesFactory MSG_FACTORY = new MetaStorageMessagesFactory();
+
     /** No-op operation singleton. */
-    private static final Operation NO_OP = Operation.noOp();
+    private static final Operation NO_OP = MSG_FACTORY.operation().operationType(OperationType.NO_OP.ordinal()).build();
 
     /** Operations. */
-    private final Operation[] operations;
+    private final List<Operation> operations;
 
     /**
      * Constructs new operations batch.
@@ -41,7 +46,7 @@ public final class Operations {
      * @param operations operations.
      */
     private Operations(Operation... operations) {
-        this.operations = operations;
+        this.operations = List.of(operations);
     }
 
     /**
@@ -51,7 +56,14 @@ public final class Operations {
      * @return update statement.
      */
     public Update yield(boolean result) {
-        return new Update(Arrays.asList(operations), new StatementResult(result));
+        StatementResult statementResult = MSG_FACTORY.statementResult()
+                .result(new byte[] {(byte) (result ? 1 : 0)})
+                .build();
+
+        return MSG_FACTORY.update()
+                .operations(operations)
+                .result(statementResult)
+                .build();
     }
 
     /**
@@ -61,7 +73,14 @@ public final class Operations {
      * @return update statement.
      */
     public Update yield(int result) {
-        return new Update(Arrays.asList(operations), new StatementResult(result));
+        StatementResult statementResult = MSG_FACTORY.statementResult()
+                .result(ByteBuffer.allocate(Integer.BYTES).putInt(result).array())
+                .build();
+
+        return MSG_FACTORY.update()
+                .operations(operations)
+                .result(statementResult)
+                .build();
     }
 
     /**
@@ -70,11 +89,18 @@ public final class Operations {
      * @return update statement.
      */
     public Update yield() {
-        return new Update(Arrays.asList(operations), new StatementResult(new byte[]{}));
+        StatementResult statementResult = MSG_FACTORY.statementResult()
+                .result(BYTE_EMPTY_ARRAY)
+                .build();
+
+        return MSG_FACTORY.update()
+                .operations(operations)
+                .result(statementResult)
+                .build();
     }
 
     /**
-     * Shortcut to create new batch of operations, for dsl-like API, see {@link If}.
+     * Shortcut to create new batch of operations, for dsl-like API, see {@link Iif}.
      *
      * @param operations operations.
      * @return batch of operations.
@@ -90,7 +116,10 @@ public final class Operations {
      * @return Operation of type <i>remove</i>.
      */
     public static Operation remove(ByteArray key) {
-        return Operation.remove(key.bytes());
+        return MSG_FACTORY.operation()
+                .key(key.bytes())
+                .operationType(OperationType.REMOVE.ordinal())
+                .build();
     }
 
     /**
@@ -101,7 +130,11 @@ public final class Operations {
      * @return Operation of type <i>put</i>.
      */
     public static Operation put(ByteArray key, byte[] value) {
-        return Operation.put(key.bytes(), value);
+        return MSG_FACTORY.operation()
+                .key(key.bytes())
+                .value(value)
+                .operationType(OperationType.PUT.ordinal())
+                .build();
     }
 
     /**
diff --git a/modules/metastorage-api/src/main/java/org/apache/ignite/internal/metastorage/dsl/SimpleCondition.java b/modules/metastorage-api/src/main/java/org/apache/ignite/internal/metastorage/dsl/SimpleCondition.java
index a5296a9fe6..26a29e6196 100644
--- a/modules/metastorage-api/src/main/java/org/apache/ignite/internal/metastorage/dsl/SimpleCondition.java
+++ b/modules/metastorage-api/src/main/java/org/apache/ignite/internal/metastorage/dsl/SimpleCondition.java
@@ -17,298 +17,43 @@
 
 package org.apache.ignite.internal.metastorage.dsl;
 
+import org.apache.ignite.network.annotations.Transferable;
+
 /**
  * Represents a condition for a meta storage conditional update.
  */
-public class SimpleCondition implements Condition {
+@Transferable(MetaStorageMessageGroup.SIMPLE_CONDITION)
+public interface SimpleCondition extends Condition {
     /** Entry key. */
-    private final byte[] key;
-
-    /**
-     * Condition type.
-     */
-    private final ConditionType type;
+    byte[] key();
 
-    private SimpleCondition(byte[] key, ConditionType type) {
-        this.key = key;
-        this.type = type;
-    }
-
-    /**
-     * Returns the key, which identifies an entry, which condition will be applied to.
-     *
-     * @return Key, which identifies an entry, which condition will be applied to.
-     */
-    public byte[] key() {
-        return key;
-    }
+    /** Condition type. */
+    int conditionType();
 
     /**
-     * Returns the condition type.
+     * Returns condition type.
      *
      * @return Condition type.
      */
-    public ConditionType type() {
-        return type;
-    }
-
-    /**
-     * Creates a builder for a revision condition.
-     *
-     * @param key Key, which identifies an entry, which condition will be applied to.
-     * @return Builder for a revision condition.
-     * @see RevisionCondition
-     */
-    public static RevisionConditionBuilder revision(byte[] key) {
-        return new RevisionConditionBuilder(key);
-    }
-
-    /**
-     * Creates a builder for a value condition.
-     *
-     * @param key Key, which identifies an entry, which condition will be applied to.
-     * @return Builder for a value condition.
-     * @see ValueCondition
-     */
-    public static ValueConditionBuilder value(byte[] key) {
-        return new ValueConditionBuilder(key);
-    }
-
-    /**
-     * Produces the condition of type {@link ConditionType#TOMBSTONE}. This condition tests that an entry's value, identified by the
-     * given key, is tombstone.
-     *
-     * @return The condition of type {@link ConditionType#TOMBSTONE}.
-     */
-    public static SimpleCondition tombstone(byte[] key) {
-        return new SimpleCondition(key, ConditionType.TOMBSTONE);
-    }
-
-    /**
-     * Produces the condition of type {@link ConditionType#KEY_EXISTS}. This condition tests the existence of an entry identified by the
-     * given key.
-     *
-     * @return The condition of type {@link ConditionType#KEY_EXISTS}.
-     */
-    public static SimpleCondition exists(byte[] key) {
-        return new SimpleCondition(key, ConditionType.KEY_EXISTS);
-    }
-
-    /**
-     * Produces the condition of type {@link ConditionType#KEY_NOT_EXISTS}. This condition tests the non-existence of an entry
-     * identified by the given key.
-     *
-     * @return The condition of type {@link ConditionType#KEY_NOT_EXISTS}.
-     */
-    public static SimpleCondition notExists(byte[] key) {
-        return new SimpleCondition(key, ConditionType.KEY_NOT_EXISTS);
-    }
-
-    /**
-     * Builder for {@link RevisionCondition}.
-     */
-    public static final class RevisionConditionBuilder {
-        private final byte[] key;
-
-        RevisionConditionBuilder(byte[] key) {
-            this.key = key;
-        }
-
-        /**
-         * Produces the condition of type {@link ConditionType#REV_EQUAL}. This condition tests the given revision on equality
-         * with the target entry revision.
-         *
-         * @param rev The revision.
-         * @return The condition of type {@link ConditionType#REV_EQUAL}.
-         */
-        public SimpleCondition eq(long rev) {
-            return new RevisionCondition(key, ConditionType.REV_EQUAL, rev);
-        }
-
-        /**
-         * Produces the condition of type {@link ConditionType#REV_NOT_EQUAL}. This condition tests the given revision on inequality with
-         * the target entry revision.
-         *
-         * @param rev The revision.
-         * @return The condition of type {@link ConditionType#REV_NOT_EQUAL}.
-         */
-        public SimpleCondition ne(long rev) {
-            return new RevisionCondition(key, ConditionType.REV_NOT_EQUAL, rev);
-        }
-
-        /**
-         * Produces the condition of type {@link ConditionType#REV_GREATER}. This condition tests that the target entry revision is greater
-         * than the given revision.
-         *
-         * @param rev The revision.
-         * @return The condition of type {@link ConditionType#REV_GREATER}.
-         */
-        public SimpleCondition gt(long rev) {
-            return new RevisionCondition(key, ConditionType.REV_GREATER, rev);
-        }
-
-        /**
-         * Produces the condition of type {@link ConditionType#REV_GREATER_OR_EQUAL}. This condition tests that the target entry revision is
-         * greater than or equals to the given revision.
-         *
-         * @param rev The revision.
-         * @return The condition of type {@link ConditionType#REV_GREATER_OR_EQUAL}.
-         */
-        public SimpleCondition ge(long rev) {
-            return new RevisionCondition(key, ConditionType.REV_GREATER_OR_EQUAL, rev);
-        }
-
-        /**
-         * Produces the condition of type {@link ConditionType#REV_LESS}. This condition tests that the target entry revision is less
-         * than the given revision.
-         *
-         * @param rev The revision.
-         * @return The condition of type {@link ConditionType#REV_LESS}.
-         */
-        public SimpleCondition lt(long rev) {
-            return new RevisionCondition(key, ConditionType.REV_LESS, rev);
-        }
-
-        /**
-         * Produces the condition of type {@link ConditionType#REV_LESS_OR_EQUAL}. This condition tests that the target entry revision
-         * is less than or equals to the given revision.
-         *
-         * @param rev The revision.
-         * @return The condition of type {@link ConditionType#REV_LESS_OR_EQUAL}.
-         */
-        public SimpleCondition le(long rev) {
-            return new RevisionCondition(key, ConditionType.REV_LESS_OR_EQUAL, rev);
-        }
+    default ConditionType type() {
+        return ConditionType.values()[conditionType()];
     }
 
     /**
      * Represents a condition on an entry revision.
      */
-    public static final class RevisionCondition extends SimpleCondition {
+    @Transferable(MetaStorageMessageGroup.REVISION_CONDITION)
+    interface RevisionCondition extends SimpleCondition {
         /** The revision as the condition argument. */
-        private final long rev;
-
-        /**
-         * Constructs a condition by a revision for an entry identified by the given key.
-         *
-         * @param key Identifies an entry, which condition will be applied to.
-         */
-        RevisionCondition(byte[] key, ConditionType type, long rev) {
-            super(key, type);
-
-            assert rev > 0 : "Revision must be positive";
-
-            this.rev = rev;
-        }
-
-        /**
-         * Returns the revision that will be used as a part of this condition.
-         */
-        public long revision() {
-            return rev;
-        }
-    }
-
-    /**
-     * Builder for {@link ValueCondition}.
-     */
-    public static final class ValueConditionBuilder {
-        private final byte[] key;
-
-        ValueConditionBuilder(byte[] key) {
-            this.key = key;
-        }
-
-        /**
-         * Produces the condition of type {@link ConditionType#VAL_EQUAL}. This condition tests the given value on equality with the target
-         * entry value.
-         *
-         * @param val The value.
-         * @return The condition of type {@link ConditionType#VAL_EQUAL}.
-         */
-        public SimpleCondition eq(byte[] val) {
-            return new ValueCondition(key, ConditionType.VAL_EQUAL, val);
-        }
-
-        /**
-         * Produces the condition of type {@link ConditionType#VAL_NOT_EQUAL}. This condition tests the given value on inequality with
-         * the target entry value.
-         *
-         * @param val The value.
-         * @return The condition of type {@link ConditionType#VAL_NOT_EQUAL}.
-         */
-        public SimpleCondition ne(byte[] val) {
-            return new ValueCondition(key, ConditionType.VAL_NOT_EQUAL, val);
-        }
-
-        /**
-         * Produces the condition of type {@link ConditionType#VAL_GREATER}. This condition tests that the target entry value is greater
-         * than the given value in the lexicographical order.
-         *
-         * @param val The value.
-         * @return The condition of type {@link ConditionType#VAL_GREATER}.
-         */
-        public SimpleCondition gt(byte[] val) {
-            return new ValueCondition(key, ConditionType.VAL_GREATER, val);
-        }
-
-        /**
-         * Produces the condition of type {@link ConditionType#VAL_GREATER_OR_EQUAL}. This condition tests that the target entry value is
-         * greater than or equals to the given value in the lexicographical order.
-         *
-         * @param val The value.
-         * @return The condition of type {@link ConditionType#VAL_GREATER_OR_EQUAL}.
-         */
-        public SimpleCondition ge(byte[] val) {
-            return new ValueCondition(key, ConditionType.VAL_GREATER_OR_EQUAL, val);
-        }
-
-        /**
-         * Produces the condition of type {@link ConditionType#VAL_LESS}. This condition tests that the target entry value is less than the
-         * given value in the lexicographical order.
-         *
-         * @param val The value.
-         * @return The condition of type {@link ConditionType#VAL_LESS}.
-         */
-        public SimpleCondition lt(byte[] val) {
-            return new ValueCondition(key, ConditionType.VAL_LESS, val);
-        }
-
-        /**
-         * Produces the condition of type {@link ConditionType#VAL_LESS_OR_EQUAL}. This condition tests that the target entry value is less
-         * than or equals to the given value in the lexicographical order.
-         *
-         * @param val The value.
-         * @return The condition of type {@link ConditionType#VAL_LESS_OR_EQUAL}.
-         */
-        public SimpleCondition le(byte[] val) {
-            return new ValueCondition(key, ConditionType.VAL_LESS_OR_EQUAL, val);
-        }
+        long revision();
     }
 
     /**
      * Represents a condition on an entry value.
      */
-    public static final class ValueCondition extends SimpleCondition {
+    @Transferable(MetaStorageMessageGroup.VALUE_CONDITION)
+    interface ValueCondition extends SimpleCondition {
         /** The value as the condition argument. */
-        private final byte[] val;
-
-        /**
-         * Constructs a condition by a value for an entry identified by the given key.
-         *
-         * @param key Identifies an entry, which condition will be applied to.
-         */
-        ValueCondition(byte[] key, ConditionType type, byte[] val) {
-            super(key, type);
-
-            this.val = val;
-        }
-
-        /**
-         * Returns the value that will be used as a part of this condition.
-         */
-        public byte[] value() {
-            return val;
-        }
+        byte[] value();
     }
 }
diff --git a/modules/metastorage-api/src/main/java/org/apache/ignite/internal/metastorage/dsl/Statement.java b/modules/metastorage-api/src/main/java/org/apache/ignite/internal/metastorage/dsl/Statement.java
index f9b9f32b7d..d8d157d9e5 100644
--- a/modules/metastorage-api/src/main/java/org/apache/ignite/internal/metastorage/dsl/Statement.java
+++ b/modules/metastorage-api/src/main/java/org/apache/ignite/internal/metastorage/dsl/Statement.java
@@ -17,67 +17,31 @@
 
 package org.apache.ignite.internal.metastorage.dsl;
 
+import org.apache.ignite.network.NetworkMessage;
+import org.apache.ignite.network.annotations.Transferable;
+
 /**
- * Simple Either-like wrapper to hold one of the statement type: {@link If} or {@link Update}.
- * Needed to construct and simple deconstruction of nested {@link If},
+ * Simple Either-like wrapper to hold one of the statement type: {@link Iif} or {@link Update}.
+ * Needed to construct and simple deconstruction of nested {@link Iif},
  * instead of empty interface and instanceof-based unwrap.
- *
- * @see If
  */
-public class Statement {
-    /** If value holder. */
-    private final If iif;
-
-    /** Update value holder. */
-    private final Update update;
-
-    /**
-     * Constructs new {@link If} statement.
-     *
-     * @param iif If
-     */
-    public Statement(If iif) {
-        this.iif = iif;
-        this.update = null;
-    }
-
-    /**
-     * Constructs new {@link Update} terminal statement.
-     *
-     * @param update Update
-     */
-    public Statement(Update update) {
-        this.update = update;
-        this.iif = null;
-    }
-
-    /**
-     * Returns true, if statement has no nested statement (i.e. it is {@link Update} statement).
-     *
-     * @return true, if statement has no nested statement (i.e. it is {@link Update} statement).
-     */
-    public boolean isTerminal() {
-        return update != null;
-    }
+public interface Statement extends NetworkMessage {
 
     /**
-     * Returns If or {@code null}, if no If value.
-     *
-     * <p>Note: check which field is filled by {@link #isTerminal()}</p>
-     *
-     * @return If or {@code null}, if no If value.
+     * Statement containing an {@code If} type.
      */
-    public If iif() {
-        return iif;
+    @Transferable(MetaStorageMessageGroup.IF_STATEMENT)
+    interface IfStatement extends Statement {
+        /** If value holder. */
+        Iif iif();
     }
 
     /**
-     * Returns Update or {@code null}, if no update value.
-     * Note: check which field is filled by {@link #isTerminal()}
-     *
-     * @return Update or {@code null}, if no update value.
+     * Statement containing an {@code Update} type.
      */
-    public Update update() {
-        return update;
+    @Transferable(MetaStorageMessageGroup.UPDATE_STATEMENT)
+    interface UpdateStatement extends Statement {
+        /** Update value holder. */
+        Update update();
     }
 }
diff --git a/modules/metastorage-api/src/main/java/org/apache/ignite/internal/metastorage/dsl/StatementResult.java b/modules/metastorage-api/src/main/java/org/apache/ignite/internal/metastorage/dsl/StatementResult.java
index 2d02c5e4a0..0d648969bb 100644
--- a/modules/metastorage-api/src/main/java/org/apache/ignite/internal/metastorage/dsl/StatementResult.java
+++ b/modules/metastorage-api/src/main/java/org/apache/ignite/internal/metastorage/dsl/StatementResult.java
@@ -17,58 +17,32 @@
 
 package org.apache.ignite.internal.metastorage.dsl;
 
-import static org.apache.ignite.lang.ErrorGroups.MetaStorage.OP_EXECUTION_ERR;
-
+import java.io.Serializable;
 import java.nio.ByteBuffer;
-import org.apache.ignite.internal.metastorage.exceptions.MetaStorageException;
+import org.apache.ignite.network.NetworkMessage;
+import org.apache.ignite.network.annotations.Transferable;
 
 /**
  * Simple result of statement execution, backed by byte[] array.
  * Provides some shortcut methods to represent the values of some primitive types.
  */
-public class StatementResult {
+@Transferable(MetaStorageMessageGroup.STATEMENT_RESULT)
+public interface StatementResult extends NetworkMessage, Serializable {
     /** Result data. */
-    private final byte[] result;
-
-    /**
-     * Constructs result from the byte array.
-     *
-     * @param result byte array.
-     */
-    public StatementResult(byte[] result) {
-        this.result = result;
-    }
-
-    /**
-     * Constructs result from the boolean value.
-     *
-     * @param result boolean.
-     */
-    public StatementResult(boolean result) {
-        this.result = new byte[] {(byte) (result ? 1 : 0)};
-    }
-
-    /**
-     * Constructs result from the int value.
-     *
-     * @param result int.
-     */
-    public StatementResult(int result) {
-        this.result = ByteBuffer.allocate(4).putInt(result).array();
-    }
+    byte[] result();
 
     /**
      * Returns result value as a boolean.
      *
      * @return boolean result.
-     * @throws ResultConversionException if boolean conversion is not possible, or can have ambiguous behaviour.
+     * @throws IllegalStateException if boolean conversion is not possible, or can have ambiguous behaviour.
      */
-    public boolean getAsBoolean() {
-        if (result.length != 1) {
-            throw new ResultConversionException("Result can't be interpreted as boolean");
+    default boolean getAsBoolean() {
+        if (result().length != 1) {
+            throw new IllegalStateException("Result can't be interpreted as boolean");
         }
 
-        return result[0] != 0;
+        return result()[0] != 0;
 
     }
 
@@ -76,37 +50,13 @@ public class StatementResult {
      * Returns result as an int.
      *
      * @return int result.
-     * @throws ResultConversionException if int conversion is not possible, or can have ambiguous behaviour.
+     * @throws IllegalStateException if int conversion is not possible, or can have ambiguous behaviour.
      */
-    public Integer getAsInt() {
-        if (result.length != 4) {
-            throw new ResultConversionException("Result can't be interpreted as int");
+    default int getAsInt() {
+        if (result().length != 4) {
+            throw new IllegalStateException("Result can't be interpreted as int");
         }
 
-        return ByteBuffer.wrap(result).getInt();
-    }
-
-    /**
-     * Returns backed byte array.
-     *
-     * @return backed byte array.
-     */
-    public byte[] bytes() {
-        return result;
-    }
-
-    /**
-     * Exception to propagate result type conversion issues.
-     */
-    public static class ResultConversionException extends MetaStorageException {
-
-        /**
-         * Constructs new conversion exception.
-         *
-         * @param msg exception message.
-         */
-        public ResultConversionException(String msg) {
-            super(OP_EXECUTION_ERR, msg);
-        }
+        return ByteBuffer.wrap(result()).getInt();
     }
 }
diff --git a/modules/metastorage-api/src/main/java/org/apache/ignite/internal/metastorage/dsl/Statements.java b/modules/metastorage-api/src/main/java/org/apache/ignite/internal/metastorage/dsl/Statements.java
new file mode 100644
index 0000000000..8dd7f9fb71
--- /dev/null
+++ b/modules/metastorage-api/src/main/java/org/apache/ignite/internal/metastorage/dsl/Statements.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.metastorage.dsl;
+
+/**
+ * Static factory for various statements.
+ */
+public class Statements {
+    private static final MetaStorageMessagesFactory MSG_FACTORY = new MetaStorageMessagesFactory();
+
+    /**
+     * Simple helper for create the new {@link Iif} statement.
+     *
+     * @param condition Boolean condition.
+     * @param andThen Execution branch, if condition evaluates to true.
+     * @param orElse Execution branch, if condition evaluates to false.
+     * @return new {@link Iif} statement.
+     */
+    public static Iif iif(Condition condition, Iif andThen, Iif orElse) {
+        return MSG_FACTORY.iif()
+                .condition(condition)
+                .andThen(MSG_FACTORY.ifStatement().iif(andThen).build())
+                .orElse(MSG_FACTORY.ifStatement().iif(orElse).build())
+                .build();
+    }
+
+    /**
+     * Simple helper for create the new {@link Iif} statement.
+     *
+     * @param condition Boolean condition.
+     * @param andThen Execution branch, if condition evaluates to true.
+     * @param orElse Execution branch, if condition evaluates to false.
+     * @return new {@link Iif} statement.
+     */
+    public static Iif iif(Condition condition, Iif andThen, Update orElse) {
+        return MSG_FACTORY.iif()
+                .condition(condition)
+                .andThen(MSG_FACTORY.ifStatement().iif(andThen).build())
+                .orElse(MSG_FACTORY.updateStatement().update(orElse).build())
+                .build();
+    }
+
+    /**
+     * Simple helper for create the new {@link Iif} statement.
+     *
+     * @param condition Boolean condition.
+     * @param andThen Execution branch, if condition evaluates to true.
+     * @param orElse Execution branch, if condition evaluates to false.
+     * @return new {@link Iif} statement.
+     */
+    public static Iif iif(Condition condition, Update andThen, Iif orElse) {
+        return MSG_FACTORY.iif()
+                .condition(condition)
+                .andThen(MSG_FACTORY.updateStatement().update(andThen).build())
+                .orElse(MSG_FACTORY.ifStatement().iif(orElse).build())
+                .build();
+    }
+
+    /**
+     * Simple helper for create the new {@link Iif} statement.
+     *
+     * @param condition Boolean condition.
+     * @param andThen Execution branch, if condition evaluates to true.
+     * @param orElse Execution branch, if condition evaluates to false.
+     * @return new {@link Iif} statement.
+     */
+    public static Iif iif(Condition condition, Update andThen, Update orElse) {
+        return MSG_FACTORY.iif()
+                .condition(condition)
+                .andThen(MSG_FACTORY.updateStatement().update(andThen).build())
+                .orElse(MSG_FACTORY.updateStatement().update(orElse).build())
+                .build();
+    }
+
+    private Statements() {
+    }
+}
diff --git a/modules/metastorage-api/src/main/java/org/apache/ignite/internal/metastorage/dsl/Update.java b/modules/metastorage-api/src/main/java/org/apache/ignite/internal/metastorage/dsl/Update.java
index 4e74d2b2cf..cc07550aa4 100644
--- a/modules/metastorage-api/src/main/java/org/apache/ignite/internal/metastorage/dsl/Update.java
+++ b/modules/metastorage-api/src/main/java/org/apache/ignite/internal/metastorage/dsl/Update.java
@@ -18,43 +18,17 @@
 package org.apache.ignite.internal.metastorage.dsl;
 
 import java.util.Collection;
+import org.apache.ignite.network.NetworkMessage;
+import org.apache.ignite.network.annotations.Transferable;
 
 /**
  * Simple operations + result wrapper to describe the terminal branch of {@link If} execution.
  */
-public class Update {
+@Transferable(MetaStorageMessageGroup.UPDATE)
+public interface Update extends NetworkMessage {
     /** Operations. */
-    private final Collection<Operation> ops;
+    Collection<Operation> operations();
 
     /** Result. */
-    private final StatementResult result;
-
-    /**
-     * Constructs new update object.
-     *
-     * @param ops operations
-     * @param result result
-     */
-    public Update(Collection<Operation> ops, StatementResult result) {
-        this.ops = ops;
-        this.result = result;
-    }
-
-    /**
-     * Returns operations.
-     *
-     * @return operations.
-     */
-    public Collection<Operation> operations() {
-        return ops;
-    }
-
-    /**
-     * Returns result.
-     *
-     * @return result.
-     */
-    public StatementResult result() {
-        return result;
-    }
+    StatementResult result();
 }
diff --git a/modules/metastorage/src/integrationTest/java/org/apache/ignite/internal/metastorage/impl/ItMetaStorageServiceTest.java b/modules/metastorage/src/integrationTest/java/org/apache/ignite/internal/metastorage/impl/ItMetaStorageServiceTest.java
index 78c8fda92a..2189724155 100644
--- a/modules/metastorage/src/integrationTest/java/org/apache/ignite/internal/metastorage/impl/ItMetaStorageServiceTest.java
+++ b/modules/metastorage/src/integrationTest/java/org/apache/ignite/internal/metastorage/impl/ItMetaStorageServiceTest.java
@@ -19,19 +19,19 @@ package org.apache.ignite.internal.metastorage.impl;
 
 import static java.util.stream.Collectors.toList;
 import static java.util.stream.Collectors.toUnmodifiableSet;
-import static org.apache.ignite.internal.metastorage.dsl.CompoundCondition.and;
-import static org.apache.ignite.internal.metastorage.dsl.CompoundCondition.or;
+import static org.apache.ignite.internal.metastorage.dsl.Conditions.and;
+import static org.apache.ignite.internal.metastorage.dsl.Conditions.or;
 import static org.apache.ignite.internal.metastorage.dsl.Conditions.revision;
 import static org.apache.ignite.internal.metastorage.dsl.Conditions.value;
-import static org.apache.ignite.internal.metastorage.dsl.If.iif;
 import static org.apache.ignite.internal.metastorage.dsl.Operations.ops;
 import static org.apache.ignite.internal.metastorage.dsl.Operations.put;
 import static org.apache.ignite.internal.metastorage.dsl.Operations.remove;
+import static org.apache.ignite.internal.metastorage.dsl.Statements.iif;
 import static org.apache.ignite.internal.metastorage.impl.ItMetaStorageServiceTest.ServerConditionMatcher.cond;
-import static org.apache.ignite.internal.metastorage.impl.ItMetaStorageServiceTest.ServerUpdateMatcher.upd;
 import static org.apache.ignite.internal.testframework.matchers.CompletableFutureMatcher.willCompleteSuccessfully;
 import static org.apache.ignite.utils.ClusterServiceTestUtils.findLocalAddresses;
 import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
 import static org.junit.jupiter.api.Assertions.assertArrayEquals;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertThrows;
@@ -49,8 +49,6 @@ import java.nio.file.Path;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
-import java.util.Collections;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.NavigableMap;
@@ -67,17 +65,15 @@ import org.apache.ignite.internal.hlc.HybridClockImpl;
 import org.apache.ignite.internal.metastorage.Entry;
 import org.apache.ignite.internal.metastorage.dsl.Condition;
 import org.apache.ignite.internal.metastorage.dsl.Conditions;
-import org.apache.ignite.internal.metastorage.dsl.If;
 import org.apache.ignite.internal.metastorage.dsl.Operation;
 import org.apache.ignite.internal.metastorage.dsl.OperationType;
 import org.apache.ignite.internal.metastorage.dsl.Operations;
-import org.apache.ignite.internal.metastorage.dsl.StatementResult;
-import org.apache.ignite.internal.metastorage.dsl.Update;
 import org.apache.ignite.internal.metastorage.exceptions.CompactedException;
 import org.apache.ignite.internal.metastorage.exceptions.OperationTimeoutException;
 import org.apache.ignite.internal.metastorage.server.AbstractCompoundCondition;
 import org.apache.ignite.internal.metastorage.server.AbstractSimpleCondition;
 import org.apache.ignite.internal.metastorage.server.AndCondition;
+import org.apache.ignite.internal.metastorage.server.If;
 import org.apache.ignite.internal.metastorage.server.KeyValueStorage;
 import org.apache.ignite.internal.metastorage.server.OrCondition;
 import org.apache.ignite.internal.metastorage.server.RevisionCondition;
@@ -734,7 +730,7 @@ public class ItMetaStorageServiceTest {
             return false
          */
 
-        var iif = If.iif(or(value(key1).eq(val1), value(key2).ne(val2)),
+        var iif = iif(or(value(key1).eq(val1), value(key2).ne(val2)),
                 iif(or(revision(key3).eq(3), or(value(key2).gt(val1), value(key1).ge(val2))),
                         ops(put(key1, rval1)).yield(true),
                         iif(and(value(key2).lt(val1), value(key1).le(val2)),
@@ -742,9 +738,9 @@ public class ItMetaStorageServiceTest {
                                 ops().yield(true))),
                 ops(put(key2, rval2)).yield(false));
 
-        var ifCaptor = ArgumentCaptor.forClass(org.apache.ignite.internal.metastorage.server.If.class);
+        var ifCaptor = ArgumentCaptor.forClass(If.class);
 
-        when(node.mockStorage.invoke(any())).thenReturn(new StatementResult(true));
+        when(node.mockStorage.invoke(any())).thenReturn(ops().yield(true).result());
 
         assertTrue(node.metaStorageService.invoke(iif).get().getAsBoolean());
 
@@ -764,20 +760,25 @@ public class ItMetaStorageServiceTest {
                 cond(new AndCondition(new ValueCondition(ValueCondition.Type.LESS, key2.bytes(), val1), new ValueCondition(
                         Type.LESS_OR_EQUAL, key1.bytes(), val2))));
 
-        assertThat(resultIf.andThen().iif().andThen().update(), upd(new Update(
-                List.of(Operation.put(key1.bytes(), rval1)),
-                new StatementResult(true))));
+        assertThat(
+                resultIf.andThen().iif().andThen().update(),
+                is(ops(put(key1, rval1)).yield(true))
+        );
 
-        assertThat(resultIf.andThen().iif().orElse().iif().andThen().update(), upd(new Update(
-                Arrays.asList(Operation.put(key1.bytes(), rval1), Operation.remove(key2.bytes())),
-                new StatementResult(false))));
+        assertThat(
+                resultIf.andThen().iif().orElse().iif().andThen().update(),
+                is(ops(put(key1, rval1), remove(key2)).yield(false))
+        );
 
-        assertThat(resultIf.andThen().iif().orElse().iif().orElse().update(),
-                upd(new Update(Collections.emptyList(), new StatementResult(true))));
+        assertThat(
+                resultIf.andThen().iif().orElse().iif().orElse().update(),
+                is(ops().yield(true))
+        );
 
-        assertThat(resultIf.orElse().update(), upd(new Update(
-                List.of(Operation.put(key2.bytes(), rval2)),
-                new StatementResult(false))));
+        assertThat(
+                resultIf.orElse().update(),
+                is(ops(put(key2, rval2)).yield(false))
+        );
     }
 
     @Test
@@ -885,58 +886,6 @@ public class ItMetaStorageServiceTest {
         assertEquals(EXPECTED_RESULT_ENTRY, cursorNode1.iterator().next());
     }
 
-    /**
-     * Matcher for {@link Update}.
-     */
-    protected static class ServerUpdateMatcher extends TypeSafeMatcher<Update> {
-
-        private final Update update;
-
-        public ServerUpdateMatcher(Update update) {
-            this.update = update;
-        }
-
-        public static ServerUpdateMatcher upd(Update update) {
-            return new ServerUpdateMatcher(update);
-        }
-
-        @Override
-        protected boolean matchesSafely(Update item) {
-            return item.operations().size() == update.operations().size()
-                    && Arrays.equals(item.result().bytes(), update.result().bytes())
-                    && opsEqual(item.operations().iterator(), update.operations().iterator());
-
-        }
-
-        @Override
-        public void describeTo(Description description) {
-            description.appendText(toString(update));
-        }
-
-        @Override
-        protected void describeMismatchSafely(Update item, Description mismatchDescription) {
-            mismatchDescription.appendText(toString(item));
-        }
-
-        private String toString(Update upd) {
-            return "Update([" + upd.operations().stream()
-                    .map(o -> o.type() + "(" + Arrays.toString(o.key()) + ", " + Arrays.toString(o.value()) + ")")
-                    .collect(Collectors.joining(",")) + "])";
-        }
-
-        private boolean opsEqual(Iterator<Operation> ops1, Iterator<Operation> ops2) {
-            if (!ops1.hasNext()) {
-                return true;
-            } else {
-                return opEqual(ops1.next(), ops2.next()) && opsEqual(ops1, ops2);
-            }
-        }
-
-        private boolean opEqual(Operation op1, Operation op2) {
-            return Arrays.equals(op1.key(), op2.key()) && Arrays.equals(op1.value(), op2.value()) && op1.type() == op2.type();
-        }
-    }
-
     /**
      * Matcher for {@link Condition}.
      */
diff --git a/modules/metastorage/src/main/java/org/apache/ignite/internal/metastorage/command/InvokeCommand.java b/modules/metastorage/src/main/java/org/apache/ignite/internal/metastorage/command/InvokeCommand.java
index 8fa7d4157d..be00fb59d6 100644
--- a/modules/metastorage/src/main/java/org/apache/ignite/internal/metastorage/command/InvokeCommand.java
+++ b/modules/metastorage/src/main/java/org/apache/ignite/internal/metastorage/command/InvokeCommand.java
@@ -17,9 +17,9 @@
 
 package org.apache.ignite.internal.metastorage.command;
 
-import java.util.List;
-import org.apache.ignite.internal.metastorage.command.info.ConditionInfo;
-import org.apache.ignite.internal.metastorage.command.info.OperationInfo;
+import java.util.Collection;
+import org.apache.ignite.internal.metastorage.dsl.Condition;
+import org.apache.ignite.internal.metastorage.dsl.Operation;
 import org.apache.ignite.internal.raft.WriteCommand;
 import org.apache.ignite.network.annotations.Transferable;
 
@@ -33,19 +33,19 @@ public interface InvokeCommand extends WriteCommand {
      *
      * @return Condition.
      */
-    ConditionInfo condition();
+    Condition condition();
 
     /**
      * Returns success operations.
      *
      * @return Success operations.
      */
-    List<OperationInfo> success();
+    Collection<Operation> success();
 
     /**
      * Returns failure operations.
      *
      * @return Failure operations.
      */
-    List<OperationInfo> failure();
+    Collection<Operation> failure();
 }
diff --git a/modules/metastorage/src/main/java/org/apache/ignite/internal/metastorage/command/MetastorageCommandsMessageGroup.java b/modules/metastorage/src/main/java/org/apache/ignite/internal/metastorage/command/MetastorageCommandsMessageGroup.java
index 40f44346c1..67c10769e0 100644
--- a/modules/metastorage/src/main/java/org/apache/ignite/internal/metastorage/command/MetastorageCommandsMessageGroup.java
+++ b/modules/metastorage/src/main/java/org/apache/ignite/internal/metastorage/command/MetastorageCommandsMessageGroup.java
@@ -21,13 +21,6 @@ import org.apache.ignite.internal.metastorage.command.cursor.CursorCloseCommand;
 import org.apache.ignite.internal.metastorage.command.cursor.CursorHasNextCommand;
 import org.apache.ignite.internal.metastorage.command.cursor.CursorNextCommand;
 import org.apache.ignite.internal.metastorage.command.cursor.CursorsCloseCommand;
-import org.apache.ignite.internal.metastorage.command.info.CompoundConditionInfo;
-import org.apache.ignite.internal.metastorage.command.info.IfInfo;
-import org.apache.ignite.internal.metastorage.command.info.OperationInfo;
-import org.apache.ignite.internal.metastorage.command.info.SimpleConditionInfo;
-import org.apache.ignite.internal.metastorage.command.info.StatementInfo;
-import org.apache.ignite.internal.metastorage.command.info.StatementResultInfo;
-import org.apache.ignite.internal.metastorage.command.info.UpdateInfo;
 import org.apache.ignite.network.annotations.MessageGroup;
 
 /**
@@ -35,27 +28,6 @@ import org.apache.ignite.network.annotations.MessageGroup;
  */
 @MessageGroup(groupType = 111, groupName = "MetaStorageCommands")
 public interface MetastorageCommandsMessageGroup {
-    /** Message type for {@link OperationInfo}. */
-    short OPERATION_INFO = 1;
-
-    /** Message type for {@link UpdateInfo}. */
-    short UPDATE_INFO = 2;
-
-    /** Message type for {@link StatementInfo}. */
-    short STATEMENT_INFO = 3;
-
-    /** Message type for {@link SimpleConditionInfo}. */
-    short SIMPLE_CONDITION_INFO = 4;
-
-    /** Message type for {@link CompoundConditionInfo}. */
-    short COMPOUND_CONDITION_INFO = 5;
-
-    /** Message type for {@link StatementResultInfo}. */
-    short STATEMENT_RESULT_INFO = 6;
-
-    /** Message type for {@link IfInfo}. */
-    short IF_INFO = 7;
-
     /** Message type for {@link InvokeCommand}. */
     short INVOKE = 10;
 
diff --git a/modules/metastorage/src/main/java/org/apache/ignite/internal/metastorage/command/MultiInvokeCommand.java b/modules/metastorage/src/main/java/org/apache/ignite/internal/metastorage/command/MultiInvokeCommand.java
index c0590214a5..843f418641 100644
--- a/modules/metastorage/src/main/java/org/apache/ignite/internal/metastorage/command/MultiInvokeCommand.java
+++ b/modules/metastorage/src/main/java/org/apache/ignite/internal/metastorage/command/MultiInvokeCommand.java
@@ -17,7 +17,7 @@
 
 package org.apache.ignite.internal.metastorage.command;
 
-import org.apache.ignite.internal.metastorage.command.info.IfInfo;
+import org.apache.ignite.internal.metastorage.dsl.Iif;
 import org.apache.ignite.internal.raft.WriteCommand;
 import org.apache.ignite.network.annotations.Transferable;
 
@@ -31,5 +31,5 @@ public interface MultiInvokeCommand extends WriteCommand {
      *
      * @return if statement.
      */
-    IfInfo iif();
+    Iif iif();
 }
diff --git a/modules/metastorage/src/main/java/org/apache/ignite/internal/metastorage/command/info/CompoundConditionInfo.java b/modules/metastorage/src/main/java/org/apache/ignite/internal/metastorage/command/info/CompoundConditionInfo.java
deleted file mode 100644
index b45e445a93..0000000000
--- a/modules/metastorage/src/main/java/org/apache/ignite/internal/metastorage/command/info/CompoundConditionInfo.java
+++ /dev/null
@@ -1,59 +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.metastorage.command.info;
-
-import org.apache.ignite.internal.metastorage.command.MetastorageCommandsMessageGroup;
-import org.apache.ignite.internal.metastorage.command.MultiInvokeCommand;
-import org.apache.ignite.internal.metastorage.dsl.CompoundConditionType;
-import org.apache.ignite.network.annotations.Transferable;
-
-/**
- * Defines compound multi-key condition for {@link MultiInvokeCommand}.
- */
-@Transferable(MetastorageCommandsMessageGroup.COMPOUND_CONDITION_INFO)
-public interface CompoundConditionInfo extends ConditionInfo {
-    /**
-     * Returns left condition definition.
-     *
-     * @return left condition definition.
-     */
-    ConditionInfo leftConditionInfo();
-
-    /**
-     * Returns right condition definition.
-     *
-     * @return right condition definition.
-     */
-    ConditionInfo rightConditionInfo();
-
-    /**
-     * Returns definition for type of compound condition.
-     *
-     * @return definition for type of compound condition.
-     */
-    int conditionType();
-
-    /**
-     * Returns definition for type of compound condition.
-     *
-     * @return definition for type of compound condition.
-     */
-    default CompoundConditionType type() {
-        return CompoundConditionType.values()[conditionType()];
-    }
-}
diff --git a/modules/metastorage/src/main/java/org/apache/ignite/internal/metastorage/command/info/ConditionInfo.java b/modules/metastorage/src/main/java/org/apache/ignite/internal/metastorage/command/info/ConditionInfo.java
deleted file mode 100644
index 55e92e166b..0000000000
--- a/modules/metastorage/src/main/java/org/apache/ignite/internal/metastorage/command/info/ConditionInfo.java
+++ /dev/null
@@ -1,30 +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.metastorage.command.info;
-
-import java.io.Serializable;
-import org.apache.ignite.network.NetworkMessage;
-
-/**
- * Interface for condition definition.
- *
- * @see SimpleConditionInfo
- * @see CompoundConditionInfo
- */
-public interface ConditionInfo extends NetworkMessage, Serializable {
-}
diff --git a/modules/metastorage/src/main/java/org/apache/ignite/internal/metastorage/command/info/IfInfo.java b/modules/metastorage/src/main/java/org/apache/ignite/internal/metastorage/command/info/IfInfo.java
deleted file mode 100644
index 392ed3188f..0000000000
--- a/modules/metastorage/src/main/java/org/apache/ignite/internal/metastorage/command/info/IfInfo.java
+++ /dev/null
@@ -1,51 +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.metastorage.command.info;
-
-import java.io.Serializable;
-import org.apache.ignite.internal.metastorage.command.MetastorageCommandsMessageGroup;
-import org.apache.ignite.internal.metastorage.command.MultiInvokeCommand;
-import org.apache.ignite.network.NetworkMessage;
-import org.apache.ignite.network.annotations.Transferable;
-
-/**
- * Defines if-statement for {@link MultiInvokeCommand}.
- */
-@Transferable(MetastorageCommandsMessageGroup.IF_INFO)
-public interface IfInfo extends NetworkMessage, Serializable {
-    /**
-     * Returns boolean condition definition.
-     *
-     * @return Boolean condition definition.
-     */
-    ConditionInfo cond();
-
-    /**
-     * Returns definition of execution branch, if condition evaluates to true (aka left branch).
-     *
-     * @return Left execution branch definition.
-     */
-    StatementInfo andThen();
-
-    /**
-     * Returns definition of execution branch, if condition evaluates to false (aka right branch).
-     *
-     * @return Right execution branch definition.
-     */
-    StatementInfo orElse();
-}
diff --git a/modules/metastorage/src/main/java/org/apache/ignite/internal/metastorage/command/info/OperationInfo.java b/modules/metastorage/src/main/java/org/apache/ignite/internal/metastorage/command/info/OperationInfo.java
deleted file mode 100644
index 0f1354064e..0000000000
--- a/modules/metastorage/src/main/java/org/apache/ignite/internal/metastorage/command/info/OperationInfo.java
+++ /dev/null
@@ -1,60 +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.metastorage.command.info;
-
-import java.io.Serializable;
-import org.apache.ignite.internal.metastorage.command.MetastorageCommandsMessageGroup;
-import org.apache.ignite.internal.metastorage.dsl.OperationType;
-import org.apache.ignite.network.NetworkMessage;
-import org.apache.ignite.network.annotations.Transferable;
-
-/**
- * Defines operation.
- */
-@Transferable(MetastorageCommandsMessageGroup.OPERATION_INFO)
-public interface OperationInfo extends NetworkMessage, Serializable {
-    /**
-     * Returns key.
-     *
-     * @return Key.
-     */
-    byte[] key();
-
-    /**
-     * Returns value.
-     *
-     * @return Value.
-     */
-    byte[] value();
-
-    /**
-     * Returns operation type.
-     *
-     * @return Operation type.
-     */
-    int operationType();
-
-    /**
-     * Returns operation type.
-     *
-     * @return Operation type.
-     */
-    default OperationType type() {
-        return OperationType.values()[operationType()];
-    }
-}
diff --git a/modules/metastorage/src/main/java/org/apache/ignite/internal/metastorage/command/info/SimpleConditionInfo.java b/modules/metastorage/src/main/java/org/apache/ignite/internal/metastorage/command/info/SimpleConditionInfo.java
deleted file mode 100644
index e05d982985..0000000000
--- a/modules/metastorage/src/main/java/org/apache/ignite/internal/metastorage/command/info/SimpleConditionInfo.java
+++ /dev/null
@@ -1,65 +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.metastorage.command.info;
-
-import org.apache.ignite.internal.metastorage.command.MetastorageCommandsMessageGroup;
-import org.apache.ignite.internal.metastorage.dsl.ConditionType;
-import org.apache.ignite.network.annotations.Transferable;
-
-/**
- * Defines condition for InvokeCommand.
- */
-@Transferable(MetastorageCommandsMessageGroup.SIMPLE_CONDITION_INFO)
-public interface SimpleConditionInfo extends ConditionInfo {
-    /**
-     * Returns key.
-     *
-     * @return Key.
-     */
-    byte[] key();
-
-    /**
-     * Returns condition type.
-     *
-     * @return Condition type.
-     */
-    int conditionType();
-
-    /**
-     * Returns condition type.
-     *
-     * @return Condition type.
-     */
-    default ConditionType type() {
-        return ConditionType.values()[conditionType()];
-    }
-
-    /**
-     * Returns value.
-     *
-     * @return Value.
-     */
-    byte[] value();
-
-    /**
-     * Returns revision.
-     *
-     * @return Revision.
-     */
-    long revision();
-}
diff --git a/modules/metastorage/src/main/java/org/apache/ignite/internal/metastorage/command/info/StatementInfo.java b/modules/metastorage/src/main/java/org/apache/ignite/internal/metastorage/command/info/StatementInfo.java
deleted file mode 100644
index 24c13cf39e..0000000000
--- a/modules/metastorage/src/main/java/org/apache/ignite/internal/metastorage/command/info/StatementInfo.java
+++ /dev/null
@@ -1,59 +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.metastorage.command.info;
-
-import java.io.Serializable;
-import org.apache.ignite.internal.metastorage.command.MetastorageCommandsMessageGroup;
-import org.apache.ignite.network.NetworkMessage;
-import org.apache.ignite.network.annotations.Transferable;
-
-/**
- * Definition of simple Either-like wrapper to hold one of the statement type: {@link IfInfo} or {@link UpdateInfo}.
- * Needed to construct and simple deconstruction of nested {@link IfInfo},
- * instead of empty interface and instanceof-based unwrap.
- *
- * @see IfInfo
- * @see UpdateInfo
- */
-@Transferable(MetastorageCommandsMessageGroup.STATEMENT_INFO)
-public interface StatementInfo extends NetworkMessage, Serializable {
-    /**
-     * Returns {@link IfInfo} or {@code null}, if iif is not defined.
-     * Note: check which field is filled by {@link #isTerminal()}
-     *
-     * @return {@link IfInfo} or {@code null}, if iif is not defined.
-     */
-    IfInfo iif();
-
-    /**
-     * Returns {@link UpdateInfo} or {@code null}, if update is not defined.
-     * Note: check which field is filled by {@link #isTerminal()}
-     *
-     * @return {@link UpdateInfo} or {@code null}, if update is not defined.
-     */
-    UpdateInfo update();
-
-    /**
-     * Returns true, if statement has no nested statement (i.e. it is {@link UpdateInfo} statement definition).
-     *
-     * @return true, if statement has no nested statement (i.e. it is {@link UpdateInfo} statement definition).
-     */
-    default boolean isTerminal() {
-        return update() != null;
-    }
-}
diff --git a/modules/metastorage/src/main/java/org/apache/ignite/internal/metastorage/command/info/StatementResultInfo.java b/modules/metastorage/src/main/java/org/apache/ignite/internal/metastorage/command/info/StatementResultInfo.java
deleted file mode 100644
index 6bd52a25b4..0000000000
--- a/modules/metastorage/src/main/java/org/apache/ignite/internal/metastorage/command/info/StatementResultInfo.java
+++ /dev/null
@@ -1,36 +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.metastorage.command.info;
-
-import java.io.Serializable;
-import org.apache.ignite.internal.metastorage.command.MetastorageCommandsMessageGroup;
-import org.apache.ignite.network.NetworkMessage;
-import org.apache.ignite.network.annotations.Transferable;
-
-/**
- * Simple result definition of statement execution, backed by byte[] array.
- */
-@Transferable(MetastorageCommandsMessageGroup.STATEMENT_RESULT_INFO)
-public interface StatementResultInfo extends NetworkMessage, Serializable {
-    /**
-     * Returns result as row byte array.
-     *
-     * @return result as row byte array.
-     */
-    byte[] result();
-}
diff --git a/modules/metastorage/src/main/java/org/apache/ignite/internal/metastorage/command/info/UpdateInfo.java b/modules/metastorage/src/main/java/org/apache/ignite/internal/metastorage/command/info/UpdateInfo.java
deleted file mode 100644
index f214b84480..0000000000
--- a/modules/metastorage/src/main/java/org/apache/ignite/internal/metastorage/command/info/UpdateInfo.java
+++ /dev/null
@@ -1,45 +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.metastorage.command.info;
-
-import java.io.Serializable;
-import java.util.Collection;
-import org.apache.ignite.internal.metastorage.command.MetastorageCommandsMessageGroup;
-import org.apache.ignite.network.NetworkMessage;
-import org.apache.ignite.network.annotations.Transferable;
-
-/**
- * Simple operations + result wrapper definition to describe the terminal branch
- * of {@link IfInfo} execution.
- */
-@Transferable(MetastorageCommandsMessageGroup.UPDATE_INFO)
-public interface UpdateInfo extends NetworkMessage, Serializable {
-    /**
-     * Retunrs operations.
-     *
-     * @return operations.
-     */
-    Collection<OperationInfo> operations();
-
-    /**
-     * Returns result.
-     *
-     * @return result.
-     */
-    StatementResultInfo result();
-}
diff --git a/modules/metastorage/src/main/java/org/apache/ignite/internal/metastorage/impl/MetaStorageManagerImpl.java b/modules/metastorage/src/main/java/org/apache/ignite/internal/metastorage/impl/MetaStorageManagerImpl.java
index 92fc067327..edf63e7e42 100644
--- a/modules/metastorage/src/main/java/org/apache/ignite/internal/metastorage/impl/MetaStorageManagerImpl.java
+++ b/modules/metastorage/src/main/java/org/apache/ignite/internal/metastorage/impl/MetaStorageManagerImpl.java
@@ -41,7 +41,7 @@ import org.apache.ignite.internal.metastorage.Entry;
 import org.apache.ignite.internal.metastorage.MetaStorageManager;
 import org.apache.ignite.internal.metastorage.WatchListener;
 import org.apache.ignite.internal.metastorage.dsl.Condition;
-import org.apache.ignite.internal.metastorage.dsl.If;
+import org.apache.ignite.internal.metastorage.dsl.Iif;
 import org.apache.ignite.internal.metastorage.dsl.Operation;
 import org.apache.ignite.internal.metastorage.dsl.StatementResult;
 import org.apache.ignite.internal.metastorage.exceptions.CompactedException;
@@ -584,7 +584,7 @@ public class MetaStorageManagerImpl implements MetaStorageManager {
     }
 
     @Override
-    public CompletableFuture<StatementResult> invoke(If iif) {
+    public CompletableFuture<StatementResult> invoke(Iif iif) {
         if (!busyLock.enterBusy()) {
             return CompletableFuture.failedFuture(new NodeStoppingException());
         }
diff --git a/modules/metastorage/src/main/java/org/apache/ignite/internal/metastorage/impl/MetaStorageService.java b/modules/metastorage/src/main/java/org/apache/ignite/internal/metastorage/impl/MetaStorageService.java
index c66c577765..87207a95dc 100644
--- a/modules/metastorage/src/main/java/org/apache/ignite/internal/metastorage/impl/MetaStorageService.java
+++ b/modules/metastorage/src/main/java/org/apache/ignite/internal/metastorage/impl/MetaStorageService.java
@@ -24,7 +24,7 @@ import java.util.concurrent.CompletableFuture;
 import org.apache.ignite.internal.close.ManuallyCloseable;
 import org.apache.ignite.internal.metastorage.Entry;
 import org.apache.ignite.internal.metastorage.dsl.Condition;
-import org.apache.ignite.internal.metastorage.dsl.If;
+import org.apache.ignite.internal.metastorage.dsl.Iif;
 import org.apache.ignite.internal.metastorage.dsl.Operation;
 import org.apache.ignite.internal.metastorage.dsl.StatementResult;
 import org.apache.ignite.internal.metastorage.exceptions.CompactedException;
@@ -213,15 +213,15 @@ public interface MetaStorageService extends ManuallyCloseable {
     CompletableFuture<Boolean> invoke(Condition condition, Collection<Operation> success, Collection<Operation> failure);
 
     /**
-     * Invoke, which supports nested conditional statements. For detailed docs about construction of new if statement, look at {@link If}
+     * Invoke, which supports nested conditional statements. For detailed docs about construction of new if statement, look at {@link Iif}
      * javadocs.
      *
-     * @param iif {@link If} statement to invoke
+     * @param iif {@link Iif} statement to invoke
      * @return execution result
-     * @see If
+     * @see Iif
      * @see StatementResult
      */
-    CompletableFuture<StatementResult> invoke(If iif);
+    CompletableFuture<StatementResult> invoke(Iif iif);
 
     /**
      * Retrieves entries for the given key range in lexicographic order. Entries will be filtered out by upper bound of given revision
diff --git a/modules/metastorage/src/main/java/org/apache/ignite/internal/metastorage/impl/MetaStorageServiceImpl.java b/modules/metastorage/src/main/java/org/apache/ignite/internal/metastorage/impl/MetaStorageServiceImpl.java
index 1d64da7871..b27046728c 100644
--- a/modules/metastorage/src/main/java/org/apache/ignite/internal/metastorage/impl/MetaStorageServiceImpl.java
+++ b/modules/metastorage/src/main/java/org/apache/ignite/internal/metastorage/impl/MetaStorageServiceImpl.java
@@ -24,7 +24,6 @@ import static org.apache.ignite.internal.metastorage.command.GetAndRemoveAllComm
 import static org.apache.ignite.internal.metastorage.command.PutAllCommand.putAllCommand;
 import static org.apache.ignite.internal.metastorage.command.RemoveAllCommand.removeAllCommand;
 
-import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.List;
@@ -50,25 +49,10 @@ import org.apache.ignite.internal.metastorage.command.RangeCommand;
 import org.apache.ignite.internal.metastorage.command.RemoveAllCommand;
 import org.apache.ignite.internal.metastorage.command.RemoveCommand;
 import org.apache.ignite.internal.metastorage.command.SingleEntryResponse;
-import org.apache.ignite.internal.metastorage.command.info.ConditionInfo;
-import org.apache.ignite.internal.metastorage.command.info.IfInfo;
-import org.apache.ignite.internal.metastorage.command.info.OperationInfo;
-import org.apache.ignite.internal.metastorage.command.info.OperationInfoBuilder;
-import org.apache.ignite.internal.metastorage.command.info.SimpleConditionInfoBuilder;
-import org.apache.ignite.internal.metastorage.command.info.StatementInfo;
-import org.apache.ignite.internal.metastorage.command.info.StatementResultInfo;
-import org.apache.ignite.internal.metastorage.command.info.UpdateInfo;
-import org.apache.ignite.internal.metastorage.dsl.CompoundCondition;
 import org.apache.ignite.internal.metastorage.dsl.Condition;
-import org.apache.ignite.internal.metastorage.dsl.If;
+import org.apache.ignite.internal.metastorage.dsl.Iif;
 import org.apache.ignite.internal.metastorage.dsl.Operation;
-import org.apache.ignite.internal.metastorage.dsl.OperationType;
-import org.apache.ignite.internal.metastorage.dsl.SimpleCondition;
-import org.apache.ignite.internal.metastorage.dsl.SimpleCondition.RevisionCondition;
-import org.apache.ignite.internal.metastorage.dsl.SimpleCondition.ValueCondition;
-import org.apache.ignite.internal.metastorage.dsl.Statement;
 import org.apache.ignite.internal.metastorage.dsl.StatementResult;
-import org.apache.ignite.internal.metastorage.dsl.Update;
 import org.apache.ignite.internal.raft.service.RaftGroupService;
 import org.apache.ignite.internal.util.Cursor;
 import org.apache.ignite.lang.ByteArray;
@@ -219,24 +203,23 @@ public class MetaStorageServiceImpl implements MetaStorageService {
             Collection<Operation> success,
             Collection<Operation> failure
     ) {
-        ConditionInfo cond = toConditionInfo(condition, commandsFactory);
-
-        List<OperationInfo> successOps = toOperationInfos(success, commandsFactory);
-
-        List<OperationInfo> failureOps = toOperationInfos(failure, commandsFactory);
-
-        InvokeCommand invokeCommand = commandsFactory.invokeCommand().condition(cond).success(successOps).failure(failureOps).build();
+        InvokeCommand invokeCommand = commandsFactory.invokeCommand()
+                .condition(condition)
+                .success(success)
+                .failure(failure)
+                .build();
 
         return metaStorageRaftGrpSvc.run(invokeCommand);
     }
 
     /** {@inheritDoc} */
     @Override
-    public CompletableFuture<StatementResult> invoke(If iif) {
-        MultiInvokeCommand multiInvokeCommand = commandsFactory.multiInvokeCommand().iif(toIfInfo(iif, commandsFactory)).build();
+    public CompletableFuture<StatementResult> invoke(Iif iif) {
+        MultiInvokeCommand multiInvokeCommand = commandsFactory.multiInvokeCommand()
+                .iif(iif)
+                .build();
 
-        return metaStorageRaftGrpSvc.run(multiInvokeCommand)
-                .thenApply(bi -> new StatementResult(((StatementResultInfo) bi).result()));
+        return metaStorageRaftGrpSvc.run(multiInvokeCommand);
     }
 
     /** {@inheritDoc} */
@@ -319,96 +302,6 @@ public class MetaStorageServiceImpl implements MetaStorageService {
         metaStorageRaftGrpSvc.shutdown();
     }
 
-    private static List<OperationInfo> toOperationInfos(Collection<Operation> ops, MetaStorageCommandsFactory commandsFactory) {
-        List<OperationInfo> res = new ArrayList<>(ops.size());
-
-        for (Operation op : ops) {
-            OperationInfoBuilder info = commandsFactory.operationInfo();
-
-            switch (op.type()) {
-                case NO_OP:
-                    info.operationType(OperationType.NO_OP.ordinal());
-
-                    break;
-
-                case REMOVE:
-                    info.key(op.key()).operationType(OperationType.REMOVE.ordinal());
-
-                    break;
-
-                case PUT:
-                    info.key(op.key()).value(op.value()).operationType(OperationType.PUT.ordinal());
-
-                    break;
-
-                default:
-                    assert false : "Unknown operation type " + op.type();
-            }
-
-            res.add(info.build());
-        }
-
-        return res;
-    }
-
-    private static UpdateInfo toUpdateInfo(Update update, MetaStorageCommandsFactory commandsFactory) {
-        return commandsFactory.updateInfo()
-                .operations(toOperationInfos(update.operations(), commandsFactory))
-                .result(commandsFactory.statementResultInfo().result(update.result().bytes()).build())
-                .build();
-    }
-
-    private static StatementInfo toIfBranchInfo(Statement statement, MetaStorageCommandsFactory commandsFactory) {
-        if (statement.isTerminal()) {
-            return commandsFactory.statementInfo().update(toUpdateInfo(statement.update(), commandsFactory)).build();
-        } else {
-            return commandsFactory.statementInfo().iif(toIfInfo(statement.iif(), commandsFactory)).build();
-        }
-    }
-
-    /**
-     * Generate network message from {@link If} statement.
-     *
-     * @param iif If statement.
-     * @param commandsFactory Commands factory.
-     * @return Network message.
-     */
-    public static IfInfo toIfInfo(If iif, MetaStorageCommandsFactory commandsFactory) {
-        return commandsFactory.ifInfo()
-                .cond(toConditionInfo(iif.condition(), commandsFactory))
-                .andThen(toIfBranchInfo(iif.andThen(), commandsFactory))
-                .orElse(toIfBranchInfo(iif.orElse(), commandsFactory))
-                .build();
-    }
-
-    private static ConditionInfo toConditionInfo(Condition condition, MetaStorageCommandsFactory commandsFactory) {
-        if (condition instanceof SimpleCondition) {
-            var simpleCondition = (SimpleCondition) condition;
-
-            SimpleConditionInfoBuilder cnd = commandsFactory.simpleConditionInfo()
-                    .key(simpleCondition.key())
-                    .conditionType(simpleCondition.type().ordinal());
-
-            if (simpleCondition instanceof SimpleCondition.RevisionCondition) {
-                cnd.revision(((RevisionCondition) simpleCondition).revision());
-            } else if (simpleCondition instanceof SimpleCondition.ValueCondition) {
-                cnd.value(((ValueCondition) simpleCondition).value());
-            }
-
-            return cnd.build();
-        } else if (condition instanceof CompoundCondition) {
-            CompoundCondition cond = (CompoundCondition) condition;
-
-            return commandsFactory.compoundConditionInfo()
-                    .leftConditionInfo(toConditionInfo(cond.leftCondition(), commandsFactory))
-                    .rightConditionInfo(toConditionInfo(cond.rightCondition(), commandsFactory))
-                    .conditionType(cond.compoundConditionType().ordinal())
-                    .build();
-        } else {
-            throw new IllegalArgumentException("Unknown condition type: " + condition.getClass().getSimpleName());
-        }
-    }
-
     private static Map<ByteArray, Entry> multipleEntryResult(Object obj) {
         MultipleEntryResponse resp = (MultipleEntryResponse) obj;
 
diff --git a/modules/metastorage/src/main/java/org/apache/ignite/internal/metastorage/server/raft/MetaStorageWriteHandler.java b/modules/metastorage/src/main/java/org/apache/ignite/internal/metastorage/server/raft/MetaStorageWriteHandler.java
index fbcebdbdc3..14db5071c3 100644
--- a/modules/metastorage/src/main/java/org/apache/ignite/internal/metastorage/server/raft/MetaStorageWriteHandler.java
+++ b/modules/metastorage/src/main/java/org/apache/ignite/internal/metastorage/server/raft/MetaStorageWriteHandler.java
@@ -26,7 +26,6 @@ import org.apache.ignite.internal.metastorage.command.GetAndPutCommand;
 import org.apache.ignite.internal.metastorage.command.GetAndRemoveAllCommand;
 import org.apache.ignite.internal.metastorage.command.GetAndRemoveCommand;
 import org.apache.ignite.internal.metastorage.command.InvokeCommand;
-import org.apache.ignite.internal.metastorage.command.MetaStorageCommandsFactory;
 import org.apache.ignite.internal.metastorage.command.MultiInvokeCommand;
 import org.apache.ignite.internal.metastorage.command.MultipleEntryResponse;
 import org.apache.ignite.internal.metastorage.command.PutAllCommand;
@@ -34,18 +33,12 @@ import org.apache.ignite.internal.metastorage.command.PutCommand;
 import org.apache.ignite.internal.metastorage.command.RemoveAllCommand;
 import org.apache.ignite.internal.metastorage.command.RemoveCommand;
 import org.apache.ignite.internal.metastorage.command.SingleEntryResponse;
-import org.apache.ignite.internal.metastorage.command.info.CompoundConditionInfo;
-import org.apache.ignite.internal.metastorage.command.info.ConditionInfo;
-import org.apache.ignite.internal.metastorage.command.info.IfInfo;
-import org.apache.ignite.internal.metastorage.command.info.OperationInfo;
-import org.apache.ignite.internal.metastorage.command.info.SimpleConditionInfo;
-import org.apache.ignite.internal.metastorage.command.info.StatementInfo;
-import org.apache.ignite.internal.metastorage.command.info.UpdateInfo;
-import org.apache.ignite.internal.metastorage.dsl.CompoundConditionType;
+import org.apache.ignite.internal.metastorage.dsl.CompoundCondition;
 import org.apache.ignite.internal.metastorage.dsl.ConditionType;
-import org.apache.ignite.internal.metastorage.dsl.Operation;
-import org.apache.ignite.internal.metastorage.dsl.StatementResult;
-import org.apache.ignite.internal.metastorage.dsl.Update;
+import org.apache.ignite.internal.metastorage.dsl.Iif;
+import org.apache.ignite.internal.metastorage.dsl.SimpleCondition;
+import org.apache.ignite.internal.metastorage.dsl.Statement.IfStatement;
+import org.apache.ignite.internal.metastorage.dsl.Statement.UpdateStatement;
 import org.apache.ignite.internal.metastorage.server.AndCondition;
 import org.apache.ignite.internal.metastorage.server.Condition;
 import org.apache.ignite.internal.metastorage.server.ExistenceCondition;
@@ -63,8 +56,6 @@ import org.apache.ignite.internal.raft.service.CommandClosure;
  * Class containing some common logic for Meta Storage Raft group listeners.
  */
 class MetaStorageWriteHandler {
-    private final MetaStorageCommandsFactory commandsFactory = new MetaStorageCommandsFactory();
-
     private final KeyValueStorage storage;
 
     MetaStorageWriteHandler(KeyValueStorage storage) {
@@ -72,8 +63,8 @@ class MetaStorageWriteHandler {
     }
 
     /**
-     * Tries to process a {@link WriteCommand}, returning {@code true} if the command has been successfully processed or {@code false}
-     * if the command requires external processing.
+     * Tries to process a {@link WriteCommand}, returning {@code true} if the command has been successfully processed or {@code false} if
+     * the command requires external processing.
      */
     boolean handleWriteCommand(CommandClosure<WriteCommand> clo) {
         WriteCommand command = clo.command();
@@ -141,19 +132,11 @@ class MetaStorageWriteHandler {
         } else if (command instanceof InvokeCommand) {
             InvokeCommand cmd = (InvokeCommand) command;
 
-            boolean res = storage.invoke(
-                    toCondition(cmd.condition()),
-                    toOperations(cmd.success()),
-                    toOperations(cmd.failure())
-            );
-
-            clo.result(res);
+            clo.result(storage.invoke(toCondition(cmd.condition()), cmd.success(), cmd.failure()));
         } else if (command instanceof MultiInvokeCommand) {
             MultiInvokeCommand cmd = (MultiInvokeCommand) command;
 
-            StatementResult res = storage.invoke(toIf(cmd.iif()));
-
-            clo.result(commandsFactory.statementResultInfo().result(res.bytes()).build());
+            clo.result(storage.invoke(toIf(cmd.iif())));
         } else {
             return false;
         }
@@ -161,85 +144,109 @@ class MetaStorageWriteHandler {
         return true;
     }
 
-    private static If toIf(IfInfo iif) {
-        return new If(toCondition(iif.cond()), toConditionBranch(iif.andThen()), toConditionBranch(iif.orElse()));
-    }
-
-    private static Update toUpdate(UpdateInfo updateInfo) {
-        return new Update(toOperations(new ArrayList<>(updateInfo.operations())), new StatementResult(updateInfo.result().result()));
+    private static If toIf(Iif iif) {
+        return new If(toCondition(iif.condition()), toConditionBranch(iif.andThen()), toConditionBranch(iif.orElse()));
     }
 
-    private static Statement toConditionBranch(StatementInfo statementInfo) {
-        if (statementInfo.isTerminal()) {
-            return new Statement(toUpdate(statementInfo.update()));
+    private static Statement toConditionBranch(org.apache.ignite.internal.metastorage.dsl.Statement statement) {
+        if (statement instanceof IfStatement) {
+            return new Statement(toIf(((IfStatement) statement).iif()));
+        } else if (statement instanceof UpdateStatement) {
+            return new Statement(((UpdateStatement) statement).update());
         } else {
-            return new Statement(toIf(statementInfo.iif()));
+            throw new IllegalArgumentException("Unexpected statement type: " + statement);
         }
     }
 
-    private static Condition toCondition(ConditionInfo info) {
-        if (info instanceof SimpleConditionInfo) {
-            SimpleConditionInfo inf = (SimpleConditionInfo) info;
-            byte[] key = inf.key();
-
-            ConditionType type = inf.type();
-
-            if (type == ConditionType.KEY_EXISTS) {
-                return new ExistenceCondition(ExistenceCondition.Type.EXISTS, key);
-            } else if (type == ConditionType.KEY_NOT_EXISTS) {
-                return new ExistenceCondition(ExistenceCondition.Type.NOT_EXISTS, key);
-            } else if (type == ConditionType.TOMBSTONE) {
-                return new TombstoneCondition(key);
-            } else if (type == ConditionType.VAL_EQUAL) {
-                return new ValueCondition(ValueCondition.Type.EQUAL, key, inf.value());
-            } else if (type == ConditionType.VAL_NOT_EQUAL) {
-                return new ValueCondition(ValueCondition.Type.NOT_EQUAL, key, inf.value());
-            } else if (type == ConditionType.VAL_GREATER) {
-                return new ValueCondition(ValueCondition.Type.GREATER, key, inf.value());
-            } else if (type == ConditionType.VAL_GREATER_OR_EQUAL) {
-                return new ValueCondition(ValueCondition.Type.GREATER_OR_EQUAL, key, inf.value());
-            } else if (type == ConditionType.VAL_LESS) {
-                return new ValueCondition(ValueCondition.Type.LESS, key, inf.value());
-            } else if (type == ConditionType.VAL_LESS_OR_EQUAL) {
-                return new ValueCondition(ValueCondition.Type.LESS_OR_EQUAL, key, inf.value());
-            } else if (type == ConditionType.REV_EQUAL) {
-                return new RevisionCondition(RevisionCondition.Type.EQUAL, key, inf.revision());
-            } else if (type == ConditionType.REV_NOT_EQUAL) {
-                return new RevisionCondition(RevisionCondition.Type.NOT_EQUAL, key, inf.revision());
-            } else if (type == ConditionType.REV_GREATER) {
-                return new RevisionCondition(RevisionCondition.Type.GREATER, key, inf.revision());
-            } else if (type == ConditionType.REV_GREATER_OR_EQUAL) {
-                return new RevisionCondition(RevisionCondition.Type.GREATER_OR_EQUAL, key, inf.revision());
-            } else if (type == ConditionType.REV_LESS) {
-                return new RevisionCondition(RevisionCondition.Type.LESS, key, inf.revision());
-            } else if (type == ConditionType.REV_LESS_OR_EQUAL) {
-                return new RevisionCondition(RevisionCondition.Type.LESS_OR_EQUAL, key, inf.revision());
-            } else {
-                throw new IllegalArgumentException("Unknown condition type: " + type);
+    private static Condition toCondition(org.apache.ignite.internal.metastorage.dsl.Condition condition) {
+        if (condition instanceof SimpleCondition.ValueCondition) {
+            var valueCondition = (SimpleCondition.ValueCondition) condition;
+
+            return new ValueCondition(
+                    toValueConditionType(valueCondition.type()),
+                    valueCondition.key(),
+                    valueCondition.value()
+            );
+        } else if (condition instanceof SimpleCondition.RevisionCondition) {
+            var revisionCondition = (SimpleCondition.RevisionCondition) condition;
+
+            return new RevisionCondition(
+                    toRevisionConditionType(revisionCondition.type()),
+                    revisionCondition.key(),
+                    revisionCondition.revision()
+            );
+        } else if (condition instanceof SimpleCondition) {
+            var simpleCondition = (SimpleCondition) condition;
+
+            switch (simpleCondition.type()) {
+                case KEY_EXISTS:
+                    return new ExistenceCondition(ExistenceCondition.Type.EXISTS, simpleCondition.key());
+
+                case KEY_NOT_EXISTS:
+                    return new ExistenceCondition(ExistenceCondition.Type.NOT_EXISTS, simpleCondition.key());
+
+                case TOMBSTONE:
+                    return new TombstoneCondition(simpleCondition.key());
+
+                default:
+                    throw new IllegalArgumentException("Unexpected simple condition type " + simpleCondition.type());
             }
-        } else if (info instanceof CompoundConditionInfo) {
-            CompoundConditionInfo inf = (CompoundConditionInfo) info;
+        } else if (condition instanceof CompoundCondition) {
+            CompoundCondition compoundCondition = (CompoundCondition) condition;
+
+            Condition leftCondition = toCondition(compoundCondition.leftCondition());
+            Condition rightCondition = toCondition(compoundCondition.rightCondition());
 
-            if (inf.type() == CompoundConditionType.AND) {
-                return new AndCondition(toCondition(inf.leftConditionInfo()), toCondition(inf.rightConditionInfo()));
+            switch (compoundCondition.type()) {
+                case AND:
+                    return new AndCondition(leftCondition, rightCondition);
 
-            } else if (inf.type() == CompoundConditionType.OR) {
-                return new OrCondition(toCondition(inf.leftConditionInfo()), toCondition(inf.rightConditionInfo()));
-            } else {
-                throw new IllegalArgumentException("Unknown compound condition " + inf.type());
+                case OR:
+                    return new OrCondition(leftCondition, rightCondition);
+
+                default:
+                    throw new IllegalArgumentException("Unexpected compound condition type " + compoundCondition.type());
             }
         } else {
-            throw new IllegalArgumentException("Unknown condition info type " + info);
+            throw new IllegalArgumentException("Unknown condition " + condition);
         }
     }
 
-    private static List<Operation> toOperations(List<OperationInfo> infos) {
-        List<Operation> ops = new ArrayList<>(infos.size());
-
-        for (OperationInfo info : infos) {
-            ops.add(new Operation(info.type(), info.key(), info.value()));
+    private static ValueCondition.Type toValueConditionType(ConditionType type) {
+        switch (type) {
+            case VAL_EQUAL:
+                return ValueCondition.Type.EQUAL;
+            case VAL_NOT_EQUAL:
+                return ValueCondition.Type.NOT_EQUAL;
+            case VAL_GREATER:
+                return ValueCondition.Type.GREATER;
+            case VAL_GREATER_OR_EQUAL:
+                return ValueCondition.Type.GREATER_OR_EQUAL;
+            case VAL_LESS:
+                return ValueCondition.Type.LESS;
+            case VAL_LESS_OR_EQUAL:
+                return ValueCondition.Type.LESS_OR_EQUAL;
+            default:
+                throw new IllegalArgumentException("Unexpected value condition type " + type);
         }
+    }
 
-        return ops;
+    private static RevisionCondition.Type toRevisionConditionType(ConditionType type) {
+        switch (type) {
+            case REV_EQUAL:
+                return RevisionCondition.Type.EQUAL;
+            case REV_NOT_EQUAL:
+                return RevisionCondition.Type.NOT_EQUAL;
+            case REV_GREATER:
+                return RevisionCondition.Type.GREATER;
+            case REV_GREATER_OR_EQUAL:
+                return RevisionCondition.Type.GREATER_OR_EQUAL;
+            case REV_LESS:
+                return RevisionCondition.Type.LESS;
+            case REV_LESS_OR_EQUAL:
+                return RevisionCondition.Type.LESS_OR_EQUAL;
+            default:
+                throw new IllegalArgumentException("Unexpected revision condition type " + type);
+        }
     }
 }
diff --git a/modules/metastorage/src/test/java/org/apache/ignite/internal/metastorage/server/AbstractKeyValueStorageTest.java b/modules/metastorage/src/test/java/org/apache/ignite/internal/metastorage/server/AbstractKeyValueStorageTest.java
index 8e06d32827..f767f800a7 100644
--- a/modules/metastorage/src/test/java/org/apache/ignite/internal/metastorage/server/AbstractKeyValueStorageTest.java
+++ b/modules/metastorage/src/test/java/org/apache/ignite/internal/metastorage/server/AbstractKeyValueStorageTest.java
@@ -19,6 +19,9 @@ package org.apache.ignite.internal.metastorage.server;
 
 import static java.nio.charset.StandardCharsets.UTF_8;
 import static java.util.function.Function.identity;
+import static org.apache.ignite.internal.metastorage.dsl.Operations.ops;
+import static org.apache.ignite.internal.metastorage.dsl.Operations.put;
+import static org.apache.ignite.internal.metastorage.dsl.Operations.remove;
 import static org.apache.ignite.internal.testframework.matchers.CompletableFutureMatcher.willBe;
 import static org.apache.ignite.internal.testframework.matchers.CompletableFutureMatcher.willCompleteSuccessfully;
 import static org.hamcrest.MatcherAssert.assertThat;
@@ -37,7 +40,6 @@ import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.timeout;
 import static org.mockito.Mockito.verify;
 
-import java.nio.ByteBuffer;
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
@@ -51,10 +53,8 @@ import org.apache.ignite.internal.metastorage.Entry;
 import org.apache.ignite.internal.metastorage.EntryEvent;
 import org.apache.ignite.internal.metastorage.WatchEvent;
 import org.apache.ignite.internal.metastorage.WatchListener;
-import org.apache.ignite.internal.metastorage.dsl.Operation;
-import org.apache.ignite.internal.metastorage.dsl.OperationType;
+import org.apache.ignite.internal.metastorage.dsl.Operations;
 import org.apache.ignite.internal.metastorage.dsl.StatementResult;
-import org.apache.ignite.internal.metastorage.dsl.Update;
 import org.apache.ignite.internal.metastorage.server.ValueCondition.Type;
 import org.apache.ignite.internal.util.Cursor;
 import org.apache.ignite.lang.ByteArray;
@@ -93,7 +93,7 @@ public abstract class AbstractKeyValueStorageTest {
     abstract KeyValueStorage storage();
 
     @Test
-    public void put() {
+    public void testPut() {
         byte[] key = key(1);
         byte[] val = keyValue(1, 1);
 
@@ -615,7 +615,7 @@ public abstract class AbstractKeyValueStorageTest {
     }
 
     @Test
-    public void remove() {
+    public void testRemove() {
         byte[] key = key(1);
         byte[] val = keyValue(1, 1);
 
@@ -1099,8 +1099,8 @@ public abstract class AbstractKeyValueStorageTest {
 
         boolean branch = storage.invoke(
                 new RevisionCondition(RevisionCondition.Type.EQUAL, key1, 1),
-                List.of(Operation.put(key1, val12), Operation.put(key2, val2)),
-                List.of(Operation.put(key3, val3))
+                List.of(put(new ByteArray(key1), val12), put(new ByteArray(key2), val2)),
+                List.of(put(new ByteArray(key3), val3))
         );
 
         // "Success" branch is applied.
@@ -1152,8 +1152,8 @@ public abstract class AbstractKeyValueStorageTest {
 
         boolean branch = storage.invoke(
                 new RevisionCondition(RevisionCondition.Type.EQUAL, key1, 2),
-                List.of(Operation.put(key3, val3)),
-                List.of(Operation.put(key1, val12), Operation.put(key2, val2))
+                List.of(put(new ByteArray(key3), val3)),
+                List.of(put(new ByteArray(key1), val12), put(new ByteArray(key2), val2))
         );
 
         // "Failure" branch is applied.
@@ -1205,8 +1205,8 @@ public abstract class AbstractKeyValueStorageTest {
 
         boolean branch = storage.invoke(
                 new ExistenceCondition(ExistenceCondition.Type.EXISTS, key1),
-                List.of(Operation.put(key1, val12), Operation.put(key2, val2)),
-                List.of(Operation.put(key3, val3))
+                List.of(put(new ByteArray(key1), val12), put(new ByteArray(key2), val2)),
+                List.of(put(new ByteArray(key3), val3))
         );
 
         // "Success" branch is applied.
@@ -1258,8 +1258,8 @@ public abstract class AbstractKeyValueStorageTest {
 
         boolean branch = storage.invoke(
                 new ExistenceCondition(ExistenceCondition.Type.EXISTS, key3),
-                List.of(Operation.put(key3, val3)),
-                List.of(Operation.put(key1, val12), Operation.put(key2, val2))
+                List.of(put(new ByteArray(key3), val3)),
+                List.of(put(new ByteArray(key1), val12), put(new ByteArray(key2), val2))
         );
 
         // "Failure" branch is applied.
@@ -1311,8 +1311,8 @@ public abstract class AbstractKeyValueStorageTest {
 
         boolean branch = storage.invoke(
                 new ExistenceCondition(ExistenceCondition.Type.NOT_EXISTS, key2),
-                List.of(Operation.put(key1, val12), Operation.put(key2, val2)),
-                List.of(Operation.put(key3, val3))
+                List.of(put(new ByteArray(key1), val12), put(new ByteArray(key2), val2)),
+                List.of(put(new ByteArray(key3), val3))
         );
 
         // "Success" branch is applied.
@@ -1364,10 +1364,10 @@ public abstract class AbstractKeyValueStorageTest {
 
         boolean branch = storage.invoke(
                 new ExistenceCondition(ExistenceCondition.Type.NOT_EXISTS, key1),
-                List.of(Operation.put(key3, val3)),
+                List.of(put(new ByteArray(key3), val3)),
                 List.of(
-                        Operation.put(key1, val12),
-                        Operation.put(key2, val2)
+                        put(new ByteArray(key1), val12),
+                        put(new ByteArray(key2), val2)
                 )
         );
 
@@ -1420,8 +1420,8 @@ public abstract class AbstractKeyValueStorageTest {
 
         boolean branch = storage.invoke(
                 new TombstoneCondition(key1),
-                List.of(Operation.put(key2, val2)),
-                List.of(Operation.put(key3, val3))
+                List.of(put(new ByteArray(key2), val2)),
+                List.of(put(new ByteArray(key3), val3))
         );
 
         // "Success" branch is applied.
@@ -1472,8 +1472,8 @@ public abstract class AbstractKeyValueStorageTest {
 
         boolean branch = storage.invoke(
                 new TombstoneCondition(key1),
-                List.of(Operation.put(key2, val2)),
-                List.of(Operation.put(key3, val3))
+                List.of(put(new ByteArray(key2), val2)),
+                List.of(put(new ByteArray(key3), val3))
         );
 
         // "Failure" branch is applied.
@@ -1526,10 +1526,10 @@ public abstract class AbstractKeyValueStorageTest {
         boolean branch = storage.invoke(
                 new ValueCondition(ValueCondition.Type.EQUAL, key1, val11),
                 List.of(
-                        Operation.put(key1, val12),
-                        Operation.put(key2, val2)
+                        put(new ByteArray(key1), val12),
+                        put(new ByteArray(key2), val2)
                 ),
-                List.of(Operation.put(key3, val3))
+                List.of(put(new ByteArray(key3), val3))
         );
 
         // "Success" branch is applied.
@@ -1581,10 +1581,10 @@ public abstract class AbstractKeyValueStorageTest {
 
         boolean branch = storage.invoke(
                 new ValueCondition(ValueCondition.Type.EQUAL, key1, val12),
-                List.of(Operation.put(key3, val3)),
+                List.of(put(new ByteArray(key3), val3)),
                 List.of(
-                        Operation.put(key1, val12),
-                        Operation.put(key2, val2)
+                        put(new ByteArray(key1), val12),
+                        put(new ByteArray(key2), val2)
                 )
         );
 
@@ -1637,8 +1637,8 @@ public abstract class AbstractKeyValueStorageTest {
         // No-op.
         boolean branch = storage.invoke(
                 new ValueCondition(ValueCondition.Type.EQUAL, key1, val1),
-                List.of(new Operation(OperationType.NO_OP, null, null)),
-                List.of(new Operation(OperationType.NO_OP, null, null))
+                List.of(Operations.noop()),
+                List.of(Operations.noop())
         );
 
         assertTrue(branch);
@@ -1651,10 +1651,10 @@ public abstract class AbstractKeyValueStorageTest {
         branch = storage.invoke(
                 new ValueCondition(ValueCondition.Type.EQUAL, key1, val1),
                 List.of(
-                        Operation.put(key2, val2),
-                        Operation.put(key3, val3)
+                        put(new ByteArray(key2), val2),
+                        put(new ByteArray(key3), val3)
                 ),
-                List.of(new Operation(OperationType.NO_OP, null, null))
+                List.of(Operations.noop())
         );
 
         assertTrue(branch);
@@ -1685,10 +1685,10 @@ public abstract class AbstractKeyValueStorageTest {
         branch = storage.invoke(
                 new ValueCondition(ValueCondition.Type.EQUAL, key1, val1),
                 List.of(
-                        new Operation(OperationType.REMOVE, key2, null),
-                        new Operation(OperationType.REMOVE, key3, null)
+                        remove(new ByteArray(key2)),
+                        remove(new ByteArray(key3))
                 ),
-                List.of(new Operation(OperationType.NO_OP, null, null))
+                List.of(Operations.noop())
         );
 
         assertTrue(branch);
@@ -1762,22 +1762,16 @@ public abstract class AbstractKeyValueStorageTest {
 
         If iif = new If(
                 new OrCondition(new ValueCondition(Type.EQUAL, key1, val1), new ExistenceCondition(ExistenceCondition.Type.EXISTS, key2)),
-                new Statement(
-                        new If(
-                                new RevisionCondition(RevisionCondition.Type.EQUAL, key3, 3),
-                                new Statement(
-                                        new Update(List.of(Operation.put(key1, rval1)), new StatementResult(1))),
-                                new Statement(
-                                        new Update(
-                                                List.of(Operation.put(key1, rval1),
-                                                        new Operation(OperationType.REMOVE, key2, null)),
-                                                new StatementResult(2))))),
-                new Statement(new Update(List.of(Operation.put(key3, rval3)), new StatementResult(3)))
+                new Statement(new If(
+                        new RevisionCondition(RevisionCondition.Type.EQUAL, key3, 3),
+                        new Statement(ops(put(new ByteArray(key1), rval1)).yield(1)),
+                        new Statement(ops(put(new ByteArray(key1), rval1), remove(new ByteArray(key2))).yield(2)))),
+                new Statement(ops(put(new ByteArray(key3), rval3)).yield(3))
         );
 
         StatementResult branch = storage.invoke(iif);
 
-        assertEquals(1, ByteBuffer.wrap(branch.bytes()).getInt());
+        assertEquals(1, branch.getAsInt());
 
         assertEquals(4, storage.revision());
         assertEquals(4, storage.updateCounter());
@@ -1847,16 +1841,15 @@ public abstract class AbstractKeyValueStorageTest {
 
         If iif = new If(
                 new OrCondition(new ValueCondition(Type.EQUAL, key1, val1), new ExistenceCondition(ExistenceCondition.Type.EXISTS, key2)),
-                new Statement(new If(new RevisionCondition(RevisionCondition.Type.EQUAL, key3, 3),
-                        new Statement(new Update(List.of(Operation.put(key1, rval1)), new StatementResult(1))),
-                        new Statement(new Update(
-                                List.of(Operation.put(key1, rval1), new Operation(OperationType.REMOVE, key2, null)),
-                                new StatementResult(2))))),
-                new Statement(new Update(List.of(Operation.put(key3, rval3)), new StatementResult(3))));
+                new Statement(new If(
+                        new RevisionCondition(RevisionCondition.Type.EQUAL, key3, 3),
+                        new Statement(ops(put(new ByteArray(key1), rval1)).yield()),
+                        new Statement(ops(put(new ByteArray(key1), rval1), remove(new ByteArray(key2))).yield(2)))),
+                new Statement(ops(put(new ByteArray(key3), rval3)).yield(3)));
 
         StatementResult branch = storage.invoke(iif);
 
-        assertEquals(2, ByteBuffer.wrap(branch.bytes()).getInt());
+        assertEquals(2, branch.getAsInt());
 
         assertEquals(5, storage.revision());
         assertEquals(6, storage.updateCounter());
@@ -1917,16 +1910,15 @@ public abstract class AbstractKeyValueStorageTest {
 
         If iif = new If(
                 new OrCondition(new ValueCondition(Type.EQUAL, key1, val1), new ExistenceCondition(ExistenceCondition.Type.EXISTS, key2)),
-                new Statement(new If(new RevisionCondition(RevisionCondition.Type.EQUAL, key3, 3),
-                        new Statement(new Update(List.of(Operation.put(key1, rval1)), new StatementResult(1))),
-                        new Statement(new Update(
-                                List.of(Operation.put(key1, rval1), new Operation(OperationType.REMOVE, key2, null)),
-                                new StatementResult(2))))),
-                new Statement(new Update(List.of(Operation.put(key3, rval3)), new StatementResult(3))));
+                new Statement(new If(
+                        new RevisionCondition(RevisionCondition.Type.EQUAL, key3, 3),
+                        new Statement(ops(put(new ByteArray(key1), rval1)).yield(1)),
+                        new Statement(ops(put(new ByteArray(key1), rval1), remove(new ByteArray(key2))).yield(2)))),
+                new Statement(ops(put(new ByteArray(key3), rval3)).yield(3)));
 
         StatementResult branch = storage.invoke(iif);
 
-        assertEquals(3, ByteBuffer.wrap(branch.bytes()).getInt());
+        assertEquals(3, branch.getAsInt());
 
         assertEquals(3, storage.revision());
         assertEquals(3, storage.updateCounter());
diff --git a/modules/network-api/build.gradle b/modules/network-api/build.gradle
index 832c857033..e3888a02ed 100644
--- a/modules/network-api/build.gradle
+++ b/modules/network-api/build.gradle
@@ -21,10 +21,11 @@ apply from: "$rootDir/buildscripts/java-junit5.gradle"
 
 dependencies {
     api project(':ignite-api')
+    api libs.fastutil.core
+
     implementation project(':ignite-configuration-api')
     implementation project(':ignite-core')
     implementation libs.jetbrains.annotations
-    implementation libs.fastutil.core
 
     testImplementation libs.hamcrest.core
     testImplementation libs.mockito.core
diff --git a/modules/network/src/main/java/org/apache/ignite/internal/network/netty/OutboundEncoder.java b/modules/network/src/main/java/org/apache/ignite/internal/network/netty/OutboundEncoder.java
index 31d2859462..7cf40f6662 100644
--- a/modules/network/src/main/java/org/apache/ignite/internal/network/netty/OutboundEncoder.java
+++ b/modules/network/src/main/java/org/apache/ignite/internal/network/netty/OutboundEncoder.java
@@ -96,14 +96,12 @@ public class OutboundEncoder extends MessageToMessageEncoder<OutNetworkObject> {
             this.serializationService = serializationService;
             this.msg = outObject.networkMessage();
 
-            if (!outObject.descriptors().isEmpty()) {
-                List<ClassDescriptorMessage> descriptors = outObject.descriptors();
+            List<ClassDescriptorMessage> outDescriptors = outObject.descriptors().stream()
+                    .filter(classDescriptorMessage -> !serializationService.isDescriptorSent(classDescriptorMessage.descriptorId()))
+                    .collect(Collectors.toList());
 
-                descriptors = descriptors.stream()
-                        .filter(classDescriptorMessage -> !serializationService.isDescriptorSent(classDescriptorMessage.descriptorId()))
-                        .collect(Collectors.toList());
-
-                this.descriptors = MSG_FACTORY.classDescriptorListMessage().messages(descriptors).build();
+            if (!outDescriptors.isEmpty()) {
+                this.descriptors = MSG_FACTORY.classDescriptorListMessage().messages(outDescriptors).build();
                 short groupType = this.descriptors.groupType();
                 short messageType = this.descriptors.messageType();
                 descriptorSerializer = serializationService.createMessageSerializer(groupType, messageType);
diff --git a/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/raft/RebalanceRaftGroupEventsListener.java b/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/raft/RebalanceRaftGroupEventsListener.java
index 4ac3dd60e6..e134a3126b 100644
--- a/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/raft/RebalanceRaftGroupEventsListener.java
+++ b/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/raft/RebalanceRaftGroupEventsListener.java
@@ -17,12 +17,13 @@
 
 package org.apache.ignite.internal.table.distributed.raft;
 
-import static org.apache.ignite.internal.metastorage.dsl.CompoundCondition.and;
+import static org.apache.ignite.internal.metastorage.dsl.Conditions.and;
 import static org.apache.ignite.internal.metastorage.dsl.Conditions.notExists;
 import static org.apache.ignite.internal.metastorage.dsl.Conditions.revision;
 import static org.apache.ignite.internal.metastorage.dsl.Operations.ops;
 import static org.apache.ignite.internal.metastorage.dsl.Operations.put;
 import static org.apache.ignite.internal.metastorage.dsl.Operations.remove;
+import static org.apache.ignite.internal.metastorage.dsl.Statements.iif;
 import static org.apache.ignite.internal.utils.RebalanceUtil.intersect;
 import static org.apache.ignite.internal.utils.RebalanceUtil.pendingPartAssignmentsKey;
 import static org.apache.ignite.internal.utils.RebalanceUtil.plannedPartAssignmentsKey;
@@ -50,7 +51,6 @@ import org.apache.ignite.internal.logger.Loggers;
 import org.apache.ignite.internal.metastorage.Entry;
 import org.apache.ignite.internal.metastorage.MetaStorageManager;
 import org.apache.ignite.internal.metastorage.dsl.Condition;
-import org.apache.ignite.internal.metastorage.dsl.If;
 import org.apache.ignite.internal.metastorage.dsl.SimpleCondition;
 import org.apache.ignite.internal.metastorage.dsl.Update;
 import org.apache.ignite.internal.raft.PeersAndLearners;
@@ -434,7 +434,7 @@ public class RebalanceRaftGroupEventsListener implements RaftGroupEventsListener
             }
 
             // TODO: https://issues.apache.org/jira/browse/IGNITE-17592 Remove synchronous wait
-            int res = metaStorageMgr.invoke(If.iif(retryPreconditions, successCase, failCase)).get().getAsInt();
+            int res = metaStorageMgr.invoke(iif(retryPreconditions, successCase, failCase)).get().getAsInt();
 
             if (res < 0) {
                 switch (res) {
diff --git a/modules/table/src/main/java/org/apache/ignite/internal/utils/RebalanceUtil.java b/modules/table/src/main/java/org/apache/ignite/internal/utils/RebalanceUtil.java
index bbf84b28e6..0b0b5f36c4 100644
--- a/modules/table/src/main/java/org/apache/ignite/internal/utils/RebalanceUtil.java
+++ b/modules/table/src/main/java/org/apache/ignite/internal/utils/RebalanceUtil.java
@@ -17,15 +17,15 @@
 
 package org.apache.ignite.internal.utils;
 
-import static org.apache.ignite.internal.metastorage.dsl.CompoundCondition.and;
-import static org.apache.ignite.internal.metastorage.dsl.CompoundCondition.or;
+import static org.apache.ignite.internal.metastorage.dsl.Conditions.and;
 import static org.apache.ignite.internal.metastorage.dsl.Conditions.notExists;
+import static org.apache.ignite.internal.metastorage.dsl.Conditions.or;
 import static org.apache.ignite.internal.metastorage.dsl.Conditions.revision;
 import static org.apache.ignite.internal.metastorage.dsl.Conditions.value;
-import static org.apache.ignite.internal.metastorage.dsl.If.iif;
 import static org.apache.ignite.internal.metastorage.dsl.Operations.ops;
 import static org.apache.ignite.internal.metastorage.dsl.Operations.put;
 import static org.apache.ignite.internal.metastorage.dsl.Operations.remove;
+import static org.apache.ignite.internal.metastorage.dsl.Statements.iif;
 
 import java.nio.charset.StandardCharsets;
 import java.util.Collection;
@@ -41,7 +41,7 @@ import org.apache.ignite.internal.logger.Loggers;
 import org.apache.ignite.internal.metastorage.Entry;
 import org.apache.ignite.internal.metastorage.MetaStorageManager;
 import org.apache.ignite.internal.metastorage.WatchEvent;
-import org.apache.ignite.internal.metastorage.dsl.If;
+import org.apache.ignite.internal.metastorage.dsl.Iif;
 import org.apache.ignite.internal.metastorage.dsl.Operations;
 import org.apache.ignite.internal.table.distributed.replicator.TablePartitionId;
 import org.apache.ignite.internal.util.ByteUtils;
@@ -381,7 +381,7 @@ public class RebalanceUtil {
         //     put(changeTriggerKey, revision)
         // }
 
-        If resultingOperation = iif(
+        Iif resultingOperation = iif(
                 and(
                         or(notExists(changeTriggerKey), value(changeTriggerKey).lt(rev)),
                         and(notExists(pendingKey), (notExists(stablePartAssignmentsKey(partId))))