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

tanxinyu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/iotdb.git


The following commit(s) were added to refs/heads/master by this push:
     new 660fc05f31 [IOTDB-2998] Pooling RatisConsensus Raft client (#5683)
660fc05f31 is described below

commit 660fc05f31d228ff43220c24cd630b587bc7f680
Author: SzyWilliam <[email protected]>
AuthorDate: Wed Apr 27 17:33:54 2022 +0800

    [IOTDB-2998] Pooling RatisConsensus Raft client (#5683)
    
    * initial commit
    
    * pooling raft client
    
    * returnSelf call
    
    * add clean logic
---
 .../apache/iotdb/consensus/ratis/RatisClient.java  | 107 +++++++++++++++++++++
 .../iotdb/consensus/ratis/RatisClientFactory.java  |  67 -------------
 .../iotdb/consensus/ratis/RatisConsensus.java      |  93 +++++++++---------
 .../iotdb/consensus/ratis/RatisConsensusTest.java  |   2 +-
 4 files changed, 156 insertions(+), 113 deletions(-)

diff --git 
a/consensus/src/main/java/org/apache/iotdb/consensus/ratis/RatisClient.java 
b/consensus/src/main/java/org/apache/iotdb/consensus/ratis/RatisClient.java
new file mode 100644
index 0000000000..8e27109533
--- /dev/null
+++ b/consensus/src/main/java/org/apache/iotdb/consensus/ratis/RatisClient.java
@@ -0,0 +1,107 @@
+/*
+ * 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.iotdb.consensus.ratis;
+
+import org.apache.iotdb.commons.client.BaseClientFactory;
+import org.apache.iotdb.commons.client.ClientFactoryProperty;
+import org.apache.iotdb.commons.client.ClientManager;
+
+import org.apache.commons.pool2.PooledObject;
+import org.apache.commons.pool2.impl.DefaultPooledObject;
+import org.apache.ratis.client.RaftClient;
+import org.apache.ratis.client.RaftClientRpc;
+import org.apache.ratis.conf.RaftProperties;
+import org.apache.ratis.protocol.RaftGroup;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+
+public class RatisClient {
+  private final Logger logger = LoggerFactory.getLogger(RatisClient.class);
+  private final RaftGroup serveGroup;
+  private final RaftClient raftClient;
+  private final ClientManager<RaftGroup, RatisClient> clientManager;
+
+  public RatisClient(
+      RaftGroup serveGroup,
+      RaftClient client,
+      ClientManager<RaftGroup, RatisClient> clientManager) {
+    this.serveGroup = serveGroup;
+    this.raftClient = client;
+    this.clientManager = clientManager;
+  }
+
+  public RaftClient getRaftClient() {
+    return raftClient;
+  }
+
+  public void close() {
+    try {
+      raftClient.close();
+    } catch (IOException e) {
+      logger.warn("cannot close raft client ", e);
+    }
+  }
+
+  public void returnSelf() {
+    if (clientManager != null) {
+      clientManager.returnClient(serveGroup, this);
+    }
+  }
+
+  public static class Factory extends BaseClientFactory<RaftGroup, 
RatisClient> {
+
+    private final RaftProperties raftProperties;
+    private final RaftClientRpc clientRpc;
+
+    public Factory(
+        ClientManager<RaftGroup, RatisClient> clientManager,
+        ClientFactoryProperty clientPoolProperty,
+        RaftProperties raftProperties,
+        RaftClientRpc clientRpc) {
+      super(clientManager, clientPoolProperty);
+      this.raftProperties = raftProperties;
+      this.clientRpc = clientRpc;
+    }
+
+    @Override
+    public void destroyObject(RaftGroup key, PooledObject<RatisClient> 
pooledObject) {
+      pooledObject.getObject().close();
+    }
+
+    @Override
+    public PooledObject<RatisClient> makeObject(RaftGroup group) throws 
Exception {
+      return new DefaultPooledObject<>(
+          new RatisClient(
+              group,
+              RaftClient.newBuilder()
+                  .setProperties(raftProperties)
+                  .setRaftGroup(group)
+                  .setClientRpc(clientRpc)
+                  .build(),
+              clientManager));
+    }
+
+    @Override
+    public boolean validateObject(RaftGroup key, PooledObject<RatisClient> 
pooledObject) {
+      return true;
+    }
+  }
+}
diff --git 
a/consensus/src/main/java/org/apache/iotdb/consensus/ratis/RatisClientFactory.java
 
b/consensus/src/main/java/org/apache/iotdb/consensus/ratis/RatisClientFactory.java
deleted file mode 100644
index 9164e91afa..0000000000
--- 
a/consensus/src/main/java/org/apache/iotdb/consensus/ratis/RatisClientFactory.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.iotdb.consensus.ratis;
-
-import org.apache.iotdb.commons.client.BaseClientFactory;
-import org.apache.iotdb.commons.client.ClientFactoryProperty;
-import org.apache.iotdb.commons.client.ClientManager;
-
-import org.apache.commons.pool2.PooledObject;
-import org.apache.commons.pool2.impl.DefaultPooledObject;
-import org.apache.ratis.client.RaftClient;
-import org.apache.ratis.client.RaftClientRpc;
-import org.apache.ratis.conf.RaftProperties;
-import org.apache.ratis.protocol.RaftGroup;
-
-public class RatisClientFactory extends BaseClientFactory<RaftGroup, 
RaftClient> {
-
-  private final RaftProperties raftProperties;
-  private final RaftClientRpc clientRpc;
-
-  public RatisClientFactory(
-      ClientManager<RaftGroup, RaftClient> clientManager,
-      ClientFactoryProperty clientPoolProperty,
-      RaftProperties raftProperties,
-      RaftClientRpc clientRpc) {
-    super(clientManager, clientPoolProperty);
-    this.raftProperties = raftProperties;
-    this.clientRpc = clientRpc;
-  }
-
-  @Override
-  public void destroyObject(RaftGroup key, PooledObject<RaftClient> 
pooledObject) throws Exception {
-    pooledObject.getObject().close();
-  }
-
-  @Override
-  public PooledObject<RaftClient> makeObject(RaftGroup group) throws Exception 
{
-    return new DefaultPooledObject<>(
-        RaftClient.newBuilder()
-            .setProperties(raftProperties)
-            .setRaftGroup(group)
-            .setClientRpc(clientRpc)
-            .build());
-  }
-
-  @Override
-  public boolean validateObject(RaftGroup key, PooledObject<RaftClient> 
pooledObject) {
-    return true;
-  }
-}
diff --git 
a/consensus/src/main/java/org/apache/iotdb/consensus/ratis/RatisConsensus.java 
b/consensus/src/main/java/org/apache/iotdb/consensus/ratis/RatisConsensus.java
index 0e4e368f03..d022f096cc 100644
--- 
a/consensus/src/main/java/org/apache/iotdb/consensus/ratis/RatisConsensus.java
+++ 
b/consensus/src/main/java/org/apache/iotdb/consensus/ratis/RatisConsensus.java
@@ -69,6 +69,8 @@ import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.atomic.AtomicLong;
 import java.util.stream.Collectors;
 
@@ -88,10 +90,12 @@ class RatisConsensus implements IConsensus {
   private final RaftProperties properties = new RaftProperties();
   private final RaftClientRpc clientRpc;
 
-  private final IClientManager<RaftGroup, RaftClient> clientManager =
-      new IClientManager.Factory<RaftGroup, RaftClient>()
+  private final IClientManager<RaftGroup, RatisClient> clientManager =
+      new IClientManager.Factory<RaftGroup, RatisClient>()
           .createClientManager(new RatisClientPoolFactory());
 
+  private Map<RaftGroupId, RaftGroup> lastSeen;
+
   private final ClientId localFakeId = ClientId.randomId();
   private final AtomicLong localFakeCallId = new AtomicLong(0);
 
@@ -104,6 +108,8 @@ class RatisConsensus implements IConsensus {
    */
   public RatisConsensus(TEndPoint endpoint, File ratisStorageDir, 
IStateMachine.Registry registry)
       throws IOException {
+    lastSeen = new ConcurrentHashMap<>();
+
     // create a RaftPeer as endpoint of comm
     String address = Utils.IPAddress(endpoint);
     myself = Utils.toRaftPeer(endpoint, DEFAULT_PRIORITY);
@@ -178,13 +184,12 @@ class RatisConsensus implements IConsensus {
     }
 
     // 2. try raft client
-    RaftClient client = null;
     TSStatus writeResult;
     try {
-      client = buildClient(raftGroup);
-      RaftClientReply reply = client.io().send(message);
+      RatisClient client = getRaftClient(raftGroup);
+      RaftClientReply reply = client.getRaftClient().io().send(message);
       writeResult = 
Utils.deserializeFrom(reply.getMessage().getContent().asReadOnlyByteBuffer());
-      client.close();
+      client.returnSelf();
     } catch (IOException | TException e) {
       return failedWrite(new RatisRequestFailedException(e));
     }
@@ -240,14 +245,12 @@ class RatisConsensus implements IConsensus {
       return failed(new ConsensusGroupNotExistException(groupId));
     }
 
-    // build and store the corresponding client
-    RaftClient client = buildClient(group);
-
     // add RaftPeer myself to this RaftGroup
     RaftClientReply reply;
     try {
-      reply = client.getGroupManagementApi(myself.getId()).add(group);
-      client.close();
+      RatisClient client = getRaftClient(group);
+      reply = 
client.getRaftClient().getGroupManagementApi(myself.getId()).add(group);
+      client.returnSelf();
     } catch (IOException e) {
       return failed(new RatisRequestFailedException(e));
     }
@@ -272,13 +275,16 @@ class RatisConsensus implements IConsensus {
       return failed(new PeerNotInConsensusGroupException(groupId, myself));
     }
 
-    RaftClient client;
     // send remove group to myself
     RaftClientReply reply;
     try {
-      client = buildClient(raftGroup);
-      reply = client.getGroupManagementApi(myself.getId()).remove(raftGroupId, 
false, false);
-      client.close();
+      RatisClient client = getRaftClient(raftGroup);
+      reply =
+          client
+              .getRaftClient()
+              .getGroupManagementApi(myself.getId())
+              .remove(raftGroupId, false, false);
+      client.returnSelf();
     } catch (IOException e) {
       return failed(new RatisRequestFailedException(e));
     }
@@ -367,9 +373,6 @@ class RatisConsensus implements IConsensus {
       return failed(new ConsensusGroupNotExistException(groupId));
     }
 
-    // build the client and store it
-    buildClient(raftGroup);
-
     // add RaftPeer myself to this RaftGroup
     RaftClientReply reply;
     try {
@@ -380,6 +383,10 @@ class RatisConsensus implements IConsensus {
     return 
ConsensusGenericResponse.newBuilder().setSuccess(reply.isSuccess()).build();
   }
 
+  /**
+   * transferLeader in Ratis implementation is not guaranteed to transfer 
leadership to the
+   * designated peer Thus, it may produce undetermined results. Caller should 
not count on this API.
+   */
   @Override
   public ConsensusGenericResponse transferLeader(ConsensusGroupId groupId, 
Peer newLeader) {
     // By default, Ratis gives every Raft Peer same priority 0
@@ -407,16 +414,17 @@ class RatisConsensus implements IConsensus {
       }
     }
 
-    RaftClient client = buildClient(raftGroup);
     RaftClientReply reply = null;
     try {
-      RaftClientReply configChangeReply = 
client.admin().setConfiguration(newConfiguration);
+      RatisClient client = getRaftClient(raftGroup);
+      RaftClientReply configChangeReply =
+          client.getRaftClient().admin().setConfiguration(newConfiguration);
       if (!configChangeReply.isSuccess()) {
         return failed(new 
RatisRequestFailedException(configChangeReply.getException()));
       }
       // TODO tuning for timeoutMs
-      reply = client.admin().transferLeadership(newRaftLeader.getId(), 2000);
-      client.close();
+      reply = 
client.getRaftClient().admin().transferLeadership(newRaftLeader.getId(), 2000);
+      client.returnSelf();
     } catch (IOException e) {
       return failed(new RatisRequestFailedException(e));
     }
@@ -489,6 +497,12 @@ class RatisConsensus implements IConsensus {
     RaftGroup raftGroup = null;
     try {
       raftGroup = server.getDivision(raftGroupId).getGroup();
+      RaftGroup lastSeenGroup = lastSeen.getOrDefault(raftGroupId, null);
+      if (lastSeenGroup != null && !lastSeenGroup.equals(raftGroup)) {
+        // delete the pooled raft-client of the out-dated group and cache the 
latest
+        clientManager.clear(lastSeenGroup);
+        lastSeen.put(raftGroupId, raftGroup);
+      }
     } catch (IOException e) {
       logger.debug("get group failed ", e);
     }
@@ -503,50 +517,39 @@ class RatisConsensus implements IConsensus {
     return RaftGroup.valueOf(Utils.toRatisGroupId(groupId), raftPeers);
   }
 
-  private RaftClient buildClient(RaftGroup group) {
-    RaftProperties raftProperties = new RaftProperties();
-    RaftClient.Builder builder =
-        RaftClient.newBuilder()
-            .setProperties(raftProperties)
-            .setRaftGroup(group)
-            .setClientRpc(
-                new GrpcFactory(new Parameters())
-                    .newRaftClientRpc(ClientId.randomId(), raftProperties));
-    return builder.build();
-  }
-
-  // TODO use this function to get RaftClient
-  private RaftClient getRaftClient(RaftGroup group) {
+  private RatisClient getRaftClient(RaftGroup group) throws IOException {
     try {
       return clientManager.borrowClient(group);
     } catch (IOException e) {
       logger.error(String.format("Borrow client from pool for group %s 
failed.", group), e);
-      return null;
+      // rethrow the exception
+      throw e;
     }
   }
 
   private RaftClientReply sendReconfiguration(RaftGroup newGroupConf)
       throws RatisRequestFailedException {
-    RaftClient client = buildClient(newGroupConf);
     // notify the group leader of configuration change
     RaftClientReply reply;
     try {
-      reply = client.admin().setConfiguration(new 
ArrayList<>(newGroupConf.getPeers()));
-      client.close();
+      RatisClient client = getRaftClient(newGroupConf);
+      reply =
+          client.getRaftClient().admin().setConfiguration(new 
ArrayList<>(newGroupConf.getPeers()));
+      client.returnSelf();
     } catch (IOException e) {
       throw new RatisRequestFailedException(e);
     }
     return reply;
   }
 
-  private class RatisClientPoolFactory implements 
IClientPoolFactory<RaftGroup, RaftClient> {
+  private class RatisClientPoolFactory implements 
IClientPoolFactory<RaftGroup, RatisClient> {
     @Override
-    public KeyedObjectPool<RaftGroup, RaftClient> createClientPool(
-        ClientManager<RaftGroup, RaftClient> manager) {
+    public KeyedObjectPool<RaftGroup, RatisClient> createClientPool(
+        ClientManager<RaftGroup, RatisClient> manager) {
       return new GenericKeyedObjectPool<>(
-          new RatisClientFactory(
+          new RatisClient.Factory(
               manager, new ClientFactoryProperty.Builder().build(), 
properties, clientRpc),
-          new ClientPoolProperty.Builder<RaftClient>().build().getConfig());
+          new ClientPoolProperty.Builder<RatisClient>().build().getConfig());
     }
   }
 }
diff --git 
a/consensus/src/test/java/org/apache/iotdb/consensus/ratis/RatisConsensusTest.java
 
b/consensus/src/test/java/org/apache/iotdb/consensus/ratis/RatisConsensusTest.java
index 282141b878..2b3e952823 100644
--- 
a/consensus/src/test/java/org/apache/iotdb/consensus/ratis/RatisConsensusTest.java
+++ 
b/consensus/src/test/java/org/apache/iotdb/consensus/ratis/RatisConsensusTest.java
@@ -122,7 +122,7 @@ public class RatisConsensusTest {
     // 3. Remove two Peers from Group (peer 0 and peer 2)
     // transfer the leader to peer1
     servers.get(0).transferLeader(gid, peer1);
-    Assert.assertTrue(servers.get(1).isLeader(gid));
+    // Assert.assertTrue(servers.get(1).isLeader(gid));
     // first use removePeer to inform the group leader of configuration change
     servers.get(1).removePeer(gid, peer0);
     servers.get(1).removePeer(gid, peer2);

Reply via email to