You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by ib...@apache.org on 2022/10/18 12:14:20 UTC

[ignite-3] branch main updated: IGNITE-17888 Meta-storage commands reimplemented as Transferable classes (#1223)

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

ibessonov 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 debe65d3f6 IGNITE-17888 Meta-storage commands reimplemented as Transferable classes (#1223)
debe65d3f6 is described below

commit debe65d3f62e87ec4bc20ba06a8af95775ba9909
Author: Ivan Bessonov <be...@gmail.com>
AuthorDate: Tue Oct 18 15:14:14 2022 +0300

    IGNITE-17888 Meta-storage commands reimplemented as Transferable classes (#1223)
---
 modules/metastorage-client/build.gradle            |   2 +-
 .../internal/metastorage/client/CursorImpl.java    |  21 ++-
 .../metastorage/client/MetaStorageServiceImpl.java | 204 ++++++++++++++-------
 modules/metastorage-common/build.gradle            |   6 +
 modules/metastorage-common/pom.xml                 |  37 ++++
 .../common/{command => }/OperationInfo.java        |  54 ++----
 .../internal/metastorage/common/StatementInfo.java |  56 ++----
 .../metastorage/common/StatementResultInfo.java    |  23 +--
 .../internal/metastorage/common/UpdateInfo.java    |  32 +---
 .../common/command/CompoundConditionInfo.java      |  47 ++---
 .../metastorage/common/command/ConditionInfo.java  |   3 +-
 .../metastorage/common/command/GetAllCommand.java  |  59 ++----
 .../common/command/GetAndPutAllCommand.java        |  53 +++---
 .../common/command/GetAndPutCommand.java           |  34 +---
 .../common/command/GetAndRemoveAllCommand.java     |  29 ++-
 .../common/command/GetAndRemoveCommand.java        |  24 +--
 .../metastorage/common/command/GetCommand.java     |  47 +----
 .../metastorage/common/command/IfInfo.java         |  40 +---
 .../metastorage/common/command/InvokeCommand.java  |  40 +---
 .../command/MetastorageCommandsMessageGroup.java   | 114 ++++++++++++
 .../common/command/MultiInvokeCommand.java         |  21 +--
 .../metastorage/common/command/PutAllCommand.java  |  47 +++--
 .../metastorage/common/command/PutCommand.java     |  34 +---
 .../metastorage/common/command/RangeCommand.java   | 192 ++-----------------
 .../common/command/RemoveAllCommand.java           |  29 ++-
 .../metastorage/common/command/RemoveCommand.java  |  24 +--
 .../common/command/SimpleConditionInfo.java        |  50 ++---
 .../common/command/WatchExactKeysCommand.java      |  89 ++++-----
 .../common/command/WatchRangeKeysCommand.java      |  86 +--------
 .../common/command/cursor/CursorCloseCommand.java  |  24 +--
 .../command/cursor/CursorHasNextCommand.java       |  24 +--
 .../common/command/cursor/CursorNextCommand.java   |  24 +--
 .../common/command/cursor/CursorsCloseCommand.java |  24 +--
 .../metastorage/common/ConditionTypeTest.java      |  60 ++++++
 .../metastorage/common/OperationTypeTest.java}     |  21 ++-
 .../common/command/CompoundConditionTypeTest.java} |  30 +--
 modules/metastorage-server/build.gradle            |   1 +
 .../server/raft/MetaStorageListener.java           |  22 ++-
 38 files changed, 708 insertions(+), 1019 deletions(-)

diff --git a/modules/metastorage-client/build.gradle b/modules/metastorage-client/build.gradle
index 32e9aad890..f15c2eed62 100644
--- a/modules/metastorage-client/build.gradle
+++ b/modules/metastorage-client/build.gradle
@@ -23,13 +23,13 @@ apply from: "$rootDir/buildscripts/java-integration-test.gradle"
 dependencies {
     implementation project(':ignite-raft-client')
     implementation project(':ignite-core')
+    implementation project(':ignite-network-api')
     implementation project(':ignite-metastorage-common')
     implementation libs.jetbrains.annotations
     implementation libs.fastutil.core
 
     testImplementation project(':ignite-raft')
     testImplementation project(':ignite-network')
-    testImplementation project(':ignite-network')
     testImplementation project(':ignite-metastorage-server')
     testImplementation project(':ignite-configuration')
     testImplementation project(':ignite-core')
diff --git a/modules/metastorage-client/src/main/java/org/apache/ignite/internal/metastorage/client/CursorImpl.java b/modules/metastorage-client/src/main/java/org/apache/ignite/internal/metastorage/client/CursorImpl.java
index 11ea05cf4b..97d06b91dd 100644
--- a/modules/metastorage-client/src/main/java/org/apache/ignite/internal/metastorage/client/CursorImpl.java
+++ b/modules/metastorage-client/src/main/java/org/apache/ignite/internal/metastorage/client/CursorImpl.java
@@ -29,8 +29,8 @@ import java.util.function.Function;
 import org.apache.ignite.internal.logger.IgniteLogger;
 import org.apache.ignite.internal.logger.Loggers;
 import org.apache.ignite.internal.metastorage.common.MetaStorageException;
+import org.apache.ignite.internal.metastorage.common.command.MetaStorageCommandsFactory;
 import org.apache.ignite.internal.metastorage.common.command.cursor.CursorCloseCommand;
-import org.apache.ignite.internal.metastorage.common.command.cursor.CursorHasNextCommand;
 import org.apache.ignite.internal.metastorage.common.command.cursor.CursorNextCommand;
 import org.apache.ignite.internal.util.Cursor;
 import org.apache.ignite.lang.IgniteUuid;
@@ -47,6 +47,9 @@ public class CursorImpl<T> implements Cursor<T> {
     /** The logger. */
     private static final IgniteLogger LOG = Loggers.forClass(CursorImpl.class);
 
+    /** Commands factory. */
+    private final MetaStorageCommandsFactory commandsFactory;
+
     /** Future that runs meta storage service operation that provides cursor. */
     private final CompletableFuture<IgniteUuid> initOp;
 
@@ -58,16 +61,19 @@ public class CursorImpl<T> implements Cursor<T> {
     /**
      * Constructor.
      *
+     * @param commandsFactory Commands factory.
      * @param metaStorageRaftGrpSvc Meta storage raft group service.
      * @param initOp                Future that runs meta storage service operation that provides cursor.
      * @param fn                    Function transforming the result of {@link CursorNextCommand} to the type of {@link T},
      *                              or to the {@link Iterable} of type {@link T} if needed.
      */
     CursorImpl(
+            MetaStorageCommandsFactory commandsFactory,
             RaftGroupService metaStorageRaftGrpSvc,
             CompletableFuture<IgniteUuid> initOp,
             Function<Object, Object> fn
     ) {
+        this.commandsFactory = commandsFactory;
         this.metaStorageRaftGrpSvc = metaStorageRaftGrpSvc;
         this.initOp = initOp;
         this.it = new InnerIterator(fn);
@@ -77,8 +83,11 @@ public class CursorImpl<T> implements Cursor<T> {
     @Override
     public void close() {
         try {
-            initOp.thenCompose(
-                    cursorId -> metaStorageRaftGrpSvc.run(new CursorCloseCommand(cursorId))).get();
+            initOp.thenCompose(cursorId -> {
+                CursorCloseCommand cursorCloseCommand = commandsFactory.cursorCloseCommand().cursorId(cursorId).build();
+
+                return metaStorageRaftGrpSvc.run(cursorCloseCommand);
+            }).get();
 
             ((InnerIterator) it).close();
         } catch (InterruptedException | ExecutionException e) {
@@ -125,7 +134,8 @@ public class CursorImpl<T> implements Cursor<T> {
                     return true;
                 } else {
                     return initOp
-                            .thenCompose(cursorId -> metaStorageRaftGrpSvc.<Boolean>run(new CursorHasNextCommand(cursorId)))
+                            .thenCompose(cursorId ->
+                                    metaStorageRaftGrpSvc.<Boolean>run(commandsFactory.cursorHasNextCommand().cursorId(cursorId).build()))
                             .get();
                 }
             } catch (InterruptedException | ExecutionException e) {
@@ -147,7 +157,8 @@ public class CursorImpl<T> implements Cursor<T> {
                     return internalCacheIterator.next();
                 } else {
                     Object res = initOp
-                            .thenCompose(cursorId -> metaStorageRaftGrpSvc.run(new CursorNextCommand(cursorId)))
+                            .thenCompose(cursorId ->
+                                    metaStorageRaftGrpSvc.run(commandsFactory.cursorNextCommand().cursorId(cursorId).build()))
                             .get();
 
                     Object transformed = fn.apply(res);
diff --git a/modules/metastorage-client/src/main/java/org/apache/ignite/internal/metastorage/client/MetaStorageServiceImpl.java b/modules/metastorage-client/src/main/java/org/apache/ignite/internal/metastorage/client/MetaStorageServiceImpl.java
index 433823e9a7..57c743812c 100644
--- a/modules/metastorage-client/src/main/java/org/apache/ignite/internal/metastorage/client/MetaStorageServiceImpl.java
+++ b/modules/metastorage-client/src/main/java/org/apache/ignite/internal/metastorage/client/MetaStorageServiceImpl.java
@@ -18,6 +18,12 @@
 package org.apache.ignite.internal.metastorage.client;
 
 import static java.util.stream.Collectors.toList;
+import static org.apache.ignite.internal.metastorage.common.command.GetAllCommand.getAllCommand;
+import static org.apache.ignite.internal.metastorage.common.command.GetAndPutAllCommand.getAndPutAllCommand;
+import static org.apache.ignite.internal.metastorage.common.command.GetAndRemoveAllCommand.getAndRemoveAllCommand;
+import static org.apache.ignite.internal.metastorage.common.command.PutAllCommand.putAllCommand;
+import static org.apache.ignite.internal.metastorage.common.command.RemoveAllCommand.removeAllCommand;
+import static org.apache.ignite.internal.metastorage.common.command.WatchExactKeysCommand.watchExactKeysCommand;
 import static org.apache.ignite.lang.ErrorGroups.MetaStorage.WATCH_STOPPING_ERR;
 
 import java.util.ArrayList;
@@ -34,11 +40,12 @@ import java.util.concurrent.RejectedExecutionException;
 import org.apache.ignite.internal.logger.IgniteLogger;
 import org.apache.ignite.internal.logger.Loggers;
 import org.apache.ignite.internal.metastorage.common.MetaStorageException;
+import org.apache.ignite.internal.metastorage.common.OperationInfo;
+import org.apache.ignite.internal.metastorage.common.OperationInfoBuilder;
 import org.apache.ignite.internal.metastorage.common.OperationType;
 import org.apache.ignite.internal.metastorage.common.StatementInfo;
 import org.apache.ignite.internal.metastorage.common.StatementResultInfo;
 import org.apache.ignite.internal.metastorage.common.UpdateInfo;
-import org.apache.ignite.internal.metastorage.common.command.CompoundConditionInfo;
 import org.apache.ignite.internal.metastorage.common.command.ConditionInfo;
 import org.apache.ignite.internal.metastorage.common.command.GetAllCommand;
 import org.apache.ignite.internal.metastorage.common.command.GetAndPutAllCommand;
@@ -48,19 +55,16 @@ import org.apache.ignite.internal.metastorage.common.command.GetAndRemoveCommand
 import org.apache.ignite.internal.metastorage.common.command.GetCommand;
 import org.apache.ignite.internal.metastorage.common.command.IfInfo;
 import org.apache.ignite.internal.metastorage.common.command.InvokeCommand;
+import org.apache.ignite.internal.metastorage.common.command.MetaStorageCommandsFactory;
 import org.apache.ignite.internal.metastorage.common.command.MultiInvokeCommand;
 import org.apache.ignite.internal.metastorage.common.command.MultipleEntryResponse;
-import org.apache.ignite.internal.metastorage.common.command.OperationInfo;
 import org.apache.ignite.internal.metastorage.common.command.PutAllCommand;
 import org.apache.ignite.internal.metastorage.common.command.PutCommand;
 import org.apache.ignite.internal.metastorage.common.command.RangeCommand;
 import org.apache.ignite.internal.metastorage.common.command.RemoveAllCommand;
 import org.apache.ignite.internal.metastorage.common.command.RemoveCommand;
-import org.apache.ignite.internal.metastorage.common.command.SimpleConditionInfo;
+import org.apache.ignite.internal.metastorage.common.command.SimpleConditionInfoBuilder;
 import org.apache.ignite.internal.metastorage.common.command.SingleEntryResponse;
-import org.apache.ignite.internal.metastorage.common.command.WatchExactKeysCommand;
-import org.apache.ignite.internal.metastorage.common.command.WatchRangeKeysCommand;
-import org.apache.ignite.internal.metastorage.common.command.cursor.CursorsCloseCommand;
 import org.apache.ignite.internal.util.Cursor;
 import org.apache.ignite.lang.ByteArray;
 import org.apache.ignite.lang.IgniteInternalException;
@@ -81,6 +85,9 @@ public class MetaStorageServiceImpl implements MetaStorageService {
     /** IgniteUuid generator. */
     private static final IgniteUuidGenerator uuidGenerator = new IgniteUuidGenerator(UUID.randomUUID(), 0);
 
+    /** Commands factory. */
+    private final MetaStorageCommandsFactory commandsFactory = new MetaStorageCommandsFactory();
+
     /** Meta storage raft group service. */
     private final RaftGroupService metaStorageRaftGrpSvc;
 
@@ -111,77 +118,97 @@ public class MetaStorageServiceImpl implements MetaStorageService {
     /** {@inheritDoc} */
     @Override
     public @NotNull CompletableFuture<Entry> get(@NotNull ByteArray key) {
-        return metaStorageRaftGrpSvc.run(new GetCommand(key)).thenApply(MetaStorageServiceImpl::singleEntryResult);
+        GetCommand getCommand = commandsFactory.getCommand().key(key.bytes()).build();
+
+        return metaStorageRaftGrpSvc.run(getCommand).thenApply(MetaStorageServiceImpl::singleEntryResult);
     }
 
     /** {@inheritDoc} */
     @Override
     public @NotNull CompletableFuture<Entry> get(@NotNull ByteArray key, long revUpperBound) {
-        return metaStorageRaftGrpSvc.run(new GetCommand(key, revUpperBound))
-                .thenApply(MetaStorageServiceImpl::singleEntryResult);
+        GetCommand getCommand = commandsFactory.getCommand().key(key.bytes()).revision(revUpperBound).build();
+
+        return metaStorageRaftGrpSvc.run(getCommand).thenApply(MetaStorageServiceImpl::singleEntryResult);
     }
 
     /** {@inheritDoc} */
     @Override
     public @NotNull CompletableFuture<Map<ByteArray, Entry>> getAll(Set<ByteArray> keys) {
-        return metaStorageRaftGrpSvc.run(new GetAllCommand(keys))
-                .thenApply(MetaStorageServiceImpl::multipleEntryResult);
+        GetAllCommand getAllCommand = getAllCommand(commandsFactory, keys, 0);
+
+        return metaStorageRaftGrpSvc.run(getAllCommand).thenApply(MetaStorageServiceImpl::multipleEntryResult);
     }
 
     /** {@inheritDoc} */
     @Override
-    public @NotNull CompletableFuture<Map<ByteArray, Entry>> getAll(Set<ByteArray> keys, long revUpperBound) {
-        return metaStorageRaftGrpSvc.run(new GetAllCommand(keys, revUpperBound)).thenApply(MetaStorageServiceImpl::multipleEntryResult);
+    public CompletableFuture<Map<ByteArray, Entry>> getAll(Set<ByteArray> keys, long revUpperBound) {
+        GetAllCommand getAllCommand = getAllCommand(commandsFactory, keys, revUpperBound);
+
+        return metaStorageRaftGrpSvc.run(getAllCommand).thenApply(MetaStorageServiceImpl::multipleEntryResult);
     }
 
     /** {@inheritDoc} */
     @Override
-    public @NotNull CompletableFuture<Void> put(@NotNull ByteArray key, @NotNull byte[] value) {
-        return metaStorageRaftGrpSvc.run(new PutCommand(key, value));
+    public CompletableFuture<Void> put(ByteArray key, byte[] value) {
+        PutCommand putCommand = commandsFactory.putCommand().key(key.bytes()).value(value).build();
+
+        return metaStorageRaftGrpSvc.run(putCommand);
     }
 
     /** {@inheritDoc} */
     @Override
-    public @NotNull CompletableFuture<Entry> getAndPut(@NotNull ByteArray key, @NotNull byte[] value) {
-        return metaStorageRaftGrpSvc.run(new GetAndPutCommand(key, value))
-                .thenApply(MetaStorageServiceImpl::singleEntryResult);
+    public @NotNull CompletableFuture<Entry> getAndPut(ByteArray key, byte[] value) {
+        GetAndPutCommand getAndPutCommand = commandsFactory.getAndPutCommand().key(key.bytes()).value(value).build();
+
+        return metaStorageRaftGrpSvc.run(getAndPutCommand).thenApply(MetaStorageServiceImpl::singleEntryResult);
     }
 
     /** {@inheritDoc} */
     @Override
     public @NotNull CompletableFuture<Void> putAll(@NotNull Map<ByteArray, byte[]> vals) {
-        return metaStorageRaftGrpSvc.run(new PutAllCommand(vals));
+        PutAllCommand putAllCommand = putAllCommand(commandsFactory, vals);
+
+        return metaStorageRaftGrpSvc.run(putAllCommand);
     }
 
     /** {@inheritDoc} */
     @Override
     public @NotNull CompletableFuture<Map<ByteArray, Entry>> getAndPutAll(@NotNull Map<ByteArray, byte[]> vals) {
-        return metaStorageRaftGrpSvc.run(new GetAndPutAllCommand(vals)).thenApply(MetaStorageServiceImpl::multipleEntryResult);
+        GetAndPutAllCommand getAndPutAllCommand = getAndPutAllCommand(commandsFactory, vals);
+
+        return metaStorageRaftGrpSvc.run(getAndPutAllCommand).thenApply(MetaStorageServiceImpl::multipleEntryResult);
     }
 
     /** {@inheritDoc} */
     @Override
     public @NotNull CompletableFuture<Void> remove(@NotNull ByteArray key) {
-        return metaStorageRaftGrpSvc.run(new RemoveCommand(key));
+        RemoveCommand removeCommand = commandsFactory.removeCommand().key(key.bytes()).build();
+
+        return metaStorageRaftGrpSvc.run(removeCommand);
     }
 
     /** {@inheritDoc} */
     @Override
     public @NotNull CompletableFuture<Entry> getAndRemove(@NotNull ByteArray key) {
-        return metaStorageRaftGrpSvc.run(new GetAndRemoveCommand(key))
-                .thenApply(MetaStorageServiceImpl::singleEntryResult);
+        GetAndRemoveCommand getAndRemoveCommand = commandsFactory.getAndRemoveCommand().key(key.bytes()).build();
+
+        return metaStorageRaftGrpSvc.run(getAndRemoveCommand).thenApply(MetaStorageServiceImpl::singleEntryResult);
     }
 
     /** {@inheritDoc} */
     @Override
     public @NotNull CompletableFuture<Void> removeAll(@NotNull Set<ByteArray> keys) {
-        return metaStorageRaftGrpSvc.run(new RemoveAllCommand(keys));
+        RemoveAllCommand removeAllCommand = removeAllCommand(commandsFactory, keys);
+
+        return metaStorageRaftGrpSvc.run(removeAllCommand);
     }
 
     /** {@inheritDoc} */
     @Override
     public @NotNull CompletableFuture<Map<ByteArray, Entry>> getAndRemoveAll(@NotNull Set<ByteArray> keys) {
-        return metaStorageRaftGrpSvc.run(new GetAndRemoveAllCommand(keys)).thenApply(MetaStorageServiceImpl::multipleEntryResult);
+        GetAndRemoveAllCommand getAndRemoveAllCommand = getAndRemoveAllCommand(commandsFactory, keys);
+
+        return metaStorageRaftGrpSvc.run(getAndRemoveAllCommand).thenApply(MetaStorageServiceImpl::multipleEntryResult);
     }
 
     @Override
@@ -206,13 +233,17 @@ public class MetaStorageServiceImpl implements MetaStorageService {
 
         List<OperationInfo> failureOps = toOperationInfos(failure);
 
-        return metaStorageRaftGrpSvc.run(new InvokeCommand(cond, successOps, failureOps));
+        InvokeCommand invokeCommand = commandsFactory.invokeCommand().condition(cond).success(successOps).failure(failureOps).build();
+
+        return metaStorageRaftGrpSvc.run(invokeCommand);
     }
 
     /** {@inheritDoc} */
     @Override
     public @NotNull CompletableFuture<StatementResult> invoke(@NotNull If iif) {
-        return metaStorageRaftGrpSvc.run(new MultiInvokeCommand(toIfInfo(iif)))
+        MultiInvokeCommand multiInvokeCommand = commandsFactory.multiInvokeCommand().iif(toIfInfo(iif)).build();
+
+        return metaStorageRaftGrpSvc.run(multiInvokeCommand)
                 .thenApply(bi -> new StatementResult(((StatementResultInfo) bi).result()));
     }
 
@@ -231,12 +262,17 @@ public class MetaStorageServiceImpl implements MetaStorageService {
             boolean includeTombstones
     ) {
         return new CursorImpl<>(
+                commandsFactory,
                 metaStorageRaftGrpSvc,
                 metaStorageRaftGrpSvc.run(
-                        RangeCommand.builder(keyFrom, localNodeId, uuidGenerator.randomUuid())
-                                .keyTo(keyTo)
+                        commandsFactory.rangeCommand()
+                                .keyFrom(keyFrom.bytes())
+                                .keyTo(keyTo == null ? null : keyTo.bytes())
+                                .requesterNodeId(localNodeId)
+                                .cursorId(uuidGenerator.randomUuid())
                                 .revUpperBound(revUpperBound)
                                 .includeTombstones(includeTombstones)
+                                .batchSize(RangeCommand.DEFAULT_BATCH_SIZE)
                                 .build()
                 ),
                 MetaStorageServiceImpl::multipleEntryResultForCache
@@ -253,9 +289,19 @@ public class MetaStorageServiceImpl implements MetaStorageService {
     @Override
     public @NotNull Cursor<Entry> range(@NotNull ByteArray keyFrom, @Nullable ByteArray keyTo, boolean includeTombstones) {
         return new CursorImpl<>(
+                commandsFactory,
             metaStorageRaftGrpSvc,
             metaStorageRaftGrpSvc.run(
-                RangeCommand.builder(keyFrom, localNodeId, uuidGenerator.randomUuid()).keyTo(keyTo).build()),
+                    commandsFactory.rangeCommand()
+                            .keyFrom(keyFrom.bytes())
+                            .keyTo(keyTo == null ? null : keyTo.bytes())
+                            .revUpperBound(-1)
+                            .requesterNodeId(localNodeId)
+                            .cursorId(uuidGenerator.randomUuid())
+                            .includeTombstones(includeTombstones)
+                            .batchSize(RangeCommand.DEFAULT_BATCH_SIZE)
+                            .build()
+            ),
             MetaStorageServiceImpl::multipleEntryResultForCache
         );
     }
@@ -268,13 +314,19 @@ public class MetaStorageServiceImpl implements MetaStorageService {
             long revision,
             @NotNull WatchListener lsnr
     ) {
-        CompletableFuture<IgniteUuid> watchRes =
-                metaStorageRaftGrpSvc.run(new WatchRangeKeysCommand(keyFrom, keyTo, revision, localNodeId, uuidGenerator.randomUuid()));
+        CompletableFuture<IgniteUuid> watchRes = metaStorageRaftGrpSvc.run(commandsFactory.watchRangeKeysCommand()
+                .keyFrom(keyFrom == null ? null : keyFrom.bytes())
+                .keyTo(keyTo == null ? null : keyTo.bytes())
+                .revision(revision)
+                .requesterNodeId(localNodeId)
+                .cursorId(uuidGenerator.randomUuid())
+                .build()
+        );
 
         watchRes.thenAccept(
                 watchId -> watchProcessor.addWatch(
                         watchId,
-                        new CursorImpl<>(metaStorageRaftGrpSvc, watchRes, MetaStorageServiceImpl::watchResponse),
+                        new CursorImpl<>(commandsFactory, metaStorageRaftGrpSvc, watchRes, MetaStorageServiceImpl::watchResponse),
                         lsnr
                 )
         );
@@ -300,12 +352,12 @@ public class MetaStorageServiceImpl implements MetaStorageService {
             @NotNull WatchListener lsnr
     ) {
         CompletableFuture<IgniteUuid> watchRes =
-                metaStorageRaftGrpSvc.run(new WatchExactKeysCommand(keys, revision, localNodeId, uuidGenerator.randomUuid()));
+                metaStorageRaftGrpSvc.run(watchExactKeysCommand(commandsFactory, keys, revision, localNodeId, uuidGenerator.randomUuid()));
 
         watchRes.thenAccept(
                 watchId -> watchProcessor.addWatch(
                         watchId,
-                        new CursorImpl<>(metaStorageRaftGrpSvc, watchRes, MetaStorageServiceImpl::watchResponse),
+                        new CursorImpl<>(commandsFactory, metaStorageRaftGrpSvc, watchRes, MetaStorageServiceImpl::watchResponse),
                         lsnr
                 )
         );
@@ -330,84 +382,106 @@ public class MetaStorageServiceImpl implements MetaStorageService {
     /** {@inheritDoc} */
     @Override
     public @NotNull CompletableFuture<Void> closeCursors(@NotNull String nodeId) {
-        return metaStorageRaftGrpSvc.run(new CursorsCloseCommand(nodeId));
+        return metaStorageRaftGrpSvc.run(commandsFactory.cursorsCloseCommand().nodeId(nodeId).build());
     }
 
-    private static List<OperationInfo> toOperationInfos(Collection<Operation> ops) {
+    private List<OperationInfo> toOperationInfos(Collection<Operation> ops) {
         List<OperationInfo> res = new ArrayList<>(ops.size());
 
         for (Operation op : ops) {
-            OperationInfo info = null;
+            OperationInfoBuilder info = commandsFactory.operationInfo();
 
-            if (op.type() == OperationType.NO_OP) {
-                info = new OperationInfo(null, null, OperationType.NO_OP);
-            } else if (op.type() == OperationType.REMOVE) {
-                info = new OperationInfo(((Operation.RemoveOp) op.inner()).key(), null, OperationType.REMOVE);
-            } else if (op.type() == OperationType.PUT) {
-                Operation.PutOp inner = (Operation.PutOp) op.inner();
+            switch (op.type()) {
+                case NO_OP:
+                    info.operationType(OperationType.NO_OP.ordinal());
 
-                info = new OperationInfo(inner.key(), inner.value(), OperationType.PUT);
-            } else {
-                assert false : "Unknown operation type " + op.type();
+                    break;
+
+                case REMOVE:
+                    info.key(op.inner().key()).operationType(OperationType.REMOVE.ordinal());
+
+                    break;
+
+                case PUT:
+                    Operation.PutOp inner = (Operation.PutOp) op.inner();
+
+                    info.key(inner.key()).value(inner.value()).operationType(OperationType.PUT.ordinal());
+
+                    break;
+
+                default:
+                    assert false : "Unknown operation type " + op.type();
             }
 
-            res.add(info);
+            res.add(info.build());
         }
 
         return res;
     }
 
-    private static UpdateInfo toUpdateInfo(Update update) {
-        return new UpdateInfo(toOperationInfos(update.operations()), new StatementResultInfo(update.result().bytes()));
+    private UpdateInfo toUpdateInfo(Update update) {
+        return commandsFactory.updateInfo()
+                .operations(toOperationInfos(update.operations()))
+                .result(commandsFactory.statementResultInfo().result(update.result().bytes()).build())
+                .build();
     }
 
-    private static StatementInfo toIfBranchInfo(Statement statement) {
+    private StatementInfo toIfBranchInfo(Statement statement) {
         if (statement.isTerminal()) {
-            return new StatementInfo(toUpdateInfo(statement.update()));
+            return commandsFactory.statementInfo().update(toUpdateInfo(statement.update())).build();
         } else {
-            return new StatementInfo(toIfInfo(statement.iif()));
+            return commandsFactory.statementInfo().iif(toIfInfo(statement.iif())).build();
         }
     }
 
-    private static IfInfo toIfInfo(If iif) {
-        return new IfInfo(toConditionInfo(iif.condition()), toIfBranchInfo(iif.andThen()), toIfBranchInfo(iif.orElse()));
+    private IfInfo toIfInfo(If iif) {
+        return commandsFactory.ifInfo()
+                .cond(toConditionInfo(iif.condition()))
+                .andThen(toIfBranchInfo(iif.andThen()))
+                .orElse(toIfBranchInfo(iif.orElse()))
+                .build();
     }
 
-    private static ConditionInfo toConditionInfo(@NotNull Condition condition) {
-        ConditionInfo cnd = null;
+    private ConditionInfo toConditionInfo(@NotNull Condition condition) {
         if (condition instanceof SimpleCondition) {
+            SimpleConditionInfoBuilder cnd = commandsFactory.simpleConditionInfo();
+
             Object obj = ((SimpleCondition) condition).inner();
 
             if (obj instanceof SimpleCondition.ExistenceCondition) {
                 SimpleCondition.ExistenceCondition inner = (SimpleCondition.ExistenceCondition) obj;
 
-                cnd = new SimpleConditionInfo(inner.key(), inner.type(), null, 0);
+                cnd.key(inner.key()).conditionType(inner.type().ordinal());
             } else if (obj instanceof SimpleCondition.TombstoneCondition) {
                 SimpleCondition.TombstoneCondition inner = (SimpleCondition.TombstoneCondition) obj;
 
-                cnd = new SimpleConditionInfo(inner.key(), inner.type(), null, 0);
+                cnd.key(inner.key()).conditionType(inner.type().ordinal());
             } else if (obj instanceof SimpleCondition.RevisionCondition) {
                 SimpleCondition.RevisionCondition inner = (SimpleCondition.RevisionCondition) obj;
 
-                cnd = new SimpleConditionInfo(inner.key(), inner.type(), null, inner.revision());
+                cnd.key(inner.key()).conditionType(inner.type().ordinal()).revision(inner.revision());
             } else if (obj instanceof SimpleCondition.ValueCondition) {
                 SimpleCondition.ValueCondition inner = (SimpleCondition.ValueCondition) obj;
 
-                cnd = new SimpleConditionInfo(inner.key(), inner.type(), inner.value(), 0);
+                cnd.key(inner.key()).conditionType(inner.type().ordinal()).value(inner.value());
             } else {
                 assert false : "Unknown condition type: " + obj.getClass().getSimpleName();
             }
 
+            return cnd.build();
         } else if (condition instanceof CompoundCondition) {
             CompoundCondition cond = (CompoundCondition) condition;
 
-            cnd = new CompoundConditionInfo(toConditionInfo(cond.leftCondition()), toConditionInfo(cond.rightCondition()),
-                    cond.compoundConditionType());
+            return commandsFactory.compoundConditionInfo()
+                    .leftConditionInfo(toConditionInfo(cond.leftCondition()))
+                    .rightConditionInfo(toConditionInfo(cond.rightCondition()))
+                    .conditionType(cond.compoundConditionType().ordinal())
+                    .build();
         } else {
             assert false : "Unknown condition type: " + condition.getClass().getSimpleName();
-        }
 
-        return cnd;
+            return null;
+        }
     }
 
     private static Map<ByteArray, Entry> multipleEntryResult(Object obj) {
diff --git a/modules/metastorage-common/build.gradle b/modules/metastorage-common/build.gradle
index 3a9b14c46d..f1a84723aa 100644
--- a/modules/metastorage-common/build.gradle
+++ b/modules/metastorage-common/build.gradle
@@ -20,9 +20,15 @@ apply from: "$rootDir/buildscripts/publishing.gradle"
 apply from: "$rootDir/buildscripts/java-junit5.gradle"
 
 dependencies {
+    annotationProcessor project(":ignite-network-annotation-processor")
+
     implementation project(':ignite-raft-client')
     implementation project(':ignite-core')
+    implementation project(':ignite-network-api')
     implementation libs.jetbrains.annotations
+    implementation libs.fastutil.core
+
+    testImplementation libs.junit5.api
 }
 
 description = 'ignite-metastorage-common'
diff --git a/modules/metastorage-common/pom.xml b/modules/metastorage-common/pom.xml
index 3a02865a4f..f32a81efc3 100644
--- a/modules/metastorage-common/pom.xml
+++ b/modules/metastorage-common/pom.xml
@@ -43,10 +43,47 @@
             <artifactId>ignite-core</artifactId>
         </dependency>
 
+        <dependency>
+            <groupId>org.apache.ignite</groupId>
+            <artifactId>ignite-network-api</artifactId>
+        </dependency>
+
         <!-- 3rd party dependencies -->
         <dependency>
             <groupId>org.jetbrains</groupId>
             <artifactId>annotations</artifactId>
         </dependency>
+
+        <!-- Test dependencies -->
+        <dependency>
+            <groupId>org.junit.jupiter</groupId>
+            <artifactId>junit-jupiter-api</artifactId>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <dependencies>
+                    <dependency>
+                        <groupId>org.apache.ignite</groupId>
+                        <artifactId>ignite-network-annotation-processor</artifactId>
+                        <version>${project.version}</version>
+                    </dependency>
+                </dependencies>
+                <configuration>
+                    <annotationProcessorPaths>
+                        <path>
+                            <groupId>org.apache.ignite</groupId>
+                            <artifactId>ignite-network-annotation-processor</artifactId>
+                            <version>${project.version}</version>
+                        </path>
+                    </annotationProcessorPaths>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
 </project>
diff --git a/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/OperationInfo.java b/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/OperationInfo.java
similarity index 58%
rename from modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/OperationInfo.java
rename to modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/OperationInfo.java
index 98d27fa3d7..115f3c1eaf 100644
--- a/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/OperationInfo.java
+++ b/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/OperationInfo.java
@@ -15,61 +15,45 @@
  * limitations under the License.
  */
 
-package org.apache.ignite.internal.metastorage.common.command;
+package org.apache.ignite.internal.metastorage.common;
 
 import java.io.Serializable;
-import org.apache.ignite.internal.metastorage.common.OperationType;
+import org.apache.ignite.internal.metastorage.common.command.MetastorageCommandsMessageGroup;
+import org.apache.ignite.network.NetworkMessage;
+import org.apache.ignite.network.annotations.Transferable;
 
 /**
  * Defines operation.
  */
-public class OperationInfo implements Serializable {
-    /** Key. */
-    private final byte[] key;
-
-    /** Value. */
-    private final byte[] val;
-
-    /** Operation type. */
-    private final OperationType type;
-
+@Transferable(MetastorageCommandsMessageGroup.OPERATION_INFO)
+public interface OperationInfo extends NetworkMessage, Serializable {
     /**
-     * Constructs operation with given parameters.
+     * Returns key.
      *
-     * @param key  Key.
-     * @param val  Value.
-     * @param type Operation type.
+     * @return Key.
      */
-    public OperationInfo(byte[] key, byte[] val, OperationType type) {
-        this.key = key;
-        this.val = val;
-        this.type = type;
-    }
+    byte[] key();
 
     /**
-     * Returns operation type.
+     * Returns value.
      *
-     * @return Operation type.
+     * @return Value.
      */
-    public OperationType type() {
-        return type;
-    }
+    byte[] value();
 
     /**
-     * Returns key.
+     * Returns operation type.
      *
-     * @return Key.
+     * @return Operation type.
      */
-    public byte[] key() {
-        return key;
-    }
+    int operationType();
 
     /**
-     * Returns value.
+     * Returns operation type.
      *
-     * @return Value.
+     * @return Operation type.
      */
-    public byte[] value() {
-        return val;
+    default OperationType type() {
+        return OperationType.values()[operationType()];
     }
 }
diff --git a/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/StatementInfo.java b/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/StatementInfo.java
index adfe0b17ef..2377b41f0a 100644
--- a/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/StatementInfo.java
+++ b/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/StatementInfo.java
@@ -19,6 +19,9 @@ package org.apache.ignite.internal.metastorage.common;
 
 import java.io.Serializable;
 import org.apache.ignite.internal.metastorage.common.command.IfInfo;
+import org.apache.ignite.internal.metastorage.common.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}.
@@ -28,51 +31,15 @@ import org.apache.ignite.internal.metastorage.common.command.IfInfo;
  * @see IfInfo
  * @see UpdateInfo
  */
-public class StatementInfo implements Serializable {
-    /** If definition holder. */
-    private final IfInfo iif;
-
-    /** Update definition holder. */
-    private final UpdateInfo update;
-
-    /**
-     * Constructs new {@link IfInfo} statement definition.
-     *
-     * @param iif If statement definition
-     */
-    public StatementInfo(IfInfo iif) {
-        this.iif = iif;
-        this.update = null;
-    }
-
-    /**
-     * Constructs new {@link UpdateInfo} terminal statement definition.
-     *
-     * @param update Update statement definition
-     */
-    public StatementInfo(UpdateInfo update) {
-        this.update = update;
-        this.iif = null;
-    }
-
-    /**
-     * 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).
-     */
-    public boolean isTerminal() {
-        return update != null;
-    }
-
+@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.
      */
-    public IfInfo iif() {
-        return iif;
-    }
+    IfInfo iif();
 
     /**
      * Returns {@link UpdateInfo} or {@code null}, if update is not defined.
@@ -80,7 +47,14 @@ public class StatementInfo implements Serializable {
      *
      * @return {@link UpdateInfo} or {@code null}, if update is not defined.
      */
-    public UpdateInfo update() {
-        return update;
+    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-common/src/main/java/org/apache/ignite/internal/metastorage/common/StatementResultInfo.java b/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/StatementResultInfo.java
index be98e4c9c1..8ba4ff4fac 100644
--- a/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/StatementResultInfo.java
+++ b/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/StatementResultInfo.java
@@ -18,30 +18,19 @@
 package org.apache.ignite.internal.metastorage.common;
 
 import java.io.Serializable;
+import org.apache.ignite.internal.metastorage.common.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.
  */
-public class StatementResultInfo implements Serializable {
-    /** Result data. */
-    private final byte[] res;
-
-    /**
-     * Constructs result definition from the byte array.
-     *
-     * @param res byte array.
-     */
-    public StatementResultInfo(byte[] res) {
-        this.res = res;
-    }
-
+@Transferable(MetastorageCommandsMessageGroup.STATEMENT_RESULT_INFO)
+public interface StatementResultInfo extends NetworkMessage, Serializable {
     /**
      * Returns result as row byte array.
      *
      * @return result as row byte array.
      */
-    public byte[] result() {
-        return res;
-    }
-
+    byte[] result();
 }
diff --git a/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/UpdateInfo.java b/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/UpdateInfo.java
index 3933507395..5174b1e440 100644
--- a/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/UpdateInfo.java
+++ b/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/UpdateInfo.java
@@ -19,45 +19,27 @@ package org.apache.ignite.internal.metastorage.common;
 
 import java.io.Serializable;
 import java.util.Collection;
-import org.apache.ignite.internal.metastorage.common.command.OperationInfo;
+import org.apache.ignite.internal.metastorage.common.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 org.apache.ignite.internal.metastorage.common.command.IfInfo} execution.
  */
-public class UpdateInfo implements Serializable {
-    /** Operations. */
-    private final Collection<OperationInfo> ops;
-
-    /** Result. */
-    private final StatementResultInfo result;
-
-    /**
-     * Constructs new update definition.
-     *
-     * @param ops operations
-     * @param result result
-     */
-    public UpdateInfo(Collection<OperationInfo> ops, StatementResultInfo result) {
-        this.ops = ops;
-        this.result = result;
-    }
-
+@Transferable(MetastorageCommandsMessageGroup.UPDATE_INFO)
+public interface UpdateInfo extends NetworkMessage, Serializable {
     /**
      * Retunrs operations.
      *
      * @return operations.
      */
-    public Collection<OperationInfo> operations() {
-        return ops;
-    }
+    Collection<OperationInfo> operations();
 
     /**
      * Returns result.
      *
      * @return result.
      */
-    public StatementResultInfo result() {
-        return result;
-    }
+    StatementResultInfo result();
 }
diff --git a/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/CompoundConditionInfo.java b/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/CompoundConditionInfo.java
index fc93a40432..4c8dfafcdf 100644
--- a/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/CompoundConditionInfo.java
+++ b/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/CompoundConditionInfo.java
@@ -17,57 +17,40 @@
 
 package org.apache.ignite.internal.metastorage.common.command;
 
+import org.apache.ignite.network.annotations.Transferable;
+
 /**
  * Defines compound multi-key condition for {@link MultiInvokeCommand}.
  */
-public class CompoundConditionInfo implements ConditionInfo {
-    /** Left condition. */
-    private final ConditionInfo leftCondInfo;
-
-    /** Right condition. */
-    private final ConditionInfo rightCondInfo;
-
-    /** Compound condition type. */
-    private final CompoundConditionType type;
-
-    /**
-     * Constructs new compound condition definition.
-     *
-     * @param leftCondInfo left condition definition.
-     * @param rightCondInfo right conditoin definition.
-     * @param type type of compound condition definition.
-     */
-    public CompoundConditionInfo(ConditionInfo leftCondInfo,
-            ConditionInfo rightCondInfo, CompoundConditionType type) {
-        this.leftCondInfo = leftCondInfo;
-        this.rightCondInfo = rightCondInfo;
-        this.type = type;
-    }
-
+@Transferable(MetastorageCommandsMessageGroup.COMPOUND_CONDITION_INFO)
+public interface CompoundConditionInfo extends ConditionInfo {
     /**
      * Returns left condition definition.
      *
      * @return left condition definition.
      */
-    public ConditionInfo leftConditionInfo() {
-        return leftCondInfo;
-    }
+    ConditionInfo leftConditionInfo();
 
     /**
      * Returns right condition definition.
      *
      * @return right condition definition.
      */
-    public ConditionInfo rightConditionInfo() {
-        return rightCondInfo;
-    }
+    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.
      */
-    public CompoundConditionType type() {
-        return type;
+    default CompoundConditionType type() {
+        return CompoundConditionType.values()[conditionType()];
     }
 }
diff --git a/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/ConditionInfo.java b/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/ConditionInfo.java
index 5cdc15e99d..1e78fc46a8 100644
--- a/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/ConditionInfo.java
+++ b/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/ConditionInfo.java
@@ -18,6 +18,7 @@
 package org.apache.ignite.internal.metastorage.common.command;
 
 import java.io.Serializable;
+import org.apache.ignite.network.NetworkMessage;
 
 /**
  * Interface for condition definition.
@@ -25,5 +26,5 @@ import java.io.Serializable;
  * @see SimpleConditionInfo
  * @see CompoundConditionInfo
  */
-public interface ConditionInfo extends Serializable {
+public interface ConditionInfo extends NetworkMessage, Serializable {
 }
diff --git a/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/GetAllCommand.java b/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/GetAllCommand.java
index fec6ca754b..c0215ef5d9 100644
--- a/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/GetAllCommand.java
+++ b/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/GetAllCommand.java
@@ -21,60 +21,39 @@ import java.util.ArrayList;
 import java.util.List;
 import java.util.Set;
 import org.apache.ignite.lang.ByteArray;
+import org.apache.ignite.network.NetworkMessage;
+import org.apache.ignite.network.annotations.Transferable;
 import org.apache.ignite.raft.client.ReadCommand;
-import org.jetbrains.annotations.NotNull;
 
 /**
  * Get all command for MetaStorageCommandListener that retrieves entries for given keys and the revision upper bound, if latter is present.
  */
-public final class GetAllCommand implements ReadCommand {
-    /** The list of keys. */
-    @NotNull
-    private final List<byte[]> keys;
-
-    /** The upper bound for entry revisions. Must be positive. */
-    private long revUpperBound;
-
+@Transferable(MetastorageCommandsMessageGroup.GET_ALL)
+public interface GetAllCommand extends ReadCommand, NetworkMessage {
     /**
-     * Constructor.
-     *
-     * @param keys The collection of keys. Couldn't be {@code null} or empty. Collection elements couldn't be {@code null}.
+     * Returns the list of keys.
      */
-    public GetAllCommand(@NotNull Set<ByteArray> keys) {
-        assert !keys.isEmpty();
-
-        this.keys = new ArrayList<>(keys.size());
+    List<byte[]> keys();
 
-        for (ByteArray key : keys) {
-            this.keys.add(key.bytes());
-        }
-    }
+    /**
+     * Returns the upper bound for entry revisions. Must be positive.
+     */
+    long revision();
 
     /**
-     * Constructor.
+     * Static constructor.
      *
-     * @param keys          The collection of keys. Couldn't be {@code null} or empty. Collection elements couldn't be {@code null}.
+     * @param commandsFactory Commands factory.
+     * @param keys The collection of keys. Couldn't be {@code null} or empty. Collection elements couldn't be {@code null}.
      * @param revUpperBound The upper bound for entry revisions. Must be positive.
      */
-    public GetAllCommand(@NotNull Set<ByteArray> keys, long revUpperBound) {
-        this(keys);
+    static GetAllCommand getAllCommand(MetaStorageCommandsFactory commandsFactory, Set<ByteArray> keys, long revUpperBound) {
+        List<byte[]> keysList = new ArrayList<>(keys.size());
 
-        assert revUpperBound > 0;
-
-        this.revUpperBound = revUpperBound;
-    }
-
-    /**
-     * Returns the list of keys.
-     */
-    public @NotNull List<byte[]> keys() {
-        return keys;
-    }
+        for (ByteArray key : keys) {
+            keysList.add(key.bytes());
+        }
 
-    /**
-     * Returns the upper bound for entry revisions. Must be positive.
-     */
-    public long revision() {
-        return revUpperBound;
+        return commandsFactory.getAllCommand().keys(keysList).revision(revUpperBound).build();
     }
 }
diff --git a/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/GetAndPutAllCommand.java b/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/GetAndPutAllCommand.java
index 2399199d95..4172d6e2d0 100644
--- a/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/GetAndPutAllCommand.java
+++ b/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/GetAndPutAllCommand.java
@@ -21,51 +21,44 @@ import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 import org.apache.ignite.lang.ByteArray;
+import org.apache.ignite.network.NetworkMessage;
+import org.apache.ignite.network.annotations.Transferable;
 import org.apache.ignite.raft.client.WriteCommand;
-import org.jetbrains.annotations.NotNull;
 
 /**
  * Get and put all command for MetaStorageCommandListener that inserts or updates entries with given keys and given values and retrieves a
  * previous entries for given keys.
  */
-public final class GetAndPutAllCommand implements WriteCommand {
-    /** Keys. */
-    @NotNull
-    private final List<byte[]> keys;
+@Transferable(MetastorageCommandsMessageGroup.GET_AND_PUT_ALL)
+public interface GetAndPutAllCommand extends WriteCommand, NetworkMessage {
+    /**
+     * Returns keys.
+     */
+    List<byte[]> keys();
 
-    /** Values. */
-    @NotNull
-    private final List<byte[]> vals;
+    /**
+     * Returns values.
+     */
+    List<byte[]> values();
 
     /**
-     * Constructor.
+     * Static constructor.
      *
-     * @param vals Values.
+     * @param commandsFactory Commands factory.
+     * @param map Values.
      */
-    public GetAndPutAllCommand(@NotNull Map<ByteArray, byte[]> vals) {
-        int size = vals.size();
+    static GetAndPutAllCommand getAndPutAllCommand(MetaStorageCommandsFactory commandsFactory, Map<ByteArray, byte[]> map) {
+        int size = map.size();
 
-        this.keys = new ArrayList<>(size);
-        this.vals = new ArrayList<>(size);
+        List<byte[]> keys = new ArrayList<>(size);
+        List<byte[]> values = new ArrayList<>(size);
 
-        for (Map.Entry<ByteArray, byte[]> e : vals.entrySet()) {
-            this.keys.add(e.getKey().bytes());
+        for (Map.Entry<ByteArray, byte[]> e : map.entrySet()) {
+            keys.add(e.getKey().bytes());
 
-            this.vals.add(e.getValue());
+            values.add(e.getValue());
         }
-    }
 
-    /**
-     * Returns keys.
-     */
-    public @NotNull List<byte[]> keys() {
-        return keys;
-    }
-
-    /**
-     * Returns values.
-     */
-    public @NotNull List<byte[]> vals() {
-        return vals;
+        return commandsFactory.getAndPutAllCommand().keys(keys).values(values).build();
     }
 }
diff --git a/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/GetAndPutCommand.java b/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/GetAndPutCommand.java
index fea0e303d7..bc03150386 100644
--- a/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/GetAndPutCommand.java
+++ b/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/GetAndPutCommand.java
@@ -17,45 +17,23 @@
 
 package org.apache.ignite.internal.metastorage.common.command;
 
-import org.apache.ignite.lang.ByteArray;
+import org.apache.ignite.network.NetworkMessage;
+import org.apache.ignite.network.annotations.Transferable;
 import org.apache.ignite.raft.client.WriteCommand;
-import org.jetbrains.annotations.NotNull;
 
 /**
  * Get and put command for MetaStorageCommandListener that inserts or updates an entry with the given key and the given value and retrieves
  * a previous entry for the given key.
  */
-public final class GetAndPutCommand implements WriteCommand {
-    /** The key. Couldn't be {@code null}. */
-    @NotNull
-    private final byte[] key;
-
-    /** The value. Couldn't be {@code null}. */
-    @NotNull
-    private final byte[] val;
-
-    /**
-     * Constructor.
-     *
-     * @param key The key. Couldn't be {@code null}.
-     * @param val The value. Couldn't be {@code null}.
-     */
-    public GetAndPutCommand(@NotNull ByteArray key, @NotNull byte[] val) {
-        this.key = key.bytes();
-        this.val = val;
-    }
-
+@Transferable(MetastorageCommandsMessageGroup.GET_AND_PUT)
+public interface GetAndPutCommand extends WriteCommand, NetworkMessage {
     /**
      * Returns the key. Couldn't be {@code null}.
      */
-    public @NotNull byte[] key() {
-        return key;
-    }
+    byte[] key();
 
     /**
      * Returns the value. Couldn't be {@code null}.
      */
-    public @NotNull byte[] value() {
-        return val;
-    }
+    byte[] value();
 }
diff --git a/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/GetAndRemoveAllCommand.java b/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/GetAndRemoveAllCommand.java
index 9ef36a4dfb..7a4a9ac645 100644
--- a/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/GetAndRemoveAllCommand.java
+++ b/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/GetAndRemoveAllCommand.java
@@ -21,34 +21,33 @@ import java.util.ArrayList;
 import java.util.List;
 import java.util.Set;
 import org.apache.ignite.lang.ByteArray;
+import org.apache.ignite.network.NetworkMessage;
+import org.apache.ignite.network.annotations.Transferable;
 import org.apache.ignite.raft.client.WriteCommand;
-import org.jetbrains.annotations.NotNull;
 
 /**
  * Get and remove all command for MetaStorageCommandListener that removes entries for given keys and retrieves previous entries.
  */
-public final class GetAndRemoveAllCommand implements WriteCommand {
-    /** The keys collection. Couldn't be {@code null}. */
-    @NotNull
-    private final List<byte[]> keys;
+@Transferable(MetastorageCommandsMessageGroup.GET_AND_REMOVE_ALL)
+public interface GetAndRemoveAllCommand extends NetworkMessage, WriteCommand {
+    /**
+     * Returns the keys collection. Couldn't be {@code null}.
+     */
+    List<byte[]> keys();
 
     /**
-     * Constructor.
+     * Static constructor.
      *
+     * @param commandsFactory Commands factory.
      * @param keys The keys collection. Couldn't be {@code null}.
      */
-    public GetAndRemoveAllCommand(@NotNull Set<ByteArray> keys) {
-        this.keys = new ArrayList<>(keys.size());
+    static GetAndRemoveAllCommand getAndRemoveAllCommand(MetaStorageCommandsFactory commandsFactory, Set<ByteArray> keys) {
+        List<byte[]> keysList = new ArrayList<>(keys.size());
 
         for (ByteArray key : keys) {
-            this.keys.add(key.bytes());
+            keysList.add(key.bytes());
         }
-    }
 
-    /**
-     * Returns the keys collection. Couldn't be {@code null}.
-     */
-    public @NotNull List<byte[]> keys() {
-        return keys;
+        return commandsFactory.getAndRemoveAllCommand().keys(keysList).build();
     }
 }
diff --git a/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/GetAndRemoveCommand.java b/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/GetAndRemoveCommand.java
index d810086039..e2850537be 100644
--- a/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/GetAndRemoveCommand.java
+++ b/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/GetAndRemoveCommand.java
@@ -17,32 +17,18 @@
 
 package org.apache.ignite.internal.metastorage.common.command;
 
-import org.apache.ignite.lang.ByteArray;
+import org.apache.ignite.network.NetworkMessage;
+import org.apache.ignite.network.annotations.Transferable;
 import org.apache.ignite.raft.client.WriteCommand;
-import org.jetbrains.annotations.NotNull;
 
 /**
  * Get and remove command for MetaStorageCommandListener that removes an entry for the given key and retrieves a previous entry for the
  * given key.
  */
-public final class GetAndRemoveCommand implements WriteCommand {
-    /** The key. Couldn't be {@code null}. */
-    @NotNull
-    private final byte[] key;
-
-    /**
-     * Constructor.
-     *
-     * @param key The key. Couldn't be {@code null}.
-     */
-    public GetAndRemoveCommand(@NotNull ByteArray key) {
-        this.key = key.bytes();
-    }
-
+@Transferable(MetastorageCommandsMessageGroup.GET_AND_REMOVE)
+public interface GetAndRemoveCommand extends WriteCommand, NetworkMessage {
     /**
      * Returns the key. Couldn't be {@code null}.
      */
-    public @NotNull byte[] key() {
-        return key;
-    }
+    byte[] key();
 }
diff --git a/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/GetCommand.java b/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/GetCommand.java
index 68c31cfbea..e2654befa9 100644
--- a/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/GetCommand.java
+++ b/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/GetCommand.java
@@ -17,55 +17,22 @@
 
 package org.apache.ignite.internal.metastorage.common.command;
 
-import org.apache.ignite.lang.ByteArray;
+import org.apache.ignite.network.NetworkMessage;
+import org.apache.ignite.network.annotations.Transferable;
 import org.apache.ignite.raft.client.ReadCommand;
-import org.jetbrains.annotations.NotNull;
 
 /**
  * Get command for MetaStorageCommandListener that retrieves an entry for the given key and the revision upper bound, if latter is present.
  */
-public final class GetCommand implements ReadCommand {
-    /** Key. */
-    @NotNull
-    private final byte[] key;
-
-    /** The upper bound for entry revisions. Must be positive. */
-    private long revUpperBound;
-
-    /**
-     * Constructor.
-     *
-     * @param key Key. Couldn't be {@code null}.
-     */
-    public GetCommand(@NotNull ByteArray key) {
-        this.key = key.bytes();
-    }
-
-    /**
-     * Constructor.
-     *
-     * @param key           Key. Couldn't be {@code null}.
-     * @param revUpperBound The upper bound for entry revisions. Must be positive.
-     */
-    public GetCommand(@NotNull ByteArray key, long revUpperBound) {
-        this.key = key.bytes();
-
-        assert revUpperBound > 0;
-
-        this.revUpperBound = revUpperBound;
-    }
-
+@Transferable(MetastorageCommandsMessageGroup.GET)
+public interface GetCommand extends ReadCommand, NetworkMessage {
     /**
-     * Returns key.
+     * Returns key. Couldn't be {@code null}.
      */
-    public @NotNull byte[] key() {
-        return key;
-    }
+    byte[] key();
 
     /**
      * Returns the upper bound for entry revisions, or {@code null} if wasn't specified.
      */
-    public long revision() {
-        return revUpperBound;
-    }
+    long revision();
 }
diff --git a/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/IfInfo.java b/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/IfInfo.java
index 799811af4a..3467884c8c 100644
--- a/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/IfInfo.java
+++ b/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/IfInfo.java
@@ -19,58 +19,32 @@ package org.apache.ignite.internal.metastorage.common.command;
 
 import java.io.Serializable;
 import org.apache.ignite.internal.metastorage.common.StatementInfo;
+import org.apache.ignite.network.NetworkMessage;
+import org.apache.ignite.network.annotations.Transferable;
 
 /**
  * Defines if-statement for {@link MultiInvokeCommand}.
  */
-public class IfInfo implements Serializable {
-    /** Condition definition. */
-    private final ConditionInfo cond;
-
-    /** Definition of execution branch, if condition evaluates to true (aka left branch). */
-    private final StatementInfo andThen;
-
-    /** Definition execution branch, if condition evaluates to false (aka right branch). */
-    private final StatementInfo orElse;
-
-    /**
-     * Constructs new if statement definition.
-     *
-     * @param cond condition.
-     * @param andThen left execution branch.
-     * @param orElse right execution branch.
-     */
-    public IfInfo(ConditionInfo cond, StatementInfo andThen,
-            StatementInfo orElse) {
-        this.cond = cond;
-        this.andThen = andThen;
-        this.orElse = orElse;
-    }
-
+@Transferable(MetastorageCommandsMessageGroup.IF_INFO)
+public interface IfInfo extends NetworkMessage, Serializable {
     /**
      * Returns boolean condition definition.
      *
      * @return Boolean condition definition.
      */
-    public ConditionInfo cond() {
-        return cond;
-    }
+    ConditionInfo cond();
 
     /**
      * Returns definition of execution branch, if condition evaluates to true (aka left branch).
      *
      * @return Left execution branch definition.
      */
-    public StatementInfo andThen() {
-        return andThen;
-    }
+    StatementInfo andThen();
 
     /**
      * Returns definition of execution branch, if condition evaluates to false (aka right branch).
      *
      * @return Right execution branch definition.
      */
-    public StatementInfo orElse() {
-        return orElse;
-    }
+    StatementInfo orElse();
 }
diff --git a/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/InvokeCommand.java b/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/InvokeCommand.java
index 25a7787d4d..50f5703827 100644
--- a/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/InvokeCommand.java
+++ b/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/InvokeCommand.java
@@ -18,58 +18,34 @@
 package org.apache.ignite.internal.metastorage.common.command;
 
 import java.util.List;
+import org.apache.ignite.internal.metastorage.common.OperationInfo;
+import org.apache.ignite.network.NetworkMessage;
+import org.apache.ignite.network.annotations.Transferable;
 import org.apache.ignite.raft.client.WriteCommand;
 
 /**
  * Represents invoke command for meta storage.
  */
-public class InvokeCommand implements WriteCommand {
-    /** Condition. */
-    private final ConditionInfo cond;
-
-    /** Success operations. */
-    private final List<OperationInfo> success;
-
-    /** Failure operations. */
-    private final List<OperationInfo> failure;
-
-    /**
-     * Constructs invoke command instance.
-     *
-     * @param cond    Condition.
-     * @param success Success operations.
-     * @param failure Failure operations.
-     */
-    public InvokeCommand(ConditionInfo cond, List<OperationInfo> success, List<OperationInfo> failure) {
-        this.cond = cond;
-        this.success = success;
-        this.failure = failure;
-    }
-
+@Transferable(MetastorageCommandsMessageGroup.INVOKE)
+public interface InvokeCommand extends NetworkMessage, WriteCommand {
     /**
      * Returns condition.
      *
      * @return Condition.
      */
-    public ConditionInfo condition() {
-        return cond;
-    }
+    ConditionInfo condition();
 
     /**
      * Returns success operations.
      *
      * @return Success operations.
      */
-    public List<OperationInfo> success() {
-        return success;
-    }
+    List<OperationInfo> success();
 
     /**
      * Returns failure operations.
      *
      * @return Failure operations.
      */
-    public List<OperationInfo> failure() {
-        return failure;
-    }
+    List<OperationInfo> failure();
 }
diff --git a/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/MetastorageCommandsMessageGroup.java b/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/MetastorageCommandsMessageGroup.java
new file mode 100644
index 0000000000..3b7f200740
--- /dev/null
+++ b/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/MetastorageCommandsMessageGroup.java
@@ -0,0 +1,114 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.metastorage.common.command;
+
+import org.apache.ignite.internal.metastorage.common.OperationInfo;
+import org.apache.ignite.internal.metastorage.common.StatementInfo;
+import org.apache.ignite.internal.metastorage.common.StatementResultInfo;
+import org.apache.ignite.internal.metastorage.common.UpdateInfo;
+import org.apache.ignite.internal.metastorage.common.command.cursor.CursorCloseCommand;
+import org.apache.ignite.internal.metastorage.common.command.cursor.CursorHasNextCommand;
+import org.apache.ignite.internal.metastorage.common.command.cursor.CursorNextCommand;
+import org.apache.ignite.internal.metastorage.common.command.cursor.CursorsCloseCommand;
+import org.apache.ignite.network.annotations.MessageGroup;
+
+/**
+ * Message group for meta-storage RAFT commands and other required classes.
+ */
+@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;
+
+    /** Message type for {@link MultiInvokeCommand}. */
+    short MULTI_INVOKE = 11;
+
+    //----------------------------------
+
+    /** Message type for {@link GetCommand}. */
+    short GET = 20;
+
+    /** Message type for {@link GetAndPutCommand}. */
+    short GET_AND_PUT = 21;
+
+    /** Message type for {@link GetAndRemoveCommand}. */
+    short GET_AND_REMOVE = 22;
+
+    /** Message type for {@link GetAllCommand}. */
+    short GET_ALL = 30;
+
+    /** Message type for {@link GetAndPutAllCommand}. */
+    short GET_AND_PUT_ALL = 31;
+
+    /** Message type for {@link GetAndRemoveAllCommand}. */
+    short GET_AND_REMOVE_ALL = 32;
+
+    /** Message type for {@link PutCommand}. */
+    short PUT = 40;
+
+    /** Message type for {@link RemoveCommand}. */
+    short REMOVE = 41;
+
+    /** Message type for {@link PutAllCommand}. */
+    short PUT_ALL = 50;
+
+    /** Message type for {@link RemoveAllCommand}. */
+    short REMOVE_ALL = 51;
+
+    /** Message type for {@link RangeCommand}. */
+    short RANGE = 60;
+
+    /** Message type for {@link WatchExactKeysCommand}. */
+    short WATCH_EXACT_KEYS = 70;
+
+    /** Message type for {@link WatchRangeKeysCommand}. */
+    short WATCH_RANGE_KEYS = 71;
+
+    /** Message type for {@link CursorHasNextCommand}. */
+    short CURSOR_HAS_NEXT = 80;
+
+    /** Message type for {@link CursorNextCommand}. */
+    short CURSOR_NEXT = 81;
+
+    /** Message type for {@link CursorCloseCommand}. */
+    short CURSOR_CLOSE = 82;
+
+    /** Message type for {@link CursorsCloseCommand}. */
+    short CURSORS_CLOSE = 83;
+}
diff --git a/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/MultiInvokeCommand.java b/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/MultiInvokeCommand.java
index 4032f65405..5a9844f302 100644
--- a/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/MultiInvokeCommand.java
+++ b/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/MultiInvokeCommand.java
@@ -17,30 +17,19 @@
 
 package org.apache.ignite.internal.metastorage.common.command;
 
+import org.apache.ignite.network.NetworkMessage;
+import org.apache.ignite.network.annotations.Transferable;
 import org.apache.ignite.raft.client.WriteCommand;
 
 /**
  * Represents invoke command with nested conditions and execution branches.
  */
-public class MultiInvokeCommand implements WriteCommand {
-    /** If statement to invoke. */
-    private final IfInfo iif;
-
-    /**
-     * Constructs new multi-invoke command.
-     *
-     * @param iif if statement.
-     */
-    public MultiInvokeCommand(IfInfo iif) {
-        this.iif = iif;
-    }
-
+@Transferable(MetastorageCommandsMessageGroup.MULTI_INVOKE)
+public interface MultiInvokeCommand extends NetworkMessage, WriteCommand {
     /**
      * Returns if statement.
      *
      * @return if statement.
      */
-    public IfInfo iif() {
-        return iif;
-    }
+    IfInfo iif();
 }
diff --git a/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/PutAllCommand.java b/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/PutAllCommand.java
index 47c268c16f..9fa6b469aa 100644
--- a/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/PutAllCommand.java
+++ b/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/PutAllCommand.java
@@ -21,32 +21,39 @@ import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 import org.apache.ignite.lang.ByteArray;
+import org.apache.ignite.network.NetworkMessage;
+import org.apache.ignite.network.annotations.Transferable;
 import org.apache.ignite.raft.client.WriteCommand;
-import org.jetbrains.annotations.NotNull;
 
 /**
  * Put all command for MetaStorageCommandListener that inserts or updates entries with given keys and given values.
  */
-public final class PutAllCommand implements WriteCommand {
-    /** List of keys. */
-    private final List<byte[]> keys;
+@Transferable(MetastorageCommandsMessageGroup.PUT_ALL)
+public interface PutAllCommand extends WriteCommand, NetworkMessage {
+    /**
+     * Returns entries keys.
+     */
+    List<byte[]> keys();
 
-    /** List of values. */
-    private final List<byte[]> vals;
+    /**
+     * Returns entries values.
+     */
+    List<byte[]> values();
 
     /**
-     * Constructor.
+     * Static constructor.
      *
-     * @param vals he map of keys and corresponding values. Couldn't be {@code null} or empty.
+     * @param commandsFactory Commands factory.
+     * @param vals The map of keys and corresponding values. Couldn't be {@code null} or empty.
      */
-    public PutAllCommand(@NotNull Map<ByteArray, byte[]> vals) {
+    static PutAllCommand putAllCommand(MetaStorageCommandsFactory commandsFactory, Map<ByteArray, byte[]> vals) {
         assert !vals.isEmpty();
 
         int size = vals.size();
 
-        this.keys = new ArrayList<>(size);
+        List<byte[]> keys = new ArrayList<>(size);
 
-        this.vals = new ArrayList<>(size);
+        List<byte[]> values = new ArrayList<>(size);
 
         for (Map.Entry<ByteArray, byte[]> e : vals.entrySet()) {
             byte[] key = e.getKey().bytes();
@@ -56,23 +63,11 @@ public final class PutAllCommand implements WriteCommand {
             assert key != null : "Key could not be null.";
             assert val != null : "Value could not be null.";
 
-            this.keys.add(key);
+            keys.add(key);
 
-            this.vals.add(val);
+            values.add(val);
         }
-    }
-
-    /**
-     * Returns entries values.
-     */
-    public @NotNull List<byte[]> keys() {
-        return keys;
-    }
 
-    /**
-     * Returns entries values.
-     */
-    public @NotNull List<byte[]> values() {
-        return vals;
+        return commandsFactory.putAllCommand().keys(keys).values(values).build();
     }
 }
diff --git a/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/PutCommand.java b/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/PutCommand.java
index 7210c513c9..7135600ee4 100644
--- a/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/PutCommand.java
+++ b/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/PutCommand.java
@@ -17,45 +17,23 @@
 
 package org.apache.ignite.internal.metastorage.common.command;
 
-import org.apache.ignite.lang.ByteArray;
+import org.apache.ignite.network.NetworkMessage;
+import org.apache.ignite.network.annotations.Transferable;
 import org.apache.ignite.raft.client.WriteCommand;
-import org.jetbrains.annotations.NotNull;
 
 /**
  * Put command for MetaStorageCommandListener that inserts or updates an entry with the given key and the given value and retrieves a
  * previous entry for the given key.
  */
-public final class PutCommand implements WriteCommand {
-    /** The key. Couldn't be {@code null}. */
-    @NotNull
-    private final byte[] key;
-
-    /** The value. Couldn't be {@code null}. */
-    @NotNull
-    private final byte[] val;
-
-    /**
-     * Constructor.
-     *
-     * @param key The key. Couldn't be {@code null}.
-     * @param val The value. Couldn't be {@code null}.
-     */
-    public PutCommand(@NotNull ByteArray key, @NotNull byte[] val) {
-        this.key = key.bytes();
-        this.val = val;
-    }
-
+@Transferable(MetastorageCommandsMessageGroup.PUT)
+public interface PutCommand extends WriteCommand, NetworkMessage {
     /**
      * Returns the key. Couldn't be {@code null}.
      */
-    public @NotNull byte[] key() {
-        return key;
-    }
+    byte[] key();
 
     /**
      * Returns the value. Couldn't be {@code null}.
      */
-    public @NotNull byte[] value() {
-        return val;
-    }
+    byte[] value();
 }
diff --git a/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/RangeCommand.java b/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/RangeCommand.java
index c40b51f4c3..7ad3c11a45 100644
--- a/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/RangeCommand.java
+++ b/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/RangeCommand.java
@@ -17,218 +17,52 @@
 
 package org.apache.ignite.internal.metastorage.common.command;
 
-import static java.util.Objects.requireNonNull;
-
-import org.apache.ignite.lang.ByteArray;
 import org.apache.ignite.lang.IgniteUuid;
+import org.apache.ignite.network.NetworkMessage;
+import org.apache.ignite.network.annotations.Transferable;
 import org.apache.ignite.raft.client.WriteCommand;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
 
 /**
  * Range command for MetaStorageCommandListener that retrieves entries for the given key range in lexicographic order. Entries will be
  * filtered out by upper bound of given revision number.
  */
-public final class RangeCommand implements WriteCommand {
+@Transferable(MetastorageCommandsMessageGroup.RANGE)
+public interface RangeCommand extends WriteCommand, NetworkMessage {
     /** Default value for {@link #batchSize}. */
-    public static final int DEFAULT_BATCH_SIZE = 100;
-
-    /** Start key of range (inclusive). Couldn't be {@code null}. */
-    @NotNull
-    private final byte[] keyFrom;
-
-    /** End key of range (exclusive). Could be {@code null}. */
-    @Nullable
-    private final byte[] keyTo;
-
-    /** The upper bound for entry revision. {@code -1} means latest revision. */
-    @NotNull
-    private final long revUpperBound;
-
-    /** Id of the node that requests range. */
-    @NotNull
-    private final String requesterNodeId;
-
-    /** Id of cursor that is associated with the current command. */
-    @NotNull
-    private final IgniteUuid cursorId;
-
-    /** Whether to include tombstone entries. */
-    private final boolean includeTombstones;
-
-    /** Maximum size of the batch that is sent in single response message. */
-    private final int batchSize;
-
-    /**
-     * Constructor.
-     *
-     * @param keyFrom           Start key of range (inclusive).
-     * @param keyTo             End key of range (exclusive).
-     * @param revUpperBound     The upper bound for entry revision. {@code -1} means latest revision.
-     * @param requesterNodeId   Id of the node that requests range.
-     * @param cursorId          Id of cursor that is associated with the current command.
-     * @param includeTombstones Whether to include tombstones.
-     * @param batchSize         Maximum size of the batch that is sent in single response message.
-     */
-    public RangeCommand(
-            @NotNull ByteArray keyFrom,
-            @Nullable ByteArray keyTo,
-            long revUpperBound,
-            @NotNull String requesterNodeId,
-            @NotNull IgniteUuid cursorId,
-            boolean includeTombstones,
-            int batchSize
-    ) {
-        this.keyFrom = keyFrom.bytes();
-        this.keyTo = keyTo == null ? null : keyTo.bytes();
-        this.revUpperBound = revUpperBound;
-        this.requesterNodeId = requesterNodeId;
-        this.cursorId = cursorId;
-        this.includeTombstones = includeTombstones;
-        this.batchSize = batchSize;
-    }
+    int DEFAULT_BATCH_SIZE = 100;
 
     /**
      * Returns start key of range (inclusive). Couldn't be {@code null}.
      */
-    public @NotNull byte[] keyFrom() {
-        return keyFrom;
-    }
+    byte[] keyFrom();
 
     /**
      * Returns end key of range (exclusive). Could be {@code null}.
      */
-    public @Nullable byte[] keyTo() {
-        return keyTo;
-    }
+    byte[] keyTo();
 
     /**
      * Returns the upper bound for entry revision. Means latest revision.
      */
-    public @NotNull long revUpperBound() {
-        return revUpperBound;
-    }
+    long revUpperBound();
 
     /**
      * Returns id of the node that requests range.
      */
-    public @NotNull String requesterNodeId() {
-        return requesterNodeId;
-    }
+    String requesterNodeId();
 
     /**
      * Returns id of cursor that is associated with the current command.
      */
-    @NotNull
-    public IgniteUuid getCursorId() {
-        return cursorId;
-    }
+    IgniteUuid cursorId();
 
     /**
      * Returns the boolean value indicating whether this range command is supposed to include tombstone entries into the cursor.
      */
-    public boolean includeTombstones() {
-        return includeTombstones;
-    }
-
-    public int batchSize() {
-        return batchSize;
-    }
-
-    public static RangeCommandBuilder builder(@NotNull ByteArray keyFrom, @NotNull String requesterNodeId, @NotNull IgniteUuid cursorId) {
-        return new RangeCommandBuilder(keyFrom, requesterNodeId, cursorId);
-    }
+    boolean includeTombstones();
 
     /**
-     * The builder.
+     * Returns maximum size of the batch that is sent in single response message.
      */
-    public static class RangeCommandBuilder {
-        private final ByteArray keyFrom;
-
-        private ByteArray keyTo;
-
-        private long revUpperBound = -1L;
-
-        private final String requesterNodeId;
-
-        private final IgniteUuid cursorId;
-
-        private boolean includeTombstones = false;
-
-        private int batchSize = DEFAULT_BATCH_SIZE;
-
-        /**
-         * The builder constructor.
-         */
-        public RangeCommandBuilder(@NotNull ByteArray keyFrom, @NotNull String requesterNodeId, @NotNull IgniteUuid cursorId) {
-            this.keyFrom = keyFrom;
-            this.requesterNodeId = requesterNodeId;
-            this.cursorId = cursorId;
-        }
-
-        /**
-         * Setter for key to.
-         *
-         * @param keyTo Key to.
-         * @return This for chaining.
-         */
-        public RangeCommandBuilder keyTo(ByteArray keyTo) {
-            this.keyTo = keyTo;
-
-            return this;
-        }
-
-        /**
-         * Setter for upper bound revision.
-         *
-         * @param revUpperBound Upper bound revision.
-         * @return This for chaining.
-         */
-        public RangeCommandBuilder revUpperBound(long revUpperBound) {
-            this.revUpperBound = revUpperBound;
-
-            return this;
-        }
-
-        /**
-         * Setter for include tombstones.
-         *
-         * @param includeTombstones Whether to include tombstones.
-         * @return This for chaining.
-         */
-        public RangeCommandBuilder includeTombstones(boolean includeTombstones) {
-            this.includeTombstones = includeTombstones;
-
-            return this;
-        }
-
-        /**
-         * Setter for batch size.
-         *
-         * @param batchSize Batch size.
-         * @return This for chaining.
-         */
-        public RangeCommandBuilder batchSize(int batchSize) {
-            this.batchSize = batchSize;
-
-            return this;
-        }
-
-        /**
-         * Build method.
-         *
-         * @return Range command.
-         */
-        public RangeCommand build() {
-            return new RangeCommand(
-                requireNonNull(keyFrom),
-                keyTo,
-                revUpperBound,
-                requireNonNull(requesterNodeId),
-                requireNonNull(cursorId),
-                includeTombstones,
-                batchSize
-            );
-        }
-    }
+    int batchSize();
 }
diff --git a/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/RemoveAllCommand.java b/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/RemoveAllCommand.java
index f4881e8a9d..56b3cc92c6 100644
--- a/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/RemoveAllCommand.java
+++ b/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/RemoveAllCommand.java
@@ -21,34 +21,33 @@ import java.util.ArrayList;
 import java.util.List;
 import java.util.Set;
 import org.apache.ignite.lang.ByteArray;
+import org.apache.ignite.network.NetworkMessage;
+import org.apache.ignite.network.annotations.Transferable;
 import org.apache.ignite.raft.client.WriteCommand;
-import org.jetbrains.annotations.NotNull;
 
 /**
  * Remove all command for MetaStorageCommandListener that removes entries for given keys.
  */
-public final class RemoveAllCommand implements WriteCommand {
-    /** The keys list. Couldn't be {@code null}. */
-    @NotNull
-    private final List<byte[]> keys;
+@Transferable(MetastorageCommandsMessageGroup.REMOVE_ALL)
+public interface RemoveAllCommand extends WriteCommand, NetworkMessage {
+    /**
+     * Returns the keys list. Couldn't be {@code null}.
+     */
+    List<byte[]> keys();
 
     /**
-     * Constructor.
+     * Static constructor.
      *
+     * @param commandsFactory Commands factory.
      * @param keys The keys collection. Couldn't be {@code null}.
      */
-    public RemoveAllCommand(@NotNull Set<ByteArray> keys) {
-        this.keys = new ArrayList<>(keys.size());
+    static RemoveAllCommand removeAllCommand(MetaStorageCommandsFactory commandsFactory, Set<ByteArray> keys) {
+        List<byte[]> list = new ArrayList<>(keys.size());
 
         for (ByteArray key : keys) {
-            this.keys.add(key.bytes());
+            list.add(key.bytes());
         }
-    }
 
-    /**
-     * Returns the keys list. Couldn't be {@code null}.
-     */
-    public @NotNull List<byte[]> keys() {
-        return keys;
+        return commandsFactory.removeAllCommand().keys(list).build();
     }
 }
diff --git a/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/RemoveCommand.java b/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/RemoveCommand.java
index 90dafcb806..3b4aa42901 100644
--- a/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/RemoveCommand.java
+++ b/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/RemoveCommand.java
@@ -17,31 +17,17 @@
 
 package org.apache.ignite.internal.metastorage.common.command;
 
-import org.apache.ignite.lang.ByteArray;
+import org.apache.ignite.network.NetworkMessage;
+import org.apache.ignite.network.annotations.Transferable;
 import org.apache.ignite.raft.client.WriteCommand;
-import org.jetbrains.annotations.NotNull;
 
 /**
  * Remove command for MetaStorageCommandListener that removes an entry for the given key.
  */
-public final class RemoveCommand implements WriteCommand {
-    /** The key. Couldn't be {@code null}. */
-    @NotNull
-    private final byte[] key;
-
-    /**
-     * Constructor.
-     *
-     * @param key he key. Couldn't be {@code null}.
-     */
-    public RemoveCommand(@NotNull ByteArray key) {
-        this.key = key.bytes();
-    }
-
+@Transferable(MetastorageCommandsMessageGroup.REMOVE)
+public interface RemoveCommand extends WriteCommand, NetworkMessage {
     /**
      * Returns the key. Couldn't be {@code null}.
      */
-    public @NotNull byte[] key() {
-        return key;
-    }
+    byte[] key();
 }
diff --git a/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/SimpleConditionInfo.java b/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/SimpleConditionInfo.java
index 6f54a0dcc0..8ed1c5407a 100644
--- a/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/SimpleConditionInfo.java
+++ b/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/SimpleConditionInfo.java
@@ -18,54 +18,34 @@
 package org.apache.ignite.internal.metastorage.common.command;
 
 import org.apache.ignite.internal.metastorage.common.ConditionType;
+import org.apache.ignite.network.annotations.Transferable;
 
 /**
  * Defines condition for InvokeCommand.
  */
-public class SimpleConditionInfo implements ConditionInfo {
-    /** Key. */
-    private final byte[] key;
-
-    /** Type. */
-    private final ConditionType type;
-
-    /** Value. */
-    private final byte[] val;
-
-    /** Revision. */
-    private final long rev;
-
+@Transferable(MetastorageCommandsMessageGroup.SIMPLE_CONDITION_INFO)
+public interface SimpleConditionInfo extends ConditionInfo {
     /**
-     * Construct condition with given parameters.
+     * Returns key.
      *
-     * @param key  Key.
-     * @param type Condition type.
-     * @param val  Value.
-     * @param rev  Revision.
+     * @return Key.
      */
-    public SimpleConditionInfo(byte[] key, ConditionType type, byte[] val, long rev) {
-        this.key = key;
-        this.type = type;
-        this.val = val;
-        this.rev = rev;
-    }
+    byte[] key();
 
     /**
-     * Returns key.
+     * Returns condition type.
      *
-     * @return Key.
+     * @return Condition type.
      */
-    public byte[] key() {
-        return key;
-    }
+    int conditionType();
 
     /**
      * Returns condition type.
      *
      * @return Condition type.
      */
-    public ConditionType type() {
-        return type;
+    default ConditionType type() {
+        return ConditionType.values()[conditionType()];
     }
 
     /**
@@ -73,16 +53,12 @@ public class SimpleConditionInfo implements ConditionInfo {
      *
      * @return Value.
      */
-    public byte[] value() {
-        return val;
-    }
+    byte[] value();
 
     /**
      * Returns revision.
      *
      * @return Revision.
      */
-    public long revision() {
-        return rev;
-    }
+    long revision();
 }
diff --git a/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/WatchExactKeysCommand.java b/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/WatchExactKeysCommand.java
index a6fc6bbcd8..9b5201e829 100644
--- a/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/WatchExactKeysCommand.java
+++ b/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/WatchExactKeysCommand.java
@@ -22,81 +22,62 @@ import java.util.List;
 import java.util.Set;
 import org.apache.ignite.lang.ByteArray;
 import org.apache.ignite.lang.IgniteUuid;
+import org.apache.ignite.network.NetworkMessage;
+import org.apache.ignite.network.annotations.Transferable;
 import org.apache.ignite.raft.client.WriteCommand;
-import org.jetbrains.annotations.NotNull;
 
 /**
  * Watch command for MetaStorageCommandListener that subscribes on meta storage updates matching the parameters.
  */
-public final class WatchExactKeysCommand implements WriteCommand {
-    /** The keys list. Couldn't be {@code null}. */
-    @NotNull
-    private final List<byte[]> keys;
+@Transferable(MetastorageCommandsMessageGroup.WATCH_EXACT_KEYS)
+public interface WatchExactKeysCommand extends NetworkMessage, WriteCommand {
+    /**
+     * Returns the keys list. Couldn't be {@code null}.
+     */
+    List<byte[]> keys();
 
-    /** Start revision inclusive. {@code 0} - all revisions. */
-    private final long revision;
+    /**
+     * Returns start revision inclusive. {@code 0} - all revisions.
+     */
+    long revision();
 
-    /** Id of the node that requests watch. */
-    @NotNull
-    private final String requesterNodeId;
+    /**
+     * Returns id of the node that requests range.
+     */
+    String requesterNodeId();
 
-    /** Id of cursor that is associated with the current command. */
-    @NotNull
-    private final IgniteUuid cursorId;
+    /**
+     * Returns id of cursor that is associated with the current command.
+     */
+    IgniteUuid cursorId();
 
     /**
-     * Constructor.
+     * Static constructor.
      *
+     * @param commandsFactory Commands factory.
      * @param keys            The keys collection. Couldn't be {@code null}.
      * @param revision        Start revision inclusive. {@code 0} - all revisions.
      * @param requesterNodeId Id of the node that requests watch.
      * @param cursorId        Id of cursor that is associated with the current command.
      */
-    public WatchExactKeysCommand(
-            @NotNull Set<ByteArray> keys,
+    static WatchExactKeysCommand watchExactKeysCommand(
+            MetaStorageCommandsFactory commandsFactory,
+            Set<ByteArray> keys,
             long revision,
-            @NotNull String requesterNodeId,
-            @NotNull IgniteUuid cursorId
+            String requesterNodeId,
+            IgniteUuid cursorId
     ) {
-        this.keys = new ArrayList<>(keys.size());
+        List<byte[]> list = new ArrayList<>(keys.size());
 
         for (ByteArray key : keys) {
-            this.keys.add(key.bytes());
+            list.add(key.bytes());
         }
 
-        this.revision = revision;
-
-        this.requesterNodeId = requesterNodeId;
-
-        this.cursorId = cursorId;
-    }
-
-    /**
-     * Returns the keys list. Couldn't be {@code null}.
-     */
-    public @NotNull List<byte[]> keys() {
-        return keys;
-    }
-
-    /**
-     * Returns start revision inclusive.
-     */
-    public @NotNull Long revision() {
-        return revision;
-    }
-
-    /**
-     * Returns id of the node that requests range.
-     */
-    public @NotNull String requesterNodeId() {
-        return requesterNodeId;
-    }
-
-    /**
-     * Returns id of cursor that is associated with the current command.
-     */
-    @NotNull
-    public IgniteUuid getCursorId() {
-        return cursorId;
+        return commandsFactory.watchExactKeysCommand()
+                .keys(list)
+                .revision(revision)
+                .requesterNodeId(requesterNodeId)
+                .cursorId(cursorId)
+                .build();
     }
 }
diff --git a/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/WatchRangeKeysCommand.java b/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/WatchRangeKeysCommand.java
index 75b9328a30..dc51e3ef1e 100644
--- a/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/WatchRangeKeysCommand.java
+++ b/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/WatchRangeKeysCommand.java
@@ -17,107 +17,39 @@
 
 package org.apache.ignite.internal.metastorage.common.command;
 
-import org.apache.ignite.lang.ByteArray;
 import org.apache.ignite.lang.IgniteUuid;
+import org.apache.ignite.network.NetworkMessage;
+import org.apache.ignite.network.annotations.Transferable;
 import org.apache.ignite.raft.client.WriteCommand;
-import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
 /**
  * Watch command for MetaStorageCommandListener that subscribes on meta storage updates matching the parameters.
  */
-public final class WatchRangeKeysCommand implements WriteCommand {
-    /** Start key of range (inclusive). Couldn't be {@code null}. */
-    @Nullable
-    private final byte[] keyFrom;
-
-    /** End key of range (exclusive). Could be {@code null}. */
-    @Nullable
-    private final byte[] keyTo;
-
-    /** Start revision inclusive. {@code 0} - all revisions. */
-    private final long revision;
-
-    /** Id of the node that requests watch. */
-    @NotNull
-    private final String requesterNodeId;
-
-    /** Id of cursor that is associated with the current command. */
-    @NotNull
-    private final IgniteUuid cursorId;
-
-    /**
-     * Constructor.
-     *
-     * @param keyFrom         Start key of range (inclusive).
-     * @param keyTo           End key of range (exclusive).
-     * @param requesterNodeId Id of the node that requests watch.
-     * @param cursorId        Id of cursor that is associated with the current command.*
-     */
-    public WatchRangeKeysCommand(
-            @Nullable ByteArray keyFrom,
-            @Nullable ByteArray keyTo,
-            @NotNull String requesterNodeId,
-            @NotNull IgniteUuid cursorId
-    ) {
-        this(keyFrom, keyTo, 0L, requesterNodeId, cursorId);
-    }
-
-    /**
-     * Constructor.
-     *
-     * @param keyFrom         Start key of range (inclusive).
-     * @param keyTo           End key of range (exclusive).
-     * @param revision        Start revision inclusive. {@code 0} - all revisions.
-     * @param requesterNodeId Id of the node that requests watch.
-     * @param cursorId        Id of cursor that is associated with the current command.
-     */
-    public WatchRangeKeysCommand(
-            @Nullable ByteArray keyFrom,
-            @Nullable ByteArray keyTo,
-            long revision,
-            @NotNull String requesterNodeId,
-            @NotNull IgniteUuid cursorId
-    ) {
-        this.keyFrom = keyFrom == null ? null : keyFrom.bytes();
-        this.keyTo = keyTo == null ? null : keyTo.bytes();
-        this.revision = revision;
-        this.requesterNodeId = requesterNodeId;
-        this.cursorId = cursorId;
-    }
-
+@Transferable(MetastorageCommandsMessageGroup.WATCH_RANGE_KEYS)
+public interface WatchRangeKeysCommand extends NetworkMessage, WriteCommand {
     /**
      * Returns start key of range (inclusive). Couldn't be {@code null}.
      */
-    public @Nullable byte[] keyFrom() {
-        return keyFrom;
-    }
+    byte @Nullable [] keyFrom();
 
     /**
      * Returns end key of range (exclusive). Could be {@code null}.
      */
-    public @Nullable byte[] keyTo() {
-        return keyTo;
-    }
+    byte @Nullable [] keyTo();
 
     /**
      * Returns start revision inclusive. {@code 0} - all revisions.
      */
-    public long revision() {
-        return revision;
-    }
+    long revision();
 
     /**
      * Returns id of the node that requests range.
      */
-    public @NotNull String requesterNodeId() {
-        return requesterNodeId;
-    }
+    String requesterNodeId();
 
     /**
      * Returns id of cursor that is associated with the current command.
      */
-    public IgniteUuid getCursorId() {
-        return cursorId;
-    }
+    IgniteUuid cursorId();
 }
diff --git a/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/cursor/CursorCloseCommand.java b/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/cursor/CursorCloseCommand.java
index e5e0fa6200..15acfdf126 100644
--- a/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/cursor/CursorCloseCommand.java
+++ b/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/cursor/CursorCloseCommand.java
@@ -17,31 +17,19 @@
 
 package org.apache.ignite.internal.metastorage.common.command.cursor;
 
+import org.apache.ignite.internal.metastorage.common.command.MetastorageCommandsMessageGroup;
 import org.apache.ignite.lang.IgniteUuid;
+import org.apache.ignite.network.NetworkMessage;
+import org.apache.ignite.network.annotations.Transferable;
 import org.apache.ignite.raft.client.WriteCommand;
-import org.jetbrains.annotations.NotNull;
 
 /**
  * Cursor close command for MetaStorageCommandListener that closes cursor with given id.
  */
-public class CursorCloseCommand implements WriteCommand {
-    /** Cursor id. */
-    @NotNull
-    private final IgniteUuid cursorId;
-
-    /**
-     * Constructor.
-     *
-     * @param cursorId Cursor id.
-     */
-    public CursorCloseCommand(@NotNull IgniteUuid cursorId) {
-        this.cursorId = cursorId;
-    }
-
+@Transferable(MetastorageCommandsMessageGroup.CURSOR_CLOSE)
+public interface CursorCloseCommand extends NetworkMessage, WriteCommand {
     /**
      * Returns cursor id.
      */
-    public @NotNull IgniteUuid cursorId() {
-        return cursorId;
-    }
+    IgniteUuid cursorId();
 }
diff --git a/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/cursor/CursorHasNextCommand.java b/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/cursor/CursorHasNextCommand.java
index c868fde6f6..1067b5b60d 100644
--- a/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/cursor/CursorHasNextCommand.java
+++ b/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/cursor/CursorHasNextCommand.java
@@ -17,31 +17,19 @@
 
 package org.apache.ignite.internal.metastorage.common.command.cursor;
 
+import org.apache.ignite.internal.metastorage.common.command.MetastorageCommandsMessageGroup;
 import org.apache.ignite.lang.IgniteUuid;
+import org.apache.ignite.network.NetworkMessage;
+import org.apache.ignite.network.annotations.Transferable;
 import org.apache.ignite.raft.client.ReadCommand;
-import org.jetbrains.annotations.NotNull;
 
 /**
  * Cursor {@code hasNext} command for MetaStorageCommandListener that checks whether next element is available.
  */
-public class CursorHasNextCommand implements ReadCommand {
-    /** Cursor id. */
-    @NotNull
-    private final IgniteUuid cursorId;
-
-    /**
-     * Constructor.
-     *
-     * @param cursorId Cursor id.
-     */
-    public CursorHasNextCommand(@NotNull IgniteUuid cursorId) {
-        this.cursorId = cursorId;
-    }
-
+@Transferable(MetastorageCommandsMessageGroup.CURSOR_HAS_NEXT)
+public interface CursorHasNextCommand extends NetworkMessage, ReadCommand {
     /**
      * Returns cursor id.
      */
-    public @NotNull IgniteUuid cursorId() {
-        return cursorId;
-    }
+    IgniteUuid cursorId();
 }
diff --git a/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/cursor/CursorNextCommand.java b/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/cursor/CursorNextCommand.java
index 49feddc6ba..2cf7ab6867 100644
--- a/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/cursor/CursorNextCommand.java
+++ b/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/cursor/CursorNextCommand.java
@@ -17,31 +17,19 @@
 
 package org.apache.ignite.internal.metastorage.common.command.cursor;
 
+import org.apache.ignite.internal.metastorage.common.command.MetastorageCommandsMessageGroup;
 import org.apache.ignite.lang.IgniteUuid;
+import org.apache.ignite.network.NetworkMessage;
+import org.apache.ignite.network.annotations.Transferable;
 import org.apache.ignite.raft.client.WriteCommand;
-import org.jetbrains.annotations.NotNull;
 
 /**
  * Cursor {@code next} command for MetaStorageCommandListener that returns next element and moves cursor.
  */
-public class CursorNextCommand implements WriteCommand {
-    /** Cursor id. */
-    @NotNull
-    private final IgniteUuid cursorId;
-
-    /**
-     * Constructor.
-     *
-     * @param cursorId Cursor id.
-     */
-    public CursorNextCommand(@NotNull IgniteUuid cursorId) {
-        this.cursorId = cursorId;
-    }
-
+@Transferable(MetastorageCommandsMessageGroup.CURSOR_NEXT)
+public interface CursorNextCommand extends NetworkMessage, WriteCommand {
     /**
      * Returns cursor id.
      */
-    public @NotNull IgniteUuid cursorId() {
-        return cursorId;
-    }
+    IgniteUuid cursorId();
 }
diff --git a/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/cursor/CursorsCloseCommand.java b/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/cursor/CursorsCloseCommand.java
index 292c01b66d..60e8bdef82 100644
--- a/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/cursor/CursorsCloseCommand.java
+++ b/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/cursor/CursorsCloseCommand.java
@@ -17,31 +17,19 @@
 
 package org.apache.ignite.internal.metastorage.common.command.cursor;
 
+import org.apache.ignite.internal.metastorage.common.command.MetastorageCommandsMessageGroup;
+import org.apache.ignite.network.NetworkMessage;
+import org.apache.ignite.network.annotations.Transferable;
 import org.apache.ignite.raft.client.WriteCommand;
-import org.jetbrains.annotations.NotNull;
 
 /**
  * Command that closes all cursor for the specified node id. Common use case for a given command is to close cursors for the node that left
  * topology.
  */
-public class CursorsCloseCommand implements WriteCommand {
-    /** Cursor id. */
-    @NotNull
-    private final String nodeId;
-
-    /**
-     * Constructor.
-     *
-     * @param nodeId Node id.
-     */
-    public CursorsCloseCommand(@NotNull String nodeId) {
-        this.nodeId = nodeId;
-    }
-
+@Transferable(MetastorageCommandsMessageGroup.CURSORS_CLOSE)
+public interface CursorsCloseCommand extends NetworkMessage, WriteCommand {
     /**
      * Returns cursor id.
      */
-    public @NotNull String nodeId() {
-        return nodeId;
-    }
+    String nodeId();
 }
diff --git a/modules/metastorage-common/src/test/java/org/apache/ignite/internal/metastorage/common/ConditionTypeTest.java b/modules/metastorage-common/src/test/java/org/apache/ignite/internal/metastorage/common/ConditionTypeTest.java
new file mode 100644
index 0000000000..88a9f01109
--- /dev/null
+++ b/modules/metastorage-common/src/test/java/org/apache/ignite/internal/metastorage/common/ConditionTypeTest.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.common;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.jupiter.api.Test;
+
+/**
+ * Tests that persisted enum ordinals have not been accidentally changed by a developer.
+ */
+class ConditionTypeTest {
+    @Test
+    void testOrdinal() {
+        assertEquals(0, ConditionType.REV_EQUAL.ordinal());
+
+        assertEquals(1, ConditionType.REV_NOT_EQUAL.ordinal());
+
+        assertEquals(2, ConditionType.REV_GREATER.ordinal());
+
+        assertEquals(3, ConditionType.REV_LESS.ordinal());
+
+        assertEquals(4, ConditionType.REV_LESS_OR_EQUAL.ordinal());
+
+        assertEquals(5, ConditionType.REV_GREATER_OR_EQUAL.ordinal());
+
+        assertEquals(6, ConditionType.VAL_EQUAL.ordinal());
+
+        assertEquals(7, ConditionType.VAL_NOT_EQUAL.ordinal());
+
+        assertEquals(8, ConditionType.VAL_GREATER.ordinal());
+
+        assertEquals(9, ConditionType.VAL_LESS.ordinal());
+
+        assertEquals(10, ConditionType.VAL_LESS_OR_EQUAL.ordinal());
+
+        assertEquals(11, ConditionType.VAL_GREATER_OR_EQUAL.ordinal());
+
+        assertEquals(12, ConditionType.KEY_EXISTS.ordinal());
+
+        assertEquals(13, ConditionType.KEY_NOT_EXISTS.ordinal());
+
+        assertEquals(14, ConditionType.TOMBSTONE.ordinal());
+    }
+}
diff --git a/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/ConditionInfo.java b/modules/metastorage-common/src/test/java/org/apache/ignite/internal/metastorage/common/OperationTypeTest.java
similarity index 63%
copy from modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/ConditionInfo.java
copy to modules/metastorage-common/src/test/java/org/apache/ignite/internal/metastorage/common/OperationTypeTest.java
index 5cdc15e99d..b703b703d1 100644
--- a/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/ConditionInfo.java
+++ b/modules/metastorage-common/src/test/java/org/apache/ignite/internal/metastorage/common/OperationTypeTest.java
@@ -15,15 +15,22 @@
  * limitations under the License.
  */
 
-package org.apache.ignite.internal.metastorage.common.command;
+package org.apache.ignite.internal.metastorage.common;
 
-import java.io.Serializable;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.jupiter.api.Test;
 
 /**
- * Interface for condition definition.
- *
- * @see SimpleConditionInfo
- * @see CompoundConditionInfo
+ * Tests that persisted enum ordinals have not been accidentally changed by a developer.
  */
-public interface ConditionInfo extends Serializable {
+class OperationTypeTest {
+    @Test
+    void testOrdinal() {
+        assertEquals(0, OperationType.NO_OP.ordinal());
+
+        assertEquals(1, OperationType.PUT.ordinal());
+
+        assertEquals(2, OperationType.REMOVE.ordinal());
+    }
 }
diff --git a/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/ErrorResponse.java b/modules/metastorage-common/src/test/java/org/apache/ignite/internal/metastorage/common/command/CompoundConditionTypeTest.java
similarity index 65%
rename from modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/ErrorResponse.java
rename to modules/metastorage-common/src/test/java/org/apache/ignite/internal/metastorage/common/command/CompoundConditionTypeTest.java
index 9364478922..aa0acf5eac 100644
--- a/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/command/ErrorResponse.java
+++ b/modules/metastorage-common/src/test/java/org/apache/ignite/internal/metastorage/common/command/CompoundConditionTypeTest.java
@@ -17,28 +17,18 @@
 
 package org.apache.ignite.internal.metastorage.common.command;
 
-import java.io.Serializable;
+import static org.junit.jupiter.api.Assertions.assertEquals;
 
-/** Defines error response. */
-public class ErrorResponse implements Serializable {
-    /** Error code. */
-    private final int errCode;
+import org.junit.jupiter.api.Test;
 
-    /**
-     * Constructs error response.
-     *
-     * @param errCode Error code
-     */
-    public ErrorResponse(int errCode) {
-        this.errCode = errCode;
-    }
+/**
+ * Tests that persisted enum ordinals have not been accidentally changed by a developer.
+ */
+class CompoundConditionTypeTest {
+    @Test
+    void testOrdinal() {
+        assertEquals(0, CompoundConditionType.AND.ordinal());
 
-    /**
-     * Returns error code.
-     *
-     * @return Error code.
-     */
-    public int errorCode() {
-        return errCode;
+        assertEquals(1, CompoundConditionType.OR.ordinal());
     }
 }
diff --git a/modules/metastorage-server/build.gradle b/modules/metastorage-server/build.gradle
index 0d8377a26a..3b699d8b9a 100644
--- a/modules/metastorage-server/build.gradle
+++ b/modules/metastorage-server/build.gradle
@@ -24,6 +24,7 @@ description = 'ignite-metastorage-server'
 
 dependencies {
     implementation project(':ignite-core')
+    implementation project(':ignite-network-api')
     implementation project(':ignite-metastorage-common')
     implementation project(':ignite-raft-client')
     implementation project(':ignite-rocksdb-common')
diff --git a/modules/metastorage-server/src/main/java/org/apache/ignite/internal/metastorage/server/raft/MetaStorageListener.java b/modules/metastorage-server/src/main/java/org/apache/ignite/internal/metastorage/server/raft/MetaStorageListener.java
index 0e78022e11..6bbebb81ea 100644
--- a/modules/metastorage-server/src/main/java/org/apache/ignite/internal/metastorage/server/raft/MetaStorageListener.java
+++ b/modules/metastorage-server/src/main/java/org/apache/ignite/internal/metastorage/server/raft/MetaStorageListener.java
@@ -32,8 +32,8 @@ import java.util.concurrent.ConcurrentHashMap;
 import java.util.function.Consumer;
 import org.apache.ignite.internal.metastorage.common.ConditionType;
 import org.apache.ignite.internal.metastorage.common.MetaStorageException;
+import org.apache.ignite.internal.metastorage.common.OperationInfo;
 import org.apache.ignite.internal.metastorage.common.StatementInfo;
-import org.apache.ignite.internal.metastorage.common.StatementResultInfo;
 import org.apache.ignite.internal.metastorage.common.UpdateInfo;
 import org.apache.ignite.internal.metastorage.common.command.CompoundConditionInfo;
 import org.apache.ignite.internal.metastorage.common.command.CompoundConditionType;
@@ -46,9 +46,9 @@ import org.apache.ignite.internal.metastorage.common.command.GetAndRemoveCommand
 import org.apache.ignite.internal.metastorage.common.command.GetCommand;
 import org.apache.ignite.internal.metastorage.common.command.IfInfo;
 import org.apache.ignite.internal.metastorage.common.command.InvokeCommand;
+import org.apache.ignite.internal.metastorage.common.command.MetaStorageCommandsFactory;
 import org.apache.ignite.internal.metastorage.common.command.MultiInvokeCommand;
 import org.apache.ignite.internal.metastorage.common.command.MultipleEntryResponse;
-import org.apache.ignite.internal.metastorage.common.command.OperationInfo;
 import org.apache.ignite.internal.metastorage.common.command.PutAllCommand;
 import org.apache.ignite.internal.metastorage.common.command.PutCommand;
 import org.apache.ignite.internal.metastorage.common.command.RangeCommand;
@@ -92,6 +92,8 @@ import org.jetbrains.annotations.TestOnly;
  * TODO: IGNITE-14693 Implement Meta storage exception handling logic.
  */
 public class MetaStorageListener implements RaftGroupListener {
+    private final MetaStorageCommandsFactory commandsFactory = new MetaStorageCommandsFactory();
+
     /** Storage. */
     private final KeyValueStorage storage;
 
@@ -155,7 +157,7 @@ public class MetaStorageListener implements RaftGroupListener {
 
                 CursorMeta cursorDesc = cursors.get(cursorHasNextCmd.cursorId());
 
-                clo.result(!(cursorDesc == null) && cursorDesc.cursor().hasNext());
+                clo.result(cursorDesc != null && cursorDesc.cursor().hasNext());
             } else {
                 assert false : "Command was not found [cmd=" + command + ']';
             }
@@ -191,7 +193,7 @@ public class MetaStorageListener implements RaftGroupListener {
             } else if (command instanceof GetAndPutAllCommand) {
                 GetAndPutAllCommand getAndPutAllCmd = (GetAndPutAllCommand) command;
 
-                Collection<Entry> entries = storage.getAndPutAll(getAndPutAllCmd.keys(), getAndPutAllCmd.vals());
+                Collection<Entry> entries = storage.getAndPutAll(getAndPutAllCmd.keys(), getAndPutAllCmd.values());
 
                 List<SingleEntryResponse> resp = new ArrayList<>(entries.size());
 
@@ -245,15 +247,15 @@ public class MetaStorageListener implements RaftGroupListener {
 
                 StatementResult res = storage.invoke(toIf(cmd.iif()));
 
-                clo.result(new StatementResultInfo(res.bytes()));
+                clo.result(commandsFactory.statementResultInfo().result(res.bytes()).build());
             } else if (command instanceof RangeCommand) {
                 RangeCommand rangeCmd = (RangeCommand) command;
 
-                IgniteUuid cursorId = rangeCmd.getCursorId();
+                IgniteUuid cursorId = rangeCmd.cursorId();
 
                 Cursor<Entry> cursor = (rangeCmd.revUpperBound() != -1)
-                        ? storage.range(rangeCmd.keyFrom(), rangeCmd.keyTo(), rangeCmd.revUpperBound(), rangeCmd.includeTombstones()) :
-                        storage.range(rangeCmd.keyFrom(), rangeCmd.keyTo(), rangeCmd.includeTombstones());
+                        ? storage.range(rangeCmd.keyFrom(), rangeCmd.keyTo(), rangeCmd.revUpperBound(), rangeCmd.includeTombstones())
+                        : storage.range(rangeCmd.keyFrom(), rangeCmd.keyTo(), rangeCmd.includeTombstones());
 
                 cursors.put(
                         cursorId,
@@ -335,7 +337,7 @@ public class MetaStorageListener implements RaftGroupListener {
             } else if (command instanceof WatchRangeKeysCommand) {
                 WatchRangeKeysCommand watchCmd = (WatchRangeKeysCommand) command;
 
-                IgniteUuid cursorId = watchCmd.getCursorId();
+                IgniteUuid cursorId = watchCmd.cursorId();
 
                 Cursor<WatchEvent> cursor =
                         storage.watch(watchCmd.keyFrom(), watchCmd.keyTo(), watchCmd.revision());
@@ -354,7 +356,7 @@ public class MetaStorageListener implements RaftGroupListener {
             } else if (command instanceof WatchExactKeysCommand) {
                 WatchExactKeysCommand watchCmd = (WatchExactKeysCommand) command;
 
-                IgniteUuid cursorId = watchCmd.getCursorId();
+                IgniteUuid cursorId = watchCmd.cursorId();
 
                 Cursor<WatchEvent> cursor = storage.watch(watchCmd.keys(), watchCmd.revision());