You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by as...@apache.org on 2021/02/16 18:02:25 UTC

[ignite-3] branch ignite-14149 created (now f9d1a7b)

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

ascherbakov pushed a change to branch ignite-14149
in repository https://gitbox.apache.org/repos/asf/ignite-3.git.


      at f9d1a7b  IGNITE-14149 wip 2.

This branch includes the following new commits:

     new b01c23c  IGNITE-14149 wip.
     new f9c2ba4  Merge branch 'main' of https://gitbox.apache.org/repos/asf/ignite-3 into ignite-14149
     new 196bd82  IGNITE-14149 wip.
     new f9d1a7b  IGNITE-14149 wip 2.

The 4 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



[ignite-3] 03/04: IGNITE-14149 wip.

Posted by as...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 196bd82a87b720bdd4a1dac28ba607d6564d149a
Author: Alexey Scherbakov <al...@gmail.com>
AuthorDate: Tue Feb 16 18:06:33 2021 +0300

    IGNITE-14149 wip.
---
 modules/raft-client/pom.xml                        |  18 +-
 .../org/apache/ignite/raft/ElectionPriority.java   |  37 +++
 .../main/java/org/apache/ignite/raft/PeerId.java   |  78 ++++++
 .../main/java/org/apache/ignite/raft/State.java    | 286 +++++++++++++++++++++
 .../raft/client/RaftClientCommonMessages.java      | 259 +++++++++++++++++++
 .../ignite/raft/client/RaftGroupRpcClient.java     | 147 +++++++++++
 .../client/message/AddLearnersRequestImpl.java     |  37 +++
 .../raft/client/message/AddPeerRequestImpl.java    |  34 +++
 .../raft/client/message/AddPeerResponseImpl.java   |  35 +++
 .../raft/client/message/ChangePeerRequestImpl.java |  35 +++
 .../client/message/ChangePeersResponseImpl.java    |  35 +++
 .../message/ClientMessageBuilderFactory.java       |  46 ++++
 .../client/message/CreateGetLeaderRequestImpl.java |  23 ++
 .../message/CreateGetLeaderResponseImpl.java       |  22 ++
 .../raft/client/message/GetPeersRequestImpl.java   |  32 +++
 .../raft/client/message/GetPeersResponseImpl.java  |  35 +++
 .../client/message/LearnersOpResponseImpl.java     |  35 +++
 .../raft/client/message/PingRequestImpl.java       |  21 ++
 .../RaftClientCommonMessageBuilderFactory.java     |  86 +++++++
 .../client/message/RemoveLearnersRequestImpl.java  |  35 +++
 .../raft/client/message/RemovePeerRequestImpl.java |  33 +++
 .../client/message/RemovePeerResponseImpl.java     |  35 +++
 .../client/message/ResetLearnersRequestImpl.java   |  35 +++
 .../raft/client/message/ResetPeerRequestImpl.java  |  35 +++
 .../raft/client/message/SnapshotRequestImpl.java   |  22 ++
 .../raft/client/message/StatusResponseImpl.java    |  32 +++
 .../client/message/TransferLeaderRequestImpl.java  |  27 ++
 .../org/apache/ignite/raft/rpc/InvokeCallback.java |  24 ++
 .../java/org/apache/ignite/raft/rpc/Message.java   |   4 +
 .../main/java/org/apache/ignite/raft/rpc/Node.java |   7 +
 .../java/org/apache/ignite/raft/rpc/NodeImpl.java  |  48 ++++
 .../apache/ignite/raft/rpc/RaftGroupMessage.java   |   5 +
 .../java/org/apache/ignite/raft/rpc/RpcClient.java |  59 +++++
 .../ignite/raft/client/RaftGroupRpcClientTest.java |  21 ++
 34 files changed, 1720 insertions(+), 3 deletions(-)

diff --git a/modules/raft-client/pom.xml b/modules/raft-client/pom.xml
index 9286853..d2613d0 100644
--- a/modules/raft-client/pom.xml
+++ b/modules/raft-client/pom.xml
@@ -26,14 +26,26 @@
 
     <parent>
         <groupId>org.apache.ignite</groupId>
-        <artifactId>apache-ignite</artifactId>
-        <version>3.0.0-SNAPSHOT</version>
-        <relativePath>../..</relativePath>
+        <artifactId>ignite-parent</artifactId>
+        <version>1</version>
+        <relativePath>../../parent/pom.xml</relativePath>
     </parent>
 
     <artifactId>ignite-raft-client</artifactId>
+    <version>3.0.0-SNAPSHOT</version>
 
     <dependencies>
+        <dependency>
+            <groupId>org.junit.jupiter</groupId>
+            <artifactId>junit-jupiter-engine</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-core</artifactId>
+            <scope>test</scope>
+        </dependency>
+
     </dependencies>
 
     <build>
diff --git a/modules/raft-client/src/main/java/org/apache/ignite/raft/ElectionPriority.java b/modules/raft-client/src/main/java/org/apache/ignite/raft/ElectionPriority.java
new file mode 100644
index 0000000..376a589
--- /dev/null
+++ b/modules/raft-client/src/main/java/org/apache/ignite/raft/ElectionPriority.java
@@ -0,0 +1,37 @@
+/*
+ * 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.raft;
+
+/**
+ * Election Priority.
+ */
+public class ElectionPriority {
+    /**
+     * Priority -1 represents this node disabled the priority election function.
+     */
+    public static final int DISABLED = -1;
+
+    /**
+     * Priority 0 is a special value so that a node will never participate in election.
+     */
+    public static final int NOT_ELECTABLE = 0;
+
+    /**
+     * Priority 1 is a minimum value for priority election.
+     */
+    public static final int MIN_VALUE = 1;
+}
diff --git a/modules/raft-client/src/main/java/org/apache/ignite/raft/PeerId.java b/modules/raft-client/src/main/java/org/apache/ignite/raft/PeerId.java
new file mode 100644
index 0000000..56d96be
--- /dev/null
+++ b/modules/raft-client/src/main/java/org/apache/ignite/raft/PeerId.java
@@ -0,0 +1,78 @@
+/*
+ * 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.raft;
+
+import java.io.Serializable;
+import org.apache.ignite.raft.rpc.Node;
+
+/**
+ * Represents a participant in a replicating group.
+ */
+public class PeerId implements Serializable {
+    private static final long serialVersionUID = 8083529734784884641L;
+
+    /**
+     * Owning node.
+     */
+    private final Node node;
+
+    /**
+     * Node's local priority value, if node don't support priority election, this value is -1.
+     */
+    private final int priority;
+
+    public PeerId(PeerId peer) {
+        this.node = peer.getNode();
+        this.priority = peer.getPriority();
+    }
+
+    public PeerId(Node node) {
+        this(node, ElectionPriority.DISABLED);
+    }
+
+    public PeerId(final Node node, final int priority) {
+        super();
+        this.node = node;
+        this.priority = priority;
+    }
+
+    public Node getNode() {
+        return this.node;
+    }
+
+    public int getPriority() {
+        return priority;
+    }
+
+    @Override public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        PeerId peerId = (PeerId) o;
+
+        if (priority != peerId.priority) return false;
+        if (!node.equals(peerId.node)) return false;
+
+        return true;
+    }
+
+    @Override public int hashCode() {
+        int result = node.hashCode();
+        result = 31 * result + priority;
+        return result;
+    }
+}
diff --git a/modules/raft-client/src/main/java/org/apache/ignite/raft/State.java b/modules/raft-client/src/main/java/org/apache/ignite/raft/State.java
new file mode 100644
index 0000000..d924847
--- /dev/null
+++ b/modules/raft-client/src/main/java/org/apache/ignite/raft/State.java
@@ -0,0 +1,286 @@
+/*
+ * 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.raft;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Raft group state.
+ */
+public class State implements Iterable<PeerId> {
+    /** Mark a leaner peer */
+    private static final String LEARNER_POSTFIX = "/learner";
+
+    private PeerId leader;
+
+    private List<PeerId> peers = new ArrayList<>();
+
+    // use LinkedHashSet to keep insertion order.
+    private List<PeerId> learners = new ArrayList<>();
+
+    public State() {
+        super();
+    }
+
+    /**
+     * Construct a configuration instance with peers.
+     *
+     * @param conf configuration
+     */
+    public State(final Iterable<PeerId> conf) {
+        this(conf, null);
+    }
+
+    /**
+     * Construct a configuration from another conf.
+     *
+     * @param conf configuration
+     */
+    public State(final State conf) {
+        this(conf.getPeers(), conf.getLearners());
+    }
+
+    /**
+     * Construct a Configuration instance with peers and learners.
+     *
+     * @param conf     peers configuration
+     * @param learners learners
+     * @since 1.3.0
+     */
+    public State(final Iterable<PeerId> conf, final Iterable<PeerId> learners) {
+        for (final PeerId peer : conf) {
+            this.peers.add(new PeerId(peer));
+        }
+        addLearners(learners);
+    }
+
+    public PeerId getLeader() {
+        return leader;
+    }
+
+    public void setLeader(PeerId leader) {
+        this.leader = leader;
+    }
+
+    public void setLearners(final List<PeerId> learners) {
+        this.learners = learners;
+    }
+
+    /**
+     * Add a learner peer.
+     *
+     * @param learner learner to add
+     * @return true when add successfully.
+     */
+    public boolean addLearner(final PeerId learner) {
+        return this.learners.add(learner);
+    }
+
+    /**
+     * Add learners in batch, returns the added count.
+     *
+     * @param learners learners to add
+     * @return the total added count
+     */
+    public int addLearners(final Iterable<PeerId> learners) {
+        int ret = 0;
+        if (learners != null) {
+            for (final PeerId peer : learners) {
+                if (this.learners.add(new PeerId(peer))) {
+                    ret++;
+                }
+            }
+        }
+        return ret;
+    }
+
+    /**
+     * Remove a learner peer.
+     *
+     * @param learner learner to remove
+     * @return true when remove successfully.
+     */
+    public boolean removeLearner(final PeerId learner) {
+        return this.learners.remove(learner);
+    }
+
+    /**
+     * Retrieve the learners set.
+     *
+     * @return learners
+     */
+    public List<PeerId> getLearners() {
+        return this.learners;
+    }
+
+    /**
+     * Retrieve the learners set copy.
+     *
+     * @return learners
+     */
+    public List<PeerId> listLearners() {
+        return new ArrayList<>(this.learners);
+    }
+
+    /**
+     * Returns true when the configuration is valid.
+     *
+     * @return true if the configuration is valid.
+     */
+    public boolean isValid() {
+        final Set<PeerId> intersection = new HashSet<>(this.peers);
+        intersection.retainAll(this.learners);
+        return !this.peers.isEmpty() && intersection.isEmpty();
+    }
+
+    public void reset() {
+        this.peers.clear();
+        this.learners.clear();
+    }
+
+    public boolean isEmpty() {
+        return this.peers.isEmpty();
+    }
+
+    /**
+     * Returns the peers total number.
+     *
+     * @return total num of peers
+     */
+    public int size() {
+        return this.peers.size();
+    }
+
+    @Override
+    public Iterator<PeerId> iterator() {
+        return this.peers.iterator();
+    }
+
+    public Set<PeerId> getPeerSet() {
+        return new HashSet<>(this.peers);
+    }
+
+    public List<PeerId> listPeers() {
+        return new ArrayList<>(this.peers);
+    }
+
+    public List<PeerId> getPeers() {
+        return this.peers;
+    }
+
+    public void setPeers(final List<PeerId> peers) {
+        this.peers.clear();
+        for (final PeerId peer : peers) {
+            this.peers.add(new PeerId(peer));
+        }
+    }
+
+    public void appendPeers(final Collection<PeerId> set) {
+        this.peers.addAll(set);
+    }
+
+    public boolean addPeer(final PeerId peer) {
+        return this.peers.add(peer);
+    }
+
+    public boolean removePeer(final PeerId peer) {
+        return this.peers.remove(peer);
+    }
+
+    public boolean contains(final PeerId peer) {
+        return this.peers.contains(peer);
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((this.learners == null) ? 0 : this.learners.hashCode());
+        result = prime * result + ((this.peers == null) ? 0 : this.peers.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(final Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        State other = (State) obj;
+        if (this.learners == null) {
+            if (other.learners != null) {
+                return false;
+            }
+        } else if (!this.learners.equals(other.learners)) {
+            return false;
+        }
+        if (this.peers == null) {
+            return other.peers == null;
+        } else {
+            return this.peers.equals(other.peers);
+        }
+    }
+
+    @Override
+    public String toString() {
+        final StringBuilder sb = new StringBuilder();
+        final List<PeerId> peers = listPeers();
+        int i = 0;
+        int size = peers.size();
+        for (final PeerId peer : peers) {
+            sb.append(peer);
+            if (i < size - 1 || !this.learners.isEmpty()) {
+                sb.append(",");
+            }
+            i++;
+        }
+
+        size = this.learners.size();
+        i = 0;
+        for (final PeerId peer : this.learners) {
+            sb.append(peer).append(LEARNER_POSTFIX);
+            if (i < size - 1) {
+                sb.append(",");
+            }
+            i++;
+        }
+
+        return sb.toString();
+    }
+
+    /**
+     * Get the difference between |*this| and |rhs|
+     * |included| would be assigned to |*this| - |rhs|
+     * |excluded| would be assigned to |rhs| - |*this|
+     */
+    public void diff(final State rhs, final State included, final State excluded) {
+        included.peers = new ArrayList<>(this.peers);
+        included.peers.removeAll(rhs.peers);
+        excluded.peers = new ArrayList<>(rhs.peers);
+        excluded.peers.removeAll(this.peers);
+    }
+}
diff --git a/modules/raft-client/src/main/java/org/apache/ignite/raft/client/RaftClientCommonMessages.java b/modules/raft-client/src/main/java/org/apache/ignite/raft/client/RaftClientCommonMessages.java
new file mode 100644
index 0000000..150fe7d
--- /dev/null
+++ b/modules/raft-client/src/main/java/org/apache/ignite/raft/client/RaftClientCommonMessages.java
@@ -0,0 +1,259 @@
+/*
+ * 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.
+ */
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: cli.proto
+
+package org.apache.ignite.raft.client;
+
+import java.util.List;
+import org.apache.ignite.raft.PeerId;
+import org.apache.ignite.raft.rpc.Message;
+import org.apache.ignite.raft.rpc.RaftGroupMessage;
+
+/**
+ *
+ */
+public final class RaftClientCommonMessages {
+    private RaftClientCommonMessages() {
+    }
+
+    public interface StatusResponse extends Message {
+        int getStatusCode();
+
+        String getStatusMsg();
+
+        interface Builder {
+            Builder setStatusCode(int code);
+
+            Builder setStatusMsg(String msg);
+
+            StatusResponse build();
+        }
+    }
+
+    public interface PingRequest extends Message {
+        long getSendTimestamp();
+
+        interface Builder {
+            Builder setSendTimestamp(long timestamp);
+
+            PingRequest build();
+        }
+    }
+
+    public interface AddPeerRequest extends RaftGroupMessage {
+        PeerId getPeerId();
+
+        interface Builder {
+            Builder setGroupId(String groupId);
+
+            Builder setPeerId(PeerId peerId);
+
+            AddPeerRequest build();
+        }
+    }
+
+    public interface AddPeerResponse extends Message {
+        List<PeerId> getOldPeersList();
+
+        List<PeerId> getNewPeersList();
+
+        public interface Builder {
+            Builder addOldPeers(PeerId oldPeersId);
+
+            Builder addNewPeers(PeerId newPeersId);
+
+            AddPeerResponse build();
+        }
+    }
+
+    public interface RemovePeerRequest extends RaftGroupMessage {
+        PeerId getPeerId();
+
+        interface Builder {
+            Builder setGroupId(String groupId);
+
+            Builder setPeerId(PeerId peerId);
+
+            RemovePeerRequest build();
+        }
+    }
+
+    public interface RemovePeerResponse extends Message {
+        List<PeerId> getOldPeersList();
+
+        List<PeerId> getNewPeersList();
+
+        public interface Builder {
+            Builder addOldPeers(PeerId oldPeerId);
+
+            Builder addNewPeers(PeerId newPeerId);
+
+            RemovePeerResponse build();
+        }
+    }
+
+    public interface ChangePeersRequest extends RaftGroupMessage {
+        List<PeerId> getNewPeersList();
+
+        public interface Builder {
+            Builder setGroupId(String groupId);
+
+            Builder addNewPeers(PeerId peerId);
+
+            ChangePeersRequest build();
+        }
+    }
+
+    public interface ChangePeersResponse extends Message {
+        List<PeerId> getOldPeersList();
+
+        List<PeerId> getNewPeersList();
+
+        public interface Builder {
+            Builder addOldPeers(PeerId oldPeerId);
+
+            Builder addNewPeers(PeerId newPeerId);
+
+            ChangePeersResponse build();
+        }
+    }
+
+    public interface SnapshotRequest extends RaftGroupMessage {
+        public interface Builder {
+            Builder setGroupId(String groupId);
+
+            SnapshotRequest build();
+        }
+    }
+
+    public interface ResetPeerRequest extends RaftGroupMessage {
+        List<PeerId> getNewPeersList();
+
+        public interface Builder {
+            Builder setGroupId(String groupId);
+
+            Builder addNewPeers(PeerId peerId);
+
+            ResetPeerRequest build();
+        }
+    }
+
+    public interface TransferLeaderRequest extends RaftGroupMessage {
+        PeerId getPeerId();
+
+        public interface Builder {
+            Builder setGroupId(String groupId);
+
+            TransferLeaderRequest build();
+        }
+    }
+
+    public interface GetLeaderRequest extends RaftGroupMessage {
+        public interface Builder {
+            Builder setGroupId(String groupId);
+
+            GetLeaderRequest build();
+        }
+    }
+
+    public interface GetLeaderResponse extends Message {
+        String getLeaderId();
+
+        public interface Builder {
+            GetLeaderResponse build();
+
+            Builder setLeaderId(String leaderId);
+        }
+    }
+
+    public interface GetPeersRequest extends RaftGroupMessage {
+        boolean getOnlyAlive();
+
+        public interface Builder {
+            Builder setGroupId(String groupId);
+
+            Builder setOnlyAlive(boolean onlyGetAlive);
+
+            GetPeersRequest build();
+        }
+    }
+
+    public interface GetPeersResponse extends Message {
+        List<PeerId> getPeersList();
+
+        List<PeerId> getLearnersList();
+
+        public interface Builder {
+            Builder addPeers(PeerId peerId);
+
+            Builder addLearners(PeerId learnerId);
+
+            GetPeersResponse build();
+        }
+    }
+
+    public interface AddLearnersRequest extends RaftGroupMessage {
+        List<PeerId> getLearnersList();
+
+        public interface Builder {
+            Builder setGroupId(String groupId);
+
+            Builder addLearners(PeerId learnerId);
+
+            AddLearnersRequest build();
+        }
+    }
+
+    public interface RemoveLearnersRequest extends RaftGroupMessage {
+        List<PeerId> getLearnersList();
+
+        public interface Builder {
+            Builder setGroupId(String groupId);
+
+            Builder addLearners(PeerId leaderId);
+
+            RemoveLearnersRequest build();
+        }
+    }
+
+    public interface ResetLearnersRequest extends RaftGroupMessage {
+        List<PeerId> getLearnersList();
+
+        public interface Builder {
+            Builder setGroupId(String groupId);
+
+            Builder addLearners(PeerId learnerId);
+
+            ResetLearnersRequest build();
+        }
+    }
+
+    public interface LearnersOpResponse extends Message {
+        List<PeerId> getOldLearnersList();
+
+        List<PeerId> getNewLearnersList();
+
+        public interface Builder {
+            Builder addOldLearners(PeerId oldLearnersId);
+
+            Builder addNewLearners(PeerId newLearnersId);
+
+            LearnersOpResponse build();
+        }
+    }
+}
diff --git a/modules/raft-client/src/main/java/org/apache/ignite/raft/client/RaftGroupRpcClient.java b/modules/raft-client/src/main/java/org/apache/ignite/raft/client/RaftGroupRpcClient.java
new file mode 100644
index 0000000..f0910d0
--- /dev/null
+++ b/modules/raft-client/src/main/java/org/apache/ignite/raft/client/RaftGroupRpcClient.java
@@ -0,0 +1,147 @@
+/*
+ * 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.raft.client;
+
+import java.util.concurrent.Future;
+import org.apache.ignite.raft.State;
+import org.apache.ignite.raft.PeerId;
+import org.apache.ignite.raft.rpc.Message;
+import org.apache.ignite.raft.rpc.RaftGroupMessage;
+
+import static org.apache.ignite.raft.client.RaftClientCommonMessages.AddLearnersRequest;
+import static org.apache.ignite.raft.client.RaftClientCommonMessages.AddPeerRequest;
+import static org.apache.ignite.raft.client.RaftClientCommonMessages.AddPeerResponse;
+import static org.apache.ignite.raft.client.RaftClientCommonMessages.ChangePeersRequest;
+import static org.apache.ignite.raft.client.RaftClientCommonMessages.ChangePeersResponse;
+import static org.apache.ignite.raft.client.RaftClientCommonMessages.LearnersOpResponse;
+import static org.apache.ignite.raft.client.RaftClientCommonMessages.RemoveLearnersRequest;
+import static org.apache.ignite.raft.client.RaftClientCommonMessages.RemovePeerRequest;
+import static org.apache.ignite.raft.client.RaftClientCommonMessages.RemovePeerResponse;
+import static org.apache.ignite.raft.client.RaftClientCommonMessages.ResetLearnersRequest;
+import static org.apache.ignite.raft.client.RaftClientCommonMessages.ResetPeerRequest;
+import static org.apache.ignite.raft.client.RaftClientCommonMessages.SnapshotRequest;
+import static org.apache.ignite.raft.client.RaftClientCommonMessages.StatusResponse;
+import static org.apache.ignite.raft.client.RaftClientCommonMessages.TransferLeaderRequest;
+
+/**
+ * Raft group RPC client.
+ */
+public interface RaftGroupRpcClient {
+    /**
+     * @param groupId Group id.
+     * @param refresh Refresh state.
+     * @return Current group state.
+     */
+    State state(String groupId, boolean refresh);
+
+    /**
+     * Adds a voring peer to the raft group.
+     *
+     * @param request   request data
+     * @return A future with the result
+     */
+    Future<AddPeerResponse> addPeer(AddPeerRequest request);
+
+    /**
+     * Removes a peer from the raft group.
+     *
+     * @param endpoint  server address
+     * @param request   request data
+     * @param done      callback
+     * @return a future with result
+     */
+    Future<RemovePeerResponse> removePeer(RemovePeerRequest request);
+
+    /**
+     * Locally resets raft group peers. Intended for recovering from a group unavailability at the price of consistency.
+     *
+     * @param peerId Node to execute the configuration reset.
+     * @param request   request data
+     * @return A future with result.
+     */
+    Future<StatusResponse> resetPeers(PeerId peerId, ResetPeerRequest request);
+
+    /**
+     * Takes a local snapshot.
+     *
+     * @param peerId  Peer id.
+     * @param request   request data
+     * @param done      callback
+     * @return a future with result
+     */
+    Future<StatusResponse> snapshot(PeerId peerId, SnapshotRequest request);
+
+    /**
+     * Change peers.
+     *
+     * @param endpoint  server address
+     * @param request   request data
+     * @param done      callback
+     * @return a future with result
+     */
+    Future<ChangePeersResponse> changePeers(ChangePeersRequest request);
+
+    /**
+     * Adds learners.
+     *
+     * @param endpoint  server address
+     * @param request   request data
+     * @param done      callback
+     * @return a future with result
+     */
+    Future<LearnersOpResponse> addLearners(AddLearnersRequest request);
+
+    /**
+     * Removes learners.
+     *
+     * @param endpoint  server address
+     * @param request   request data
+     * @param done      callback
+     * @return a future with result
+     */
+    Future<LearnersOpResponse> removeLearners(RemoveLearnersRequest request);
+
+    /**
+     * Resets learners to new set.
+     *
+     * @param endpoint  server address
+     * @param request   request data
+     * @param done      callback
+     * @return a future with result
+     */
+    Future<LearnersOpResponse> resetLearners(ResetLearnersRequest request);
+
+    /**
+     * Transfer leadership to other peer.
+     *
+     * @param endpoint  server address
+     * @param request   request data
+     * @param done      callback
+     * @return a future with result
+     */
+    Future<StatusResponse> transferLeader(TransferLeaderRequest request);
+
+    /**
+     * Performs a custom action defined by specific request on the raft group leader.
+     *
+     * @param endpoint  server address
+     * @param request   request data
+     * @param done      callback
+     * @return a future with result
+     */
+    <R extends Message> Future<R> sendCustom(RaftGroupMessage request);
+}
diff --git a/modules/raft-client/src/main/java/org/apache/ignite/raft/client/message/AddLearnersRequestImpl.java b/modules/raft-client/src/main/java/org/apache/ignite/raft/client/message/AddLearnersRequestImpl.java
new file mode 100644
index 0000000..cc3a763
--- /dev/null
+++ b/modules/raft-client/src/main/java/org/apache/ignite/raft/client/message/AddLearnersRequestImpl.java
@@ -0,0 +1,37 @@
+package org.apache.ignite.raft.client.message;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.ignite.raft.PeerId;
+import org.apache.ignite.raft.client.RaftClientCommonMessages;
+
+public class AddLearnersRequestImpl implements RaftClientCommonMessages.AddLearnersRequest, RaftClientCommonMessages.AddLearnersRequest.Builder {
+    private String groupId;
+    private PeerId leaderId;
+    private List<PeerId> learnersList = new ArrayList<>();
+
+    @Override public String getGroupId() {
+        return groupId;
+    }
+
+    @Override public List<PeerId> getLearnersList() {
+        return learnersList;
+    }
+
+    @Override public Builder setGroupId(String groupId) {
+        this.groupId = groupId;
+
+        return this;
+    }
+
+
+    @Override public Builder addLearners(PeerId learnerId) {
+        learnersList.add(learnerId);
+
+        return this;
+    }
+
+    @Override public RaftClientCommonMessages.AddLearnersRequest build() {
+        return this;
+    }
+}
diff --git a/modules/raft-client/src/main/java/org/apache/ignite/raft/client/message/AddPeerRequestImpl.java b/modules/raft-client/src/main/java/org/apache/ignite/raft/client/message/AddPeerRequestImpl.java
new file mode 100644
index 0000000..01fb298
--- /dev/null
+++ b/modules/raft-client/src/main/java/org/apache/ignite/raft/client/message/AddPeerRequestImpl.java
@@ -0,0 +1,34 @@
+package org.apache.ignite.raft.client.message;
+
+import org.apache.ignite.raft.PeerId;
+import org.apache.ignite.raft.client.RaftClientCommonMessages;
+
+class AddPeerRequestImpl implements RaftClientCommonMessages.AddPeerRequest, RaftClientCommonMessages.AddPeerRequest.Builder {
+    private String groupId;
+    private PeerId leaderId;
+    private PeerId peerId;
+
+    @Override public String getGroupId() {
+        return groupId;
+    }
+
+    @Override public PeerId getPeerId() {
+        return peerId;
+    }
+
+    @Override public Builder setGroupId(String groupId) {
+        this.groupId = groupId;
+
+        return this;
+    }
+
+    @Override public Builder setPeerId(PeerId peerId) {
+        this.peerId = peerId;
+
+        return this;
+    }
+
+    @Override public RaftClientCommonMessages.AddPeerRequest build() {
+        return this;
+    }
+}
diff --git a/modules/raft-client/src/main/java/org/apache/ignite/raft/client/message/AddPeerResponseImpl.java b/modules/raft-client/src/main/java/org/apache/ignite/raft/client/message/AddPeerResponseImpl.java
new file mode 100644
index 0000000..127124a
--- /dev/null
+++ b/modules/raft-client/src/main/java/org/apache/ignite/raft/client/message/AddPeerResponseImpl.java
@@ -0,0 +1,35 @@
+package org.apache.ignite.raft.client.message;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.ignite.raft.PeerId;
+import org.apache.ignite.raft.client.RaftClientCommonMessages;
+
+class AddPeerResponseImpl implements RaftClientCommonMessages.AddPeerResponse, RaftClientCommonMessages.AddPeerResponse.Builder {
+    private List<PeerId> oldPeersList = new ArrayList<>();
+    private List<PeerId> newPeersList = new ArrayList<>();
+
+    @Override public List<PeerId> getOldPeersList() {
+        return oldPeersList;
+    }
+
+    @Override public List<PeerId> getNewPeersList() {
+        return newPeersList;
+    }
+
+    @Override public Builder addOldPeers(PeerId oldPeersId) {
+        oldPeersList.add(oldPeersId);
+
+        return this;
+    }
+
+    @Override public Builder addNewPeers(PeerId newPeersId) {
+        newPeersList.add(newPeersId);
+
+        return this;
+    }
+
+    @Override public RaftClientCommonMessages.AddPeerResponse build() {
+        return this;
+    }
+}
diff --git a/modules/raft-client/src/main/java/org/apache/ignite/raft/client/message/ChangePeerRequestImpl.java b/modules/raft-client/src/main/java/org/apache/ignite/raft/client/message/ChangePeerRequestImpl.java
new file mode 100644
index 0000000..06570ea
--- /dev/null
+++ b/modules/raft-client/src/main/java/org/apache/ignite/raft/client/message/ChangePeerRequestImpl.java
@@ -0,0 +1,35 @@
+package org.apache.ignite.raft.client.message;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.ignite.raft.PeerId;
+import org.apache.ignite.raft.client.RaftClientCommonMessages;
+
+class ChangePeerRequestImpl implements RaftClientCommonMessages.ChangePeersRequest, RaftClientCommonMessages.ChangePeersRequest.Builder {
+    private String groupId;
+    private List<PeerId> newPeersList = new ArrayList<>();
+
+    @Override public String getGroupId() {
+        return groupId;
+    }
+
+    @Override public List<PeerId> getNewPeersList() {
+        return newPeersList;
+    }
+
+    @Override public Builder setGroupId(String groupId) {
+        this.groupId = groupId;
+
+        return this;
+    }
+
+    @Override public Builder addNewPeers(PeerId peerId) {
+        newPeersList.add(peerId);
+
+        return this;
+    }
+
+    @Override public RaftClientCommonMessages.ChangePeersRequest build() {
+        return this;
+    }
+}
diff --git a/modules/raft-client/src/main/java/org/apache/ignite/raft/client/message/ChangePeersResponseImpl.java b/modules/raft-client/src/main/java/org/apache/ignite/raft/client/message/ChangePeersResponseImpl.java
new file mode 100644
index 0000000..d22d8f0
--- /dev/null
+++ b/modules/raft-client/src/main/java/org/apache/ignite/raft/client/message/ChangePeersResponseImpl.java
@@ -0,0 +1,35 @@
+package org.apache.ignite.raft.client.message;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.ignite.raft.PeerId;
+import org.apache.ignite.raft.client.RaftClientCommonMessages;
+
+class ChangePeersResponseImpl implements RaftClientCommonMessages.ChangePeersResponse, RaftClientCommonMessages.ChangePeersResponse.Builder {
+    private List<PeerId> oldPeersList = new ArrayList<>();
+    private List<PeerId> newPeersList = new ArrayList<>();
+
+    @Override public List<PeerId> getOldPeersList() {
+        return oldPeersList;
+    }
+
+    @Override public List<PeerId> getNewPeersList() {
+        return newPeersList;
+    }
+
+    @Override public Builder addOldPeers(PeerId oldPeerId) {
+        oldPeersList.add(oldPeerId);
+
+        return this;
+    }
+
+    @Override public Builder addNewPeers(PeerId newPeerId) {
+        newPeersList.add(newPeerId);
+
+        return this;
+    }
+
+    @Override public RaftClientCommonMessages.ChangePeersResponse build() {
+        return this;
+    }
+}
diff --git a/modules/raft-client/src/main/java/org/apache/ignite/raft/client/message/ClientMessageBuilderFactory.java b/modules/raft-client/src/main/java/org/apache/ignite/raft/client/message/ClientMessageBuilderFactory.java
new file mode 100644
index 0000000..952fbfd
--- /dev/null
+++ b/modules/raft-client/src/main/java/org/apache/ignite/raft/client/message/ClientMessageBuilderFactory.java
@@ -0,0 +1,46 @@
+package org.apache.ignite.raft.client.message;
+
+import org.apache.ignite.raft.client.RaftClientCommonMessages;
+
+/** */
+public interface ClientMessageBuilderFactory {
+    public static ClientMessageBuilderFactory DEFAULT = new RaftClientCommonMessageBuilderFactory();
+
+    RaftClientCommonMessages.PingRequest.Builder createPingRequest();
+
+    RaftClientCommonMessages.StatusResponse.Builder createStatusResponse();
+
+    RaftClientCommonMessages.AddPeerRequest.Builder createAddPeerRequest();
+
+    RaftClientCommonMessages.AddPeerResponse.Builder createAddPeerResponse();
+
+    RaftClientCommonMessages.RemovePeerRequest.Builder createRemovePeerRequest();
+
+    RaftClientCommonMessages.RemovePeerResponse.Builder createRemovePeerResponse();
+
+    RaftClientCommonMessages.ChangePeersRequest.Builder createChangePeerRequest();
+
+    RaftClientCommonMessages.ChangePeersResponse.Builder createChangePeerResponse();
+
+    RaftClientCommonMessages.SnapshotRequest.Builder createSnapshotRequest();
+
+    RaftClientCommonMessages.ResetPeerRequest.Builder createResetPeerRequest();
+
+    RaftClientCommonMessages.TransferLeaderRequest.Builder createTransferLeaderRequest();
+
+    RaftClientCommonMessages.GetLeaderRequest.Builder createGetLeaderRequest();
+
+    RaftClientCommonMessages.GetLeaderResponse.Builder createGetLeaderResponse();
+
+    RaftClientCommonMessages.GetPeersRequest.Builder createGetPeersRequest();
+
+    RaftClientCommonMessages.GetPeersResponse.Builder createGetPeersResponse();
+
+    RaftClientCommonMessages.AddLearnersRequest.Builder createAddLearnersRequest();
+
+    RaftClientCommonMessages.RemoveLearnersRequest.Builder createRemoveLearnersRequest();
+
+    RaftClientCommonMessages.ResetLearnersRequest.Builder createResetLearnersRequest();
+
+    RaftClientCommonMessages.LearnersOpResponse.Builder createLearnersOpResponse();
+}
diff --git a/modules/raft-client/src/main/java/org/apache/ignite/raft/client/message/CreateGetLeaderRequestImpl.java b/modules/raft-client/src/main/java/org/apache/ignite/raft/client/message/CreateGetLeaderRequestImpl.java
new file mode 100644
index 0000000..9c44e11
--- /dev/null
+++ b/modules/raft-client/src/main/java/org/apache/ignite/raft/client/message/CreateGetLeaderRequestImpl.java
@@ -0,0 +1,23 @@
+package org.apache.ignite.raft.client.message;
+
+
+import org.apache.ignite.raft.PeerId;
+import org.apache.ignite.raft.client.RaftClientCommonMessages;
+
+public class CreateGetLeaderRequestImpl implements RaftClientCommonMessages.GetLeaderRequest, RaftClientCommonMessages.GetLeaderRequest.Builder {
+    private String groupId;
+
+    @Override public String getGroupId() {
+        return groupId;
+    }
+
+    @Override public Builder setGroupId(String groupId) {
+        this.groupId = groupId;
+
+        return this;
+    }
+
+    @Override public RaftClientCommonMessages.GetLeaderRequest build() {
+        return this;
+    }
+}
diff --git a/modules/raft-client/src/main/java/org/apache/ignite/raft/client/message/CreateGetLeaderResponseImpl.java b/modules/raft-client/src/main/java/org/apache/ignite/raft/client/message/CreateGetLeaderResponseImpl.java
new file mode 100644
index 0000000..5b58d48
--- /dev/null
+++ b/modules/raft-client/src/main/java/org/apache/ignite/raft/client/message/CreateGetLeaderResponseImpl.java
@@ -0,0 +1,22 @@
+package org.apache.ignite.raft.client.message;
+
+
+import org.apache.ignite.raft.client.RaftClientCommonMessages;
+
+public class CreateGetLeaderResponseImpl implements RaftClientCommonMessages.GetLeaderResponse, RaftClientCommonMessages.GetLeaderResponse.Builder {
+    private String leaderId;
+
+    @Override public String getLeaderId() {
+        return leaderId;
+    }
+
+    @Override public RaftClientCommonMessages.GetLeaderResponse build() {
+        return this;
+    }
+
+    @Override public Builder setLeaderId(String leaderId) {
+        this.leaderId = leaderId;
+
+        return this;
+    }
+}
diff --git a/modules/raft-client/src/main/java/org/apache/ignite/raft/client/message/GetPeersRequestImpl.java b/modules/raft-client/src/main/java/org/apache/ignite/raft/client/message/GetPeersRequestImpl.java
new file mode 100644
index 0000000..1851152
--- /dev/null
+++ b/modules/raft-client/src/main/java/org/apache/ignite/raft/client/message/GetPeersRequestImpl.java
@@ -0,0 +1,32 @@
+package org.apache.ignite.raft.client.message;
+
+import org.apache.ignite.raft.client.RaftClientCommonMessages;
+
+class GetPeersRequestImpl implements RaftClientCommonMessages.GetPeersRequest, RaftClientCommonMessages.GetPeersRequest.Builder {
+    private String groupId;
+    private boolean onlyAlive;
+
+    @Override public String getGroupId() {
+        return groupId;
+    }
+
+    @Override public boolean getOnlyAlive() {
+        return onlyAlive;
+    }
+
+    @Override public Builder setGroupId(String groupId) {
+        this.groupId = groupId;
+
+        return this;
+    }
+
+    @Override public Builder setOnlyAlive(boolean onlyGetAlive) {
+        this.onlyAlive = onlyGetAlive;
+
+        return this;
+    }
+
+    @Override public RaftClientCommonMessages.GetPeersRequest build() {
+        return this;
+    }
+}
diff --git a/modules/raft-client/src/main/java/org/apache/ignite/raft/client/message/GetPeersResponseImpl.java b/modules/raft-client/src/main/java/org/apache/ignite/raft/client/message/GetPeersResponseImpl.java
new file mode 100644
index 0000000..37a4912
--- /dev/null
+++ b/modules/raft-client/src/main/java/org/apache/ignite/raft/client/message/GetPeersResponseImpl.java
@@ -0,0 +1,35 @@
+package org.apache.ignite.raft.client.message;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.ignite.raft.PeerId;
+import org.apache.ignite.raft.client.RaftClientCommonMessages;
+
+class GetPeersResponseImpl implements RaftClientCommonMessages.GetPeersResponse, RaftClientCommonMessages.GetPeersResponse.Builder {
+    private List<PeerId> peersList = new ArrayList<>();
+    private List<PeerId> learnersList = new ArrayList<>();
+
+    @Override public List<PeerId> getPeersList() {
+        return peersList;
+    }
+
+    @Override public List<PeerId> getLearnersList() {
+        return learnersList;
+    }
+
+    @Override public Builder addPeers(PeerId peerId) {
+        peersList.add(peerId);
+
+        return this;
+    }
+
+    @Override public Builder addLearners(PeerId learnerId) {
+        learnersList.add(learnerId);
+
+        return this;
+    }
+
+    @Override public RaftClientCommonMessages.GetPeersResponse build() {
+        return this;
+    }
+}
diff --git a/modules/raft-client/src/main/java/org/apache/ignite/raft/client/message/LearnersOpResponseImpl.java b/modules/raft-client/src/main/java/org/apache/ignite/raft/client/message/LearnersOpResponseImpl.java
new file mode 100644
index 0000000..4c3f4c1
--- /dev/null
+++ b/modules/raft-client/src/main/java/org/apache/ignite/raft/client/message/LearnersOpResponseImpl.java
@@ -0,0 +1,35 @@
+package org.apache.ignite.raft.client.message;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.ignite.raft.PeerId;
+import org.apache.ignite.raft.client.RaftClientCommonMessages;
+
+class LearnersOpResponseImpl implements RaftClientCommonMessages.LearnersOpResponse, RaftClientCommonMessages.LearnersOpResponse.Builder {
+    private List<PeerId> oldLearnersList = new ArrayList<>();
+    private List<PeerId> newLearnersList = new ArrayList<>();
+
+    @Override public List<PeerId> getOldLearnersList() {
+        return oldLearnersList;
+    }
+
+    @Override public List<PeerId> getNewLearnersList() {
+        return newLearnersList;
+    }
+
+    @Override public Builder addOldLearners(PeerId oldLearnersId) {
+        oldLearnersList.add(oldLearnersId);
+
+        return this;
+    }
+
+    @Override public Builder addNewLearners(PeerId newLearnersId) {
+        newLearnersList.add(newLearnersId);
+
+        return this;
+    }
+
+    @Override public RaftClientCommonMessages.LearnersOpResponse build() {
+        return this;
+    }
+}
diff --git a/modules/raft-client/src/main/java/org/apache/ignite/raft/client/message/PingRequestImpl.java b/modules/raft-client/src/main/java/org/apache/ignite/raft/client/message/PingRequestImpl.java
new file mode 100644
index 0000000..d4ad03d
--- /dev/null
+++ b/modules/raft-client/src/main/java/org/apache/ignite/raft/client/message/PingRequestImpl.java
@@ -0,0 +1,21 @@
+package org.apache.ignite.raft.client.message;
+
+import org.apache.ignite.raft.client.RaftClientCommonMessages;
+
+class PingRequestImpl implements RaftClientCommonMessages.PingRequest, RaftClientCommonMessages.PingRequest.Builder {
+    private long sendTimestamp;
+
+    @Override public long getSendTimestamp() {
+        return sendTimestamp;
+    }
+
+    @Override public Builder setSendTimestamp(long timestamp) {
+        this.sendTimestamp = timestamp;
+
+        return this;
+    }
+
+    @Override public RaftClientCommonMessages.PingRequest build() {
+        return this;
+    }
+}
diff --git a/modules/raft-client/src/main/java/org/apache/ignite/raft/client/message/RaftClientCommonMessageBuilderFactory.java b/modules/raft-client/src/main/java/org/apache/ignite/raft/client/message/RaftClientCommonMessageBuilderFactory.java
new file mode 100644
index 0000000..f54ec48
--- /dev/null
+++ b/modules/raft-client/src/main/java/org/apache/ignite/raft/client/message/RaftClientCommonMessageBuilderFactory.java
@@ -0,0 +1,86 @@
+package org.apache.ignite.raft.client.message;
+
+import org.apache.ignite.raft.client.RaftClientCommonMessages;
+
+/**
+ * Raft client message builders factory.
+ */
+public class RaftClientCommonMessageBuilderFactory implements ClientMessageBuilderFactory {
+    public static RaftClientCommonMessageBuilderFactory DEFAULT = new RaftClientCommonMessageBuilderFactory();
+
+    @Override public RaftClientCommonMessages.PingRequest.Builder createPingRequest() {
+        return new PingRequestImpl();
+    }
+
+    @Override public RaftClientCommonMessages.StatusResponse.Builder createStatusResponse() {
+        return new StatusResponseImpl();
+    }
+
+    @Override public RaftClientCommonMessages.AddPeerRequest.Builder createAddPeerRequest() {
+        return new AddPeerRequestImpl();
+    }
+
+    @Override public RaftClientCommonMessages.AddPeerResponse.Builder createAddPeerResponse() {
+        return new AddPeerResponseImpl();
+    }
+
+    @Override public RaftClientCommonMessages.RemovePeerRequest.Builder createRemovePeerRequest() {
+        return new RemovePeerRequestImpl();
+    }
+
+    @Override public RaftClientCommonMessages.RemovePeerResponse.Builder createRemovePeerResponse() {
+        return new RemovePeerResponseImpl();
+    }
+
+    @Override public RaftClientCommonMessages.ChangePeersRequest.Builder createChangePeerRequest() {
+        return new ChangePeerRequestImpl();
+    }
+
+    @Override public RaftClientCommonMessages.ChangePeersResponse.Builder createChangePeerResponse() {
+        return new ChangePeersResponseImpl();
+    }
+
+    @Override public RaftClientCommonMessages.SnapshotRequest.Builder createSnapshotRequest() {
+        return new SnapshotRequestImpl();
+    }
+
+    @Override public RaftClientCommonMessages.ResetPeerRequest.Builder createResetPeerRequest() {
+        return new ResetPeerRequestImpl();
+    }
+
+    @Override public RaftClientCommonMessages.TransferLeaderRequest.Builder createTransferLeaderRequest() {
+        return new TransferLeaderRequestImpl();
+    }
+
+    @Override public RaftClientCommonMessages.GetLeaderRequest.Builder createGetLeaderRequest() {
+        return new CreateGetLeaderRequestImpl();
+    }
+
+    @Override public RaftClientCommonMessages.GetLeaderResponse.Builder createGetLeaderResponse() {
+        return new CreateGetLeaderResponseImpl();
+    }
+
+    @Override public RaftClientCommonMessages.GetPeersRequest.Builder createGetPeersRequest() {
+        return new GetPeersRequestImpl();
+    }
+
+    @Override public RaftClientCommonMessages.GetPeersResponse.Builder createGetPeersResponse() {
+        return new GetPeersResponseImpl();
+    }
+
+    @Override public RaftClientCommonMessages.AddLearnersRequest.Builder createAddLearnersRequest() {
+        return new AddLearnersRequestImpl();
+    }
+
+    @Override public RaftClientCommonMessages.RemoveLearnersRequest.Builder createRemoveLearnersRequest() {
+        return new RemoveLearnersRequestImpl();
+    }
+
+    @Override public RaftClientCommonMessages.ResetLearnersRequest.Builder createResetLearnersRequest() {
+        return new ResetLearnersRequestImpl();
+    }
+
+    @Override public RaftClientCommonMessages.LearnersOpResponse.Builder createLearnersOpResponse() {
+        return new LearnersOpResponseImpl();
+    }
+}
diff --git a/modules/raft-client/src/main/java/org/apache/ignite/raft/client/message/RemoveLearnersRequestImpl.java b/modules/raft-client/src/main/java/org/apache/ignite/raft/client/message/RemoveLearnersRequestImpl.java
new file mode 100644
index 0000000..de0b056
--- /dev/null
+++ b/modules/raft-client/src/main/java/org/apache/ignite/raft/client/message/RemoveLearnersRequestImpl.java
@@ -0,0 +1,35 @@
+package org.apache.ignite.raft.client.message;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.ignite.raft.PeerId;
+import org.apache.ignite.raft.client.RaftClientCommonMessages;
+
+class RemoveLearnersRequestImpl implements RaftClientCommonMessages.RemoveLearnersRequest, RaftClientCommonMessages.RemoveLearnersRequest.Builder {
+    private String groupId;
+    private List<PeerId> learnersList = new ArrayList<>();
+
+    @Override public String getGroupId() {
+        return groupId;
+    }
+
+    @Override public List<PeerId> getLearnersList() {
+        return learnersList;
+    }
+
+    @Override public Builder setGroupId(String groupId) {
+        this.groupId = groupId;
+
+        return this;
+    }
+
+    @Override public Builder addLearners(PeerId learnerId) {
+        learnersList.add(learnerId);
+
+        return this;
+    }
+
+    @Override public RaftClientCommonMessages.RemoveLearnersRequest build() {
+        return this;
+    }
+}
diff --git a/modules/raft-client/src/main/java/org/apache/ignite/raft/client/message/RemovePeerRequestImpl.java b/modules/raft-client/src/main/java/org/apache/ignite/raft/client/message/RemovePeerRequestImpl.java
new file mode 100644
index 0000000..a068f1d
--- /dev/null
+++ b/modules/raft-client/src/main/java/org/apache/ignite/raft/client/message/RemovePeerRequestImpl.java
@@ -0,0 +1,33 @@
+package org.apache.ignite.raft.client.message;
+
+import org.apache.ignite.raft.PeerId;
+import org.apache.ignite.raft.client.RaftClientCommonMessages;
+
+class RemovePeerRequestImpl implements RaftClientCommonMessages.RemovePeerRequest, RaftClientCommonMessages.RemovePeerRequest.Builder {
+    private String groupId;
+    private PeerId peerId;
+
+    @Override public String getGroupId() {
+        return groupId;
+    }
+
+    @Override public PeerId getPeerId() {
+        return peerId;
+    }
+
+    @Override public Builder setGroupId(String groupId) {
+        this.groupId = groupId;
+
+        return this;
+    }
+
+    @Override public Builder setPeerId(PeerId peerId) {
+        this.peerId = peerId;
+
+        return this;
+    }
+
+    @Override public RaftClientCommonMessages.RemovePeerRequest build() {
+        return this;
+    }
+}
diff --git a/modules/raft-client/src/main/java/org/apache/ignite/raft/client/message/RemovePeerResponseImpl.java b/modules/raft-client/src/main/java/org/apache/ignite/raft/client/message/RemovePeerResponseImpl.java
new file mode 100644
index 0000000..35d9013
--- /dev/null
+++ b/modules/raft-client/src/main/java/org/apache/ignite/raft/client/message/RemovePeerResponseImpl.java
@@ -0,0 +1,35 @@
+package org.apache.ignite.raft.client.message;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.ignite.raft.PeerId;
+import org.apache.ignite.raft.client.RaftClientCommonMessages;
+
+class RemovePeerResponseImpl implements RaftClientCommonMessages.RemovePeerResponse, RaftClientCommonMessages.RemovePeerResponse.Builder {
+    private List<PeerId> oldPeersList = new ArrayList<>();
+    private List<PeerId> newPeersList = new ArrayList<>();
+
+    @Override public List<PeerId> getOldPeersList() {
+        return oldPeersList;
+    }
+
+    @Override public List<PeerId> getNewPeersList() {
+        return newPeersList;
+    }
+
+    @Override public Builder addOldPeers(PeerId oldPeerId) {
+        oldPeersList.add(oldPeerId);
+
+        return this;
+    }
+
+    @Override public Builder addNewPeers(PeerId newPeerId) {
+        newPeersList.add(newPeerId);
+
+        return this;
+    }
+
+    @Override public RaftClientCommonMessages.RemovePeerResponse build() {
+        return this;
+    }
+}
diff --git a/modules/raft-client/src/main/java/org/apache/ignite/raft/client/message/ResetLearnersRequestImpl.java b/modules/raft-client/src/main/java/org/apache/ignite/raft/client/message/ResetLearnersRequestImpl.java
new file mode 100644
index 0000000..1e5188d
--- /dev/null
+++ b/modules/raft-client/src/main/java/org/apache/ignite/raft/client/message/ResetLearnersRequestImpl.java
@@ -0,0 +1,35 @@
+package org.apache.ignite.raft.client.message;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.ignite.raft.PeerId;
+import org.apache.ignite.raft.client.RaftClientCommonMessages;
+
+class ResetLearnersRequestImpl implements RaftClientCommonMessages.ResetLearnersRequest, RaftClientCommonMessages.ResetLearnersRequest.Builder {
+    private String groupId;
+    private List<PeerId> learnersList = new ArrayList<>();
+
+    @Override public String getGroupId() {
+        return groupId;
+    }
+
+    @Override public List<PeerId> getLearnersList() {
+        return learnersList;
+    }
+
+    @Override public Builder setGroupId(String groupId) {
+        this.groupId = groupId;
+
+        return this;
+    }
+
+    @Override public Builder addLearners(PeerId learnerId) {
+        learnersList.add(learnerId);
+
+        return this;
+    }
+
+    @Override public RaftClientCommonMessages.ResetLearnersRequest build() {
+        return this;
+    }
+}
diff --git a/modules/raft-client/src/main/java/org/apache/ignite/raft/client/message/ResetPeerRequestImpl.java b/modules/raft-client/src/main/java/org/apache/ignite/raft/client/message/ResetPeerRequestImpl.java
new file mode 100644
index 0000000..bb9c28b
--- /dev/null
+++ b/modules/raft-client/src/main/java/org/apache/ignite/raft/client/message/ResetPeerRequestImpl.java
@@ -0,0 +1,35 @@
+package org.apache.ignite.raft.client.message;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.ignite.raft.PeerId;
+import org.apache.ignite.raft.client.RaftClientCommonMessages;
+
+class ResetPeerRequestImpl implements RaftClientCommonMessages.ResetPeerRequest, RaftClientCommonMessages.ResetPeerRequest.Builder {
+    private String groupId;
+    private List<PeerId> newPeersList = new ArrayList<>();
+
+    @Override public String getGroupId() {
+        return groupId;
+    }
+
+    @Override public List<PeerId> getNewPeersList() {
+        return newPeersList;
+    }
+
+    @Override public Builder setGroupId(String groupId) {
+        this.groupId = groupId;
+
+        return this;
+    }
+
+    @Override public Builder addNewPeers(PeerId peerId) {
+        newPeersList.add(peerId);
+
+        return this;
+    }
+
+    @Override public RaftClientCommonMessages.ResetPeerRequest build() {
+        return this;
+    }
+}
diff --git a/modules/raft-client/src/main/java/org/apache/ignite/raft/client/message/SnapshotRequestImpl.java b/modules/raft-client/src/main/java/org/apache/ignite/raft/client/message/SnapshotRequestImpl.java
new file mode 100644
index 0000000..5f1bde1
--- /dev/null
+++ b/modules/raft-client/src/main/java/org/apache/ignite/raft/client/message/SnapshotRequestImpl.java
@@ -0,0 +1,22 @@
+package org.apache.ignite.raft.client.message;
+
+import org.apache.ignite.raft.PeerId;
+import org.apache.ignite.raft.client.RaftClientCommonMessages;
+
+class SnapshotRequestImpl implements RaftClientCommonMessages.SnapshotRequest, RaftClientCommonMessages.SnapshotRequest.Builder {
+    private String groupId;
+
+    @Override public String getGroupId() {
+        return groupId;
+    }
+
+    @Override public Builder setGroupId(String groupId) {
+        this.groupId = groupId;
+
+        return this;
+    }
+
+    @Override public RaftClientCommonMessages.SnapshotRequest build() {
+        return this;
+    }
+}
diff --git a/modules/raft-client/src/main/java/org/apache/ignite/raft/client/message/StatusResponseImpl.java b/modules/raft-client/src/main/java/org/apache/ignite/raft/client/message/StatusResponseImpl.java
new file mode 100644
index 0000000..5afcf22
--- /dev/null
+++ b/modules/raft-client/src/main/java/org/apache/ignite/raft/client/message/StatusResponseImpl.java
@@ -0,0 +1,32 @@
+package org.apache.ignite.raft.client.message;
+
+import org.apache.ignite.raft.client.RaftClientCommonMessages;
+
+class StatusResponseImpl implements RaftClientCommonMessages.StatusResponse, RaftClientCommonMessages.StatusResponse.Builder {
+    private int errorCode;
+    private String errorMsg = "";
+
+    @Override public int getStatusCode() {
+        return errorCode;
+    }
+
+    @Override public Builder setStatusCode(int errorCode) {
+        this.errorCode = errorCode;
+
+        return this;
+    }
+
+    @Override public String getStatusMsg() {
+        return errorMsg;
+    }
+
+    @Override public Builder setStatusMsg(String errorMsg) {
+        this.errorMsg = errorMsg;
+
+        return this;
+    }
+
+    @Override public RaftClientCommonMessages.StatusResponse build() {
+        return this;
+    }
+}
diff --git a/modules/raft-client/src/main/java/org/apache/ignite/raft/client/message/TransferLeaderRequestImpl.java b/modules/raft-client/src/main/java/org/apache/ignite/raft/client/message/TransferLeaderRequestImpl.java
new file mode 100644
index 0000000..b125aec
--- /dev/null
+++ b/modules/raft-client/src/main/java/org/apache/ignite/raft/client/message/TransferLeaderRequestImpl.java
@@ -0,0 +1,27 @@
+package org.apache.ignite.raft.client.message;
+
+import org.apache.ignite.raft.PeerId;
+import org.apache.ignite.raft.client.RaftClientCommonMessages;
+
+class TransferLeaderRequestImpl implements RaftClientCommonMessages.TransferLeaderRequest, RaftClientCommonMessages.TransferLeaderRequest.Builder {
+    private String groupId;
+    private PeerId peerId;
+
+    @Override public String getGroupId() {
+        return groupId;
+    }
+
+    @Override public PeerId getPeerId() {
+        return peerId;
+    }
+
+    @Override public Builder setGroupId(String groupId) {
+        this.groupId = groupId;
+
+        return this;
+    }
+
+    @Override public RaftClientCommonMessages.TransferLeaderRequest build() {
+        return this;
+    }
+}
diff --git a/modules/raft-client/src/main/java/org/apache/ignite/raft/rpc/InvokeCallback.java b/modules/raft-client/src/main/java/org/apache/ignite/raft/rpc/InvokeCallback.java
new file mode 100644
index 0000000..c58b5e2
--- /dev/null
+++ b/modules/raft-client/src/main/java/org/apache/ignite/raft/rpc/InvokeCallback.java
@@ -0,0 +1,24 @@
+/*
+ * 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.raft.rpc;
+
+/**
+ *
+ */
+public interface InvokeCallback {
+    void complete(final Message response, final Throwable err);
+}
diff --git a/modules/raft-client/src/main/java/org/apache/ignite/raft/rpc/Message.java b/modules/raft-client/src/main/java/org/apache/ignite/raft/rpc/Message.java
new file mode 100644
index 0000000..175d27b
--- /dev/null
+++ b/modules/raft-client/src/main/java/org/apache/ignite/raft/rpc/Message.java
@@ -0,0 +1,4 @@
+package org.apache.ignite.raft.rpc;
+
+public interface Message {
+}
diff --git a/modules/raft-client/src/main/java/org/apache/ignite/raft/rpc/Node.java b/modules/raft-client/src/main/java/org/apache/ignite/raft/rpc/Node.java
new file mode 100644
index 0000000..bfff562
--- /dev/null
+++ b/modules/raft-client/src/main/java/org/apache/ignite/raft/rpc/Node.java
@@ -0,0 +1,7 @@
+package org.apache.ignite.raft.rpc;
+
+import java.io.Serializable;
+
+public interface Node extends Serializable {
+    String id();
+}
diff --git a/modules/raft-client/src/main/java/org/apache/ignite/raft/rpc/NodeImpl.java b/modules/raft-client/src/main/java/org/apache/ignite/raft/rpc/NodeImpl.java
new file mode 100644
index 0000000..63556ac
--- /dev/null
+++ b/modules/raft-client/src/main/java/org/apache/ignite/raft/rpc/NodeImpl.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ignite.raft.rpc;
+
+/**
+ * An node with an immutable id.
+ */
+public class NodeImpl implements Node {
+    private final String id;
+
+    public NodeImpl(String id) {
+        super();
+        this.id = id;
+    }
+
+    @Override public String id() {
+        return null;
+    }
+
+    @Override public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        NodeImpl node = (NodeImpl) o;
+
+        if (!id.equals(node.id)) return false;
+
+        return true;
+    }
+
+    @Override public int hashCode() {
+        return id.hashCode();
+    }
+}
diff --git a/modules/raft-client/src/main/java/org/apache/ignite/raft/rpc/RaftGroupMessage.java b/modules/raft-client/src/main/java/org/apache/ignite/raft/rpc/RaftGroupMessage.java
new file mode 100644
index 0000000..0ee4561
--- /dev/null
+++ b/modules/raft-client/src/main/java/org/apache/ignite/raft/rpc/RaftGroupMessage.java
@@ -0,0 +1,5 @@
+package org.apache.ignite.raft.rpc;
+
+public interface RaftGroupMessage extends Message {
+    public String getGroupId();
+}
diff --git a/modules/raft-client/src/main/java/org/apache/ignite/raft/rpc/RpcClient.java b/modules/raft-client/src/main/java/org/apache/ignite/raft/rpc/RpcClient.java
new file mode 100644
index 0000000..cdb6db7
--- /dev/null
+++ b/modules/raft-client/src/main/java/org/apache/ignite/raft/rpc/RpcClient.java
@@ -0,0 +1,59 @@
+/*
+ * 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.raft.rpc;
+
+import java.util.concurrent.Executor;
+
+/**
+ *
+ */
+public interface RpcClient {
+    /**
+     * Check connection for given address.
+     *
+     * @param node target address
+     * @return true if there is a connection and the connection is active and writable.
+     */
+    boolean checkConnection(final NodeImpl node);
+
+    /**
+     * Check connection for given address and async to create a new one if there is no connection.
+     *
+     * @param node       target address
+     * @param createIfAbsent create a new one if there is no connection
+     * @return true if there is a connection and the connection is active and writable.
+     */
+    boolean checkConnection(final NodeImpl node, final boolean createIfAbsent);
+
+    /**
+     * Close all connections of a address.
+     *
+     * @param node target address
+     */
+    void closeConnection(final NodeImpl node);
+
+    /**
+     * Asynchronous invocation with a callback.
+     *
+     * @param node  Target node.
+     * @param request   Request object
+     * @param callback  Invoke callback.
+     * @param executor  Executor to run invoke callback.
+     * @param timeoutMs Timeout millisecond
+     */
+    void invokeAsync(final Node node, final Message request, InvokeCallback callback, Executor executor, final long timeoutMs);
+}
diff --git a/modules/raft-client/src/test/java/org/apache/ignite/raft/client/RaftGroupRpcClientTest.java b/modules/raft-client/src/test/java/org/apache/ignite/raft/client/RaftGroupRpcClientTest.java
new file mode 100644
index 0000000..d5bd8e1
--- /dev/null
+++ b/modules/raft-client/src/test/java/org/apache/ignite/raft/client/RaftGroupRpcClientTest.java
@@ -0,0 +1,21 @@
+package org.apache.ignite.raft.client;
+
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+public class RaftGroupRpcClientTest {
+    @BeforeEach
+    public void beforeTest() {
+
+    }
+
+    @AfterEach
+    public void afterTest() {
+    }
+
+    @Test
+    public void test() {
+
+    }
+}


[ignite-3] 04/04: IGNITE-14149 wip 2.

Posted by as...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit f9d1a7b6873da7ffb6edcac1af649a508db35c67
Author: Alexey Scherbakov <al...@gmail.com>
AuthorDate: Tue Feb 16 21:02:07 2021 +0300

    IGNITE-14149 wip 2.
---
 modules/raft-client/pom.xml                        |   5 +
 .../main/java/org/apache/ignite/raft/State.java    |   2 +-
 .../raft/client/RaftClientCommonMessages.java      |   4 +-
 .../ignite/raft/client/RaftGroupRpcClient.java     |   1 -
 .../raft/client/impl/RaftGroupRpcClientImpl.java   | 144 +++++++++++++++++++++
 .../message/CreateGetLeaderResponseImpl.java       |  22 ----
 ...rRequestImpl.java => GetLeaderRequestImpl.java} |   3 +-
 .../raft/client/message/GetLeaderResponseImpl.java |  23 ++++
 .../RaftClientCommonMessageBuilderFactory.java     |   4 +-
 .../org/apache/ignite/raft/rpc/InvokeCallback.java |   4 +-
 .../main/java/org/apache/ignite/raft/rpc/Node.java |   3 +
 .../java/org/apache/ignite/raft/rpc/NodeImpl.java  |   1 +
 .../ignite/raft/client/RaftGroupRpcClientTest.java |  92 +++++++++++--
 13 files changed, 268 insertions(+), 40 deletions(-)

diff --git a/modules/raft-client/pom.xml b/modules/raft-client/pom.xml
index d2613d0..05f2489 100644
--- a/modules/raft-client/pom.xml
+++ b/modules/raft-client/pom.xml
@@ -42,6 +42,11 @@
         </dependency>
         <dependency>
             <groupId>org.mockito</groupId>
+            <artifactId>mockito-junit-jupiter</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.mockito</groupId>
             <artifactId>mockito-core</artifactId>
             <scope>test</scope>
         </dependency>
diff --git a/modules/raft-client/src/main/java/org/apache/ignite/raft/State.java b/modules/raft-client/src/main/java/org/apache/ignite/raft/State.java
index d924847..5f5fb15 100644
--- a/modules/raft-client/src/main/java/org/apache/ignite/raft/State.java
+++ b/modules/raft-client/src/main/java/org/apache/ignite/raft/State.java
@@ -30,7 +30,7 @@ public class State implements Iterable<PeerId> {
     /** Mark a leaner peer */
     private static final String LEARNER_POSTFIX = "/learner";
 
-    private PeerId leader;
+    private volatile PeerId leader;
 
     private List<PeerId> peers = new ArrayList<>();
 
diff --git a/modules/raft-client/src/main/java/org/apache/ignite/raft/client/RaftClientCommonMessages.java b/modules/raft-client/src/main/java/org/apache/ignite/raft/client/RaftClientCommonMessages.java
index 150fe7d..39b9b90 100644
--- a/modules/raft-client/src/main/java/org/apache/ignite/raft/client/RaftClientCommonMessages.java
+++ b/modules/raft-client/src/main/java/org/apache/ignite/raft/client/RaftClientCommonMessages.java
@@ -172,12 +172,12 @@ public final class RaftClientCommonMessages {
     }
 
     public interface GetLeaderResponse extends Message {
-        String getLeaderId();
+        PeerId getLeaderId();
 
         public interface Builder {
             GetLeaderResponse build();
 
-            Builder setLeaderId(String leaderId);
+            Builder setLeaderId(PeerId leaderId);
         }
     }
 
diff --git a/modules/raft-client/src/main/java/org/apache/ignite/raft/client/RaftGroupRpcClient.java b/modules/raft-client/src/main/java/org/apache/ignite/raft/client/RaftGroupRpcClient.java
index f0910d0..bccfded 100644
--- a/modules/raft-client/src/main/java/org/apache/ignite/raft/client/RaftGroupRpcClient.java
+++ b/modules/raft-client/src/main/java/org/apache/ignite/raft/client/RaftGroupRpcClient.java
@@ -61,7 +61,6 @@ public interface RaftGroupRpcClient {
      *
      * @param endpoint  server address
      * @param request   request data
-     * @param done      callback
      * @return a future with result
      */
     Future<RemovePeerResponse> removePeer(RemovePeerRequest request);
diff --git a/modules/raft-client/src/main/java/org/apache/ignite/raft/client/impl/RaftGroupRpcClientImpl.java b/modules/raft-client/src/main/java/org/apache/ignite/raft/client/impl/RaftGroupRpcClientImpl.java
new file mode 100644
index 0000000..affa939
--- /dev/null
+++ b/modules/raft-client/src/main/java/org/apache/ignite/raft/client/impl/RaftGroupRpcClientImpl.java
@@ -0,0 +1,144 @@
+package org.apache.ignite.raft.client.impl;
+
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import org.apache.ignite.raft.PeerId;
+import org.apache.ignite.raft.State;
+import org.apache.ignite.raft.client.RaftClientCommonMessages;
+import org.apache.ignite.raft.client.RaftGroupRpcClient;
+import org.apache.ignite.raft.client.message.RaftClientCommonMessageBuilderFactory;
+import org.apache.ignite.raft.rpc.InvokeCallback;
+import org.apache.ignite.raft.rpc.Message;
+import org.apache.ignite.raft.rpc.Node;
+import org.apache.ignite.raft.rpc.RaftGroupMessage;
+import org.apache.ignite.raft.rpc.RpcClient;
+
+public class RaftGroupRpcClientImpl implements RaftGroupRpcClient {
+    private final ExecutorService executor;
+    private final int defaultTimeout;
+    private final RpcClient rpcClient;
+
+    /** Where to ask for initial configuration. */
+    private final Set<Node> initialCfgNodes;
+
+    private Map<String, State> states = new ConcurrentHashMap<>();
+
+    /**
+     * Accepts dependencies in constructor.
+     * @param rpcClient
+     * @param defaultTimeout
+     * @param initialCfgNode Initial configuration nodes.
+     */
+    public RaftGroupRpcClientImpl(RpcClient rpcClient, int defaultTimeout, Set<Node> initialCfgNodes) {
+        this.defaultTimeout = defaultTimeout;
+        this.rpcClient = rpcClient;
+        this.initialCfgNodes = new HashSet<>(initialCfgNodes);
+        executor = Executors.newWorkStealingPool();
+    }
+
+    @Override public State state(String groupId, boolean refresh) {
+        return states.get(groupId);
+    }
+
+    @Override public Future<RaftClientCommonMessages.AddPeerResponse> addPeer(RaftClientCommonMessages.AddPeerRequest request) {
+        return null;
+    }
+
+    @Override public Future<RaftClientCommonMessages.RemovePeerResponse> removePeer(RaftClientCommonMessages.RemovePeerRequest request) {
+        return null;
+    }
+
+    @Override public Future<RaftClientCommonMessages.StatusResponse> resetPeers(PeerId peerId, RaftClientCommonMessages.ResetPeerRequest request) {
+        return null;
+    }
+
+    @Override public Future<RaftClientCommonMessages.StatusResponse> snapshot(PeerId peerId, RaftClientCommonMessages.SnapshotRequest request) {
+        return null;
+    }
+
+    @Override public Future<RaftClientCommonMessages.ChangePeersResponse> changePeers(RaftClientCommonMessages.ChangePeersRequest request) {
+        return null;
+    }
+
+    @Override public Future<RaftClientCommonMessages.LearnersOpResponse> addLearners(RaftClientCommonMessages.AddLearnersRequest request) {
+        return null;
+    }
+
+    @Override public Future<RaftClientCommonMessages.LearnersOpResponse> removeLearners(RaftClientCommonMessages.RemoveLearnersRequest request) {
+        return null;
+    }
+
+    @Override public Future<RaftClientCommonMessages.LearnersOpResponse> resetLearners(RaftClientCommonMessages.ResetLearnersRequest request) {
+        return null;
+    }
+
+    @Override public Future<RaftClientCommonMessages.StatusResponse> transferLeader(RaftClientCommonMessages.TransferLeaderRequest request) {
+        return null;
+    }
+
+    private CompletableFuture<RaftClientCommonMessages.GetLeaderResponse> refreshLeader(Node node, String groupId) {
+        RaftClientCommonMessages.GetLeaderRequest req = RaftClientCommonMessageBuilderFactory.DEFAULT.createGetLeaderRequest().setGroupId(groupId).build();
+
+        CompletableFuture<RaftClientCommonMessages.GetLeaderResponse> fut = new CompletableFuture<>();
+
+        rpcClient.invokeAsync(node, req, new InvokeCallback<RaftClientCommonMessages.GetLeaderResponse>() {
+            @Override public void complete(RaftClientCommonMessages.GetLeaderResponse response, Throwable err) {
+                if (err != null)
+                    fut.completeExceptionally(err);
+                else
+                    fut.complete(response);
+            }
+        }, executor, defaultTimeout);
+
+        return fut;
+    }
+
+    @Override public <R extends Message> Future<R> sendCustom(RaftGroupMessage request) {
+        State newState = new State();
+
+        State state = states.putIfAbsent(request.getGroupId(), newState);
+
+        if (state == null)
+            state = newState;
+
+        CompletableFuture<R> fut = new CompletableFuture<>();
+
+        fut.orTimeout(defaultTimeout, TimeUnit.MILLISECONDS);
+
+        if (state.getLeader() == null) {
+            synchronized (state) {
+                CompletableFuture<RaftClientCommonMessages.GetLeaderResponse> fut0 =
+                    refreshLeader(initialCfgNodes.iterator().next(), request.getGroupId()); // TODO asch search all nodes.
+
+                try {
+                    RaftClientCommonMessages.GetLeaderResponse resp = fut0.get(defaultTimeout, TimeUnit.MILLISECONDS);
+
+                    state.setLeader(resp.getLeaderId());
+                }
+                catch (Exception e) {
+                    fut.completeExceptionally(e);
+
+                    return fut;
+                }
+            }
+        }
+
+        rpcClient.invokeAsync(state.getLeader().getNode(), request, new InvokeCallback<R>() {
+            @Override public void complete(R response, Throwable err) {
+                if (err != null)
+                    fut.completeExceptionally(err);
+                else
+                    fut.complete(response);
+            }
+        }, executor, defaultTimeout);
+
+        return fut;
+    }
+}
diff --git a/modules/raft-client/src/main/java/org/apache/ignite/raft/client/message/CreateGetLeaderResponseImpl.java b/modules/raft-client/src/main/java/org/apache/ignite/raft/client/message/CreateGetLeaderResponseImpl.java
deleted file mode 100644
index 5b58d48..0000000
--- a/modules/raft-client/src/main/java/org/apache/ignite/raft/client/message/CreateGetLeaderResponseImpl.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package org.apache.ignite.raft.client.message;
-
-
-import org.apache.ignite.raft.client.RaftClientCommonMessages;
-
-public class CreateGetLeaderResponseImpl implements RaftClientCommonMessages.GetLeaderResponse, RaftClientCommonMessages.GetLeaderResponse.Builder {
-    private String leaderId;
-
-    @Override public String getLeaderId() {
-        return leaderId;
-    }
-
-    @Override public RaftClientCommonMessages.GetLeaderResponse build() {
-        return this;
-    }
-
-    @Override public Builder setLeaderId(String leaderId) {
-        this.leaderId = leaderId;
-
-        return this;
-    }
-}
diff --git a/modules/raft-client/src/main/java/org/apache/ignite/raft/client/message/CreateGetLeaderRequestImpl.java b/modules/raft-client/src/main/java/org/apache/ignite/raft/client/message/GetLeaderRequestImpl.java
similarity index 70%
rename from modules/raft-client/src/main/java/org/apache/ignite/raft/client/message/CreateGetLeaderRequestImpl.java
rename to modules/raft-client/src/main/java/org/apache/ignite/raft/client/message/GetLeaderRequestImpl.java
index 9c44e11..429bab4 100644
--- a/modules/raft-client/src/main/java/org/apache/ignite/raft/client/message/CreateGetLeaderRequestImpl.java
+++ b/modules/raft-client/src/main/java/org/apache/ignite/raft/client/message/GetLeaderRequestImpl.java
@@ -1,10 +1,9 @@
 package org.apache.ignite.raft.client.message;
 
 
-import org.apache.ignite.raft.PeerId;
 import org.apache.ignite.raft.client.RaftClientCommonMessages;
 
-public class CreateGetLeaderRequestImpl implements RaftClientCommonMessages.GetLeaderRequest, RaftClientCommonMessages.GetLeaderRequest.Builder {
+public class GetLeaderRequestImpl implements RaftClientCommonMessages.GetLeaderRequest, RaftClientCommonMessages.GetLeaderRequest.Builder {
     private String groupId;
 
     @Override public String getGroupId() {
diff --git a/modules/raft-client/src/main/java/org/apache/ignite/raft/client/message/GetLeaderResponseImpl.java b/modules/raft-client/src/main/java/org/apache/ignite/raft/client/message/GetLeaderResponseImpl.java
new file mode 100644
index 0000000..22789b1
--- /dev/null
+++ b/modules/raft-client/src/main/java/org/apache/ignite/raft/client/message/GetLeaderResponseImpl.java
@@ -0,0 +1,23 @@
+package org.apache.ignite.raft.client.message;
+
+
+import org.apache.ignite.raft.PeerId;
+import org.apache.ignite.raft.client.RaftClientCommonMessages;
+
+public class GetLeaderResponseImpl implements RaftClientCommonMessages.GetLeaderResponse, RaftClientCommonMessages.GetLeaderResponse.Builder {
+    private PeerId leaderId;
+
+    @Override public PeerId getLeaderId() {
+        return leaderId;
+    }
+
+    @Override public RaftClientCommonMessages.GetLeaderResponse build() {
+        return this;
+    }
+
+    @Override public Builder setLeaderId(PeerId leaderId) {
+        this.leaderId = leaderId;
+
+        return this;
+    }
+}
diff --git a/modules/raft-client/src/main/java/org/apache/ignite/raft/client/message/RaftClientCommonMessageBuilderFactory.java b/modules/raft-client/src/main/java/org/apache/ignite/raft/client/message/RaftClientCommonMessageBuilderFactory.java
index f54ec48..45f070a 100644
--- a/modules/raft-client/src/main/java/org/apache/ignite/raft/client/message/RaftClientCommonMessageBuilderFactory.java
+++ b/modules/raft-client/src/main/java/org/apache/ignite/raft/client/message/RaftClientCommonMessageBuilderFactory.java
@@ -53,11 +53,11 @@ public class RaftClientCommonMessageBuilderFactory implements ClientMessageBuild
     }
 
     @Override public RaftClientCommonMessages.GetLeaderRequest.Builder createGetLeaderRequest() {
-        return new CreateGetLeaderRequestImpl();
+        return new GetLeaderRequestImpl();
     }
 
     @Override public RaftClientCommonMessages.GetLeaderResponse.Builder createGetLeaderResponse() {
-        return new CreateGetLeaderResponseImpl();
+        return new GetLeaderResponseImpl();
     }
 
     @Override public RaftClientCommonMessages.GetPeersRequest.Builder createGetPeersRequest() {
diff --git a/modules/raft-client/src/main/java/org/apache/ignite/raft/rpc/InvokeCallback.java b/modules/raft-client/src/main/java/org/apache/ignite/raft/rpc/InvokeCallback.java
index c58b5e2..743d519 100644
--- a/modules/raft-client/src/main/java/org/apache/ignite/raft/rpc/InvokeCallback.java
+++ b/modules/raft-client/src/main/java/org/apache/ignite/raft/rpc/InvokeCallback.java
@@ -19,6 +19,6 @@ package org.apache.ignite.raft.rpc;
 /**
  *
  */
-public interface InvokeCallback {
-    void complete(final Message response, final Throwable err);
+public interface InvokeCallback<T extends Message> {
+    void complete(final T response, final Throwable err);
 }
diff --git a/modules/raft-client/src/main/java/org/apache/ignite/raft/rpc/Node.java b/modules/raft-client/src/main/java/org/apache/ignite/raft/rpc/Node.java
index bfff562..966ff52 100644
--- a/modules/raft-client/src/main/java/org/apache/ignite/raft/rpc/Node.java
+++ b/modules/raft-client/src/main/java/org/apache/ignite/raft/rpc/Node.java
@@ -2,6 +2,9 @@ package org.apache.ignite.raft.rpc;
 
 import java.io.Serializable;
 
+/**
+ * TODO FIXME asch must be elsewhere.
+ */
 public interface Node extends Serializable {
     String id();
 }
diff --git a/modules/raft-client/src/main/java/org/apache/ignite/raft/rpc/NodeImpl.java b/modules/raft-client/src/main/java/org/apache/ignite/raft/rpc/NodeImpl.java
index 63556ac..f71424f 100644
--- a/modules/raft-client/src/main/java/org/apache/ignite/raft/rpc/NodeImpl.java
+++ b/modules/raft-client/src/main/java/org/apache/ignite/raft/rpc/NodeImpl.java
@@ -18,6 +18,7 @@ package org.apache.ignite.raft.rpc;
 
 /**
  * An node with an immutable id.
+ * TODO FIXME asch must be elsewhere.
  */
 public class NodeImpl implements Node {
     private final String id;
diff --git a/modules/raft-client/src/test/java/org/apache/ignite/raft/client/RaftGroupRpcClientTest.java b/modules/raft-client/src/test/java/org/apache/ignite/raft/client/RaftGroupRpcClientTest.java
index d5bd8e1..bf1656a 100644
--- a/modules/raft-client/src/test/java/org/apache/ignite/raft/client/RaftGroupRpcClientTest.java
+++ b/modules/raft-client/src/test/java/org/apache/ignite/raft/client/RaftGroupRpcClientTest.java
@@ -1,21 +1,97 @@
 package org.apache.ignite.raft.client;
 
-import org.junit.jupiter.api.AfterEach;
-import org.junit.jupiter.api.BeforeEach;
+import java.util.Collections;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Future;
+import org.apache.ignite.raft.PeerId;
+import org.apache.ignite.raft.State;
+import org.apache.ignite.raft.client.impl.RaftGroupRpcClientImpl;
+import org.apache.ignite.raft.client.message.GetLeaderResponseImpl;
+import org.apache.ignite.raft.client.message.RaftClientCommonMessageBuilderFactory;
+import org.apache.ignite.raft.rpc.InvokeCallback;
+import org.apache.ignite.raft.rpc.Message;
+import org.apache.ignite.raft.rpc.NodeImpl;
+import org.apache.ignite.raft.rpc.RaftGroupMessage;
+import org.apache.ignite.raft.rpc.RpcClient;
 import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.mockito.stubbing.Answer;
 
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.eq;
+
+@ExtendWith(MockitoExtension.class)
 public class RaftGroupRpcClientTest {
-    @BeforeEach
-    public void beforeTest() {
+    @Mock
+    private RpcClient rpcClient;
+
+    private static PeerId leader = new PeerId(new NodeImpl("test"));
+
+    @Test
+    public void testCustomMessage() throws Exception {
+        String groupId = "test";
+
+        mockClient();
+
+        // TODO FIXME asch where to get initial configuration for the group ?
+        RaftGroupRpcClient client = new RaftGroupRpcClientImpl(rpcClient, 5_000, Collections.singleton(leader.getNode()));
+
+        JunkRequest req = new JunkRequest(groupId);
+
+        Future<Message> fut = client.sendCustom(req);
+
+        State state = client.state(groupId, false);
 
+        // Expecting raft group state to be transparently loaded on first request.
+        assertEquals(leader, state.getLeader());
+
+        assertTrue(fut.get() instanceof JunkResponse);
     }
 
-    @AfterEach
-    public void afterTest() {
+    private static class JunkRequest implements RaftGroupMessage {
+        private final String groupId;
+
+        JunkRequest(String groupId) {
+            this.groupId = groupId;
+        }
+
+        @Override public String getGroupId() {
+            return groupId;
+        }
     }
 
-    @Test
-    public void test() {
+    private static class JunkResponse implements Message {}
+
+    private void mockClient() {
+        // Mock junk request.
+        Mockito.doAnswer(new Answer() {
+            @Override public Object answer(InvocationOnMock invocation) throws Throwable {
+                InvokeCallback callback = invocation.getArgument(2);
+                Executor executor = invocation.getArgument(3);
+
+                executor.execute(() -> callback.complete(new JunkResponse(), null));
+
+                return null;
+            }
+        }).when(rpcClient).invokeAsync(eq(leader.getNode()), any(JunkRequest.class), any(), any(), anyLong());
+
+        // Mock get leader request.
+        Mockito.doAnswer(new Answer() {
+            @Override public Object answer(InvocationOnMock invocation) throws Throwable {
+                InvokeCallback callback = invocation.getArgument(2);
+                Executor executor = invocation.getArgument(3);
+
+                executor.execute(() -> callback.complete(RaftClientCommonMessageBuilderFactory.DEFAULT.createGetLeaderResponse().setLeaderId(leader).build(), null));
 
+                return null;
+            }
+        }).when(rpcClient).invokeAsync(eq(leader.getNode()), any(RaftClientCommonMessages.GetLeaderRequest.class), any(), any(), anyLong());
     }
 }


[ignite-3] 01/04: IGNITE-14149 wip.

Posted by as...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit b01c23cc542e6b25b472cdba4a008c250a3d7cdf
Author: Alexey Scherbakov <al...@gmail.com>
AuthorDate: Tue Feb 9 20:00:41 2021 +0300

    IGNITE-14149 wip.
---
 modules/raft-client/pom.xml | 54 +++++++++++++++++++++++++++++++++++++++++++++
 pom.xml                     |  1 +
 2 files changed, 55 insertions(+)

diff --git a/modules/raft-client/pom.xml b/modules/raft-client/pom.xml
new file mode 100644
index 0000000..9286853
--- /dev/null
+++ b/modules/raft-client/pom.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<!--
+    POM file.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.ignite</groupId>
+        <artifactId>apache-ignite</artifactId>
+        <version>3.0.0-SNAPSHOT</version>
+        <relativePath>../..</relativePath>
+    </parent>
+
+    <artifactId>ignite-raft-client</artifactId>
+
+    <dependencies>
+    </dependencies>
+
+    <build>
+        <resources>
+            <resource>
+                <directory>src/main/resources</directory>
+                <filtering>true</filtering>
+            </resource>
+        </resources>
+
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/pom.xml b/pom.xml
index abf5ce6..e3afc38 100644
--- a/pom.xml
+++ b/pom.xml
@@ -40,6 +40,7 @@
         <module>modules/configuration-annotation-processor</module>
         <module>modules/rest</module>
         <module>modules/runner</module>
+        <module>modules/raft-client</module>
     </modules>
 
     <build>


[ignite-3] 02/04: Merge branch 'main' of https://gitbox.apache.org/repos/asf/ignite-3 into ignite-14149

Posted by as...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit f9c2ba4c7f2634be11d90caf8f689fdc14f50121
Merge: b01c23c 7e08e60
Author: Alexey Scherbakov <al...@gmail.com>
AuthorDate: Tue Feb 16 09:54:11 2021 +0300

    Merge branch 'main' of https://gitbox.apache.org/repos/asf/ignite-3 into ignite-14149

 modules/configuration-annotation-processor/pom.xml |  1 -
 .../internal/TestConfigurationSchema.java          |  4 +-
 .../processor/internal/Processor.java              | 40 +++++++------
 .../{ => internal}/util/ConfigurationUtilTest.java | 20 +++----
 .../sample/ClusterWideConfigurationSchema.java     |  7 +--
 .../sample/ConstructableTreeNodeTest.java          |  4 +-
 .../sample/LocalConfigurationSchema.java           |  5 +-
 .../sample/NetworkConfigurationSchema.java         |  6 +-
 .../sample/TraversableTreeNodeTest.java            | 52 ++++++++--------
 .../sample/storage/ConfigurationChangerTest.java   | 34 +++++------
 .../sample/storage/TestConfigurationStorage.java   |  9 +--
 .../ignite/configuration/ConfigurationChanger.java | 70 +++++++++++++---------
 .../ignite/configuration/annotation/Config.java    | 10 ----
 .../annotation/ConfigurationRoot.java              | 43 +++++++++++++
 .../configuration/internal/DynamicProperty.java    |  2 +-
 .../{ => internal}/util/ConfigurationUtil.java     | 59 +++++++++---------
 .../{ => internal}/util/KeyNotFoundException.java  |  2 +-
 .../storage/ConfigurationStorage.java              |  8 +--
 .../configuration/tree/ConfigurationVisitor.java   | 11 ++--
 .../ignite/configuration/tree/InnerNode.java       |  6 +-
 .../ignite/configuration/tree/NamedListChange.java | 10 ++--
 ...TraversableTreeNode.java => NamedListInit.java} | 13 ++--
 .../ignite/configuration/tree/NamedListNode.java   | 23 +++++--
 .../configuration/tree/TraversableTreeNode.java    |  2 +-
 .../configuration/RestConfigurationSchema.java     |  4 +-
 .../extended/AutoAdjustConfigurationSchema.java    |  2 +-
 .../extended/LocalConfigurationSchema.java         |  4 +-
 27 files changed, 260 insertions(+), 191 deletions(-)