You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hugegraph.apache.org by je...@apache.org on 2023/12/02 23:12:46 UTC

(incubator-hugegraph) branch server-info-to-global updated (cb9f6e2cf -> 30505c397)

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

jermy pushed a change to branch server-info-to-global
in repository https://gitbox.apache.org/repos/asf/incubator-hugegraph.git


 discard cb9f6e2cf chore: move server info into GlobalNodeRoleInfo
     new 30505c397 chore: move server info into GlobalMasterInfo

This update added new revisions after undoing existing revisions.
That is to say, some revisions that were in the old version of the
branch are not in the new version.  This situation occurs
when a user --force pushes a change and generates a repository
containing something like this:

 * -- * -- B -- O -- O -- O   (cb9f6e2cf)
            \
             N -- N -- N   refs/heads/server-info-to-global (30505c397)

You should already have received notification emails for all of the O
revisions, and so the following emails describe only the N revisions
from the common base, B.

Any revisions marked "omit" are not gone; other references still
refer to them.  Any revisions marked "discard" are gone forever.

The 1 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.


Summary of changes:
 .../java/org/apache/hugegraph/api/filter/RedirectFilter.java |  6 +++---
 .../java/org/apache/hugegraph/auth/HugeGraphAuthProxy.java   |  6 +++---
 .../main/java/org/apache/hugegraph/core/GraphManager.java    |  8 ++++----
 .../src/main/java/org/apache/hugegraph/HugeGraph.java        |  6 +++---
 .../main/java/org/apache/hugegraph/StandardHugeGraph.java    |  6 +++---
 .../{GlobalNodeRoleInfo.java => GlobaMasterInfo.java}        | 12 ++++++------
 .../hugegraph/masterelection/StandardRoleListener.java       |  4 ++--
 .../java/org/apache/hugegraph/task/ServerInfoManager.java    |  8 ++++----
 .../main/java/org/apache/hugegraph/example/ExampleUtil.java  |  4 ++--
 .../main/java/org/apache/hugegraph/core/BaseCoreTest.java    |  4 ++--
 .../main/java/org/apache/hugegraph/core/MultiGraphsTest.java | 10 +++++-----
 .../main/java/org/apache/hugegraph/tinkerpop/TestGraph.java  |  4 ++--
 .../org/apache/hugegraph/unit/core/SecurityManagerTest.java  |  4 ++--
 13 files changed, 41 insertions(+), 41 deletions(-)
 rename hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/masterelection/{GlobalNodeRoleInfo.java => GlobaMasterInfo.java} (92%)


(incubator-hugegraph) 01/01: chore: move server info into GlobalMasterInfo

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

jermy pushed a commit to branch server-info-to-global
in repository https://gitbox.apache.org/repos/asf/incubator-hugegraph.git

commit 30505c39709dff48fad3f90a07dedbb5160bc387
Author: Jermy Li <je...@apache.org>
AuthorDate: Sun Dec 3 06:52:16 2023 +0800

    chore: move server info into GlobalMasterInfo
    
    Change-Id: Id854892333115fd45d7c8b9799d255627541b2ad
---
 .../hugegraph/api/filter/RedirectFilter.java       |  14 +--
 .../apache/hugegraph/auth/HugeGraphAuthProxy.java  |  10 +-
 .../org/apache/hugegraph/core/GraphManager.java    |  96 ++++++++---------
 .../main/java/org/apache/hugegraph/HugeGraph.java  |   8 +-
 .../org/apache/hugegraph/StandardHugeGraph.java    |  44 ++++----
 .../hugegraph/job/computer/AbstractComputer.java   |   8 +-
 .../hugegraph/masterelection/GlobaMasterInfo.java  | 119 +++++++++++++++++++++
 .../hugegraph/masterelection/GlobalMasterInfo.java |  66 ------------
 .../masterelection/RoleElectionStateMachine.java   |   2 +-
 ...StateMachineCallback.java => RoleListener.java} |   2 +-
 .../StandardRoleElectionStateMachine.java          |  53 +++++----
 ...hineCallback.java => StandardRoleListener.java} |  63 ++++++-----
 .../masterelection/StateMachineContext.java        |   2 +-
 .../apache/hugegraph/task/ServerInfoManager.java   |  88 +++++++--------
 .../hugegraph/task/StandardTaskScheduler.java      |  35 +++---
 .../org/apache/hugegraph/task/TaskManager.java     |  50 ++++-----
 .../org/apache/hugegraph/example/ExampleUtil.java  |   7 +-
 .../org/apache/hugegraph/core/BaseCoreTest.java    |   5 +-
 .../org/apache/hugegraph/core/MultiGraphsTest.java |  11 +-
 .../core/RoleElectionStateMachineTest.java         |  10 +-
 .../org/apache/hugegraph/tinkerpop/TestGraph.java  |  22 ++--
 .../hugegraph/unit/core/SecurityManagerTest.java   |  13 ++-
 22 files changed, 389 insertions(+), 339 deletions(-)

diff --git a/hugegraph-server/hugegraph-api/src/main/java/org/apache/hugegraph/api/filter/RedirectFilter.java b/hugegraph-server/hugegraph-api/src/main/java/org/apache/hugegraph/api/filter/RedirectFilter.java
index e675dd955..a08dc4b57 100644
--- a/hugegraph-server/hugegraph-api/src/main/java/org/apache/hugegraph/api/filter/RedirectFilter.java
+++ b/hugegraph-server/hugegraph-api/src/main/java/org/apache/hugegraph/api/filter/RedirectFilter.java
@@ -31,7 +31,7 @@ import java.util.Set;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.http.client.utils.URIBuilder;
 import org.apache.hugegraph.core.GraphManager;
-import org.apache.hugegraph.masterelection.GlobalMasterInfo;
+import org.apache.hugegraph.masterelection.GlobaMasterInfo;
 import org.apache.hugegraph.util.E;
 import org.apache.hugegraph.util.Log;
 import org.glassfish.hk2.api.IterableProvider;
@@ -82,16 +82,16 @@ public class RedirectFilter implements ContainerRequestFilter {
             return;
         }
 
-        GlobalMasterInfo globalMasterInfo = manager.globalMasterInfo();
-        if (globalMasterInfo == null || !globalMasterInfo.isFeatureSupport()) {
+        GlobaMasterInfo globalNodeInfo = manager.globalNodeRoleInfo();
+        if (globalNodeInfo == null || !globalNodeInfo.supportElection()) {
             return;
         }
-        GlobalMasterInfo.NodeInfo masterNodeInfo = globalMasterInfo.nodeInfo();
-        if (masterNodeInfo == null || masterNodeInfo.isMaster() ||
-            StringUtils.isEmpty(masterNodeInfo.url())) {
+        GlobaMasterInfo.NodeInfo masterInfo = globalNodeInfo.masterInfo();
+        if (masterInfo == null || masterInfo.isMaster() ||
+            StringUtils.isEmpty(masterInfo.nodeUrl())) {
             return;
         }
-        String url = masterNodeInfo.url();
+        String url = masterInfo.nodeUrl();
 
         URI redirectUri;
         try {
diff --git a/hugegraph-server/hugegraph-api/src/main/java/org/apache/hugegraph/auth/HugeGraphAuthProxy.java b/hugegraph-server/hugegraph-api/src/main/java/org/apache/hugegraph/auth/HugeGraphAuthProxy.java
index 2435e2667..dfe042c2b 100644
--- a/hugegraph-server/hugegraph-api/src/main/java/org/apache/hugegraph/auth/HugeGraphAuthProxy.java
+++ b/hugegraph-server/hugegraph-api/src/main/java/org/apache/hugegraph/auth/HugeGraphAuthProxy.java
@@ -55,6 +55,7 @@ import org.apache.hugegraph.config.TypedOption;
 import org.apache.hugegraph.exception.NotSupportException;
 import org.apache.hugegraph.iterator.FilterIterator;
 import org.apache.hugegraph.iterator.MapperIterator;
+import org.apache.hugegraph.masterelection.GlobaMasterInfo;
 import org.apache.hugegraph.masterelection.RoleElectionStateMachine;
 import org.apache.hugegraph.rpc.RpcServiceConfig4Client;
 import org.apache.hugegraph.rpc.RpcServiceConfig4Server;
@@ -78,7 +79,6 @@ import org.apache.hugegraph.type.HugeType;
 import org.apache.hugegraph.type.Nameable;
 import org.apache.hugegraph.type.define.GraphMode;
 import org.apache.hugegraph.type.define.GraphReadMode;
-import org.apache.hugegraph.type.define.NodeRole;
 import org.apache.hugegraph.util.E;
 import org.apache.hugegraph.util.Log;
 import org.apache.hugegraph.util.RateLimiter;
@@ -669,9 +669,9 @@ public final class HugeGraphAuthProxy implements HugeGraph {
     }
 
     @Override
-    public void serverStarted(Id serverId, NodeRole serverRole) {
+    public void serverStarted(GlobaMasterInfo serverInfo) {
         this.verifyAdminPermission();
-        this.hugegraph.serverStarted(serverId, serverRole);
+        this.hugegraph.serverStarted(serverInfo);
     }
 
     @Override
@@ -776,9 +776,9 @@ public final class HugeGraphAuthProxy implements HugeGraph {
     }
 
     @Override
-    public void create(String configPath, Id server, NodeRole role) {
+    public void create(String configPath, GlobaMasterInfo serverInfo) {
         this.verifyPermission(HugePermission.WRITE, ResourceType.STATUS);
-        this.hugegraph.create(configPath, server, role);
+        this.hugegraph.create(configPath, serverInfo);
     }
 
     @Override
diff --git a/hugegraph-server/hugegraph-api/src/main/java/org/apache/hugegraph/core/GraphManager.java b/hugegraph-server/hugegraph-api/src/main/java/org/apache/hugegraph/core/GraphManager.java
index 2c73b5ee9..c1ace6abd 100644
--- a/hugegraph-server/hugegraph-api/src/main/java/org/apache/hugegraph/core/GraphManager.java
+++ b/hugegraph-server/hugegraph-api/src/main/java/org/apache/hugegraph/core/GraphManager.java
@@ -23,8 +23,6 @@ import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.Executor;
-import java.util.concurrent.Executors;
 import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicInteger;
@@ -41,7 +39,6 @@ import org.apache.hugegraph.auth.StandardAuthenticator;
 import org.apache.hugegraph.backend.BackendException;
 import org.apache.hugegraph.backend.cache.Cache;
 import org.apache.hugegraph.backend.cache.CacheManager;
-import org.apache.hugegraph.backend.id.Id;
 import org.apache.hugegraph.backend.id.IdGenerator;
 import org.apache.hugegraph.backend.store.BackendStoreInfo;
 import org.apache.hugegraph.config.CoreOptions;
@@ -50,10 +47,10 @@ import org.apache.hugegraph.config.ServerOptions;
 import org.apache.hugegraph.config.TypedOption;
 import org.apache.hugegraph.event.EventHub;
 import org.apache.hugegraph.exception.NotSupportException;
-import org.apache.hugegraph.masterelection.GlobalMasterInfo;
+import org.apache.hugegraph.masterelection.GlobaMasterInfo;
 import org.apache.hugegraph.masterelection.RoleElectionOptions;
 import org.apache.hugegraph.masterelection.RoleElectionStateMachine;
-import org.apache.hugegraph.masterelection.StandardStateMachineCallback;
+import org.apache.hugegraph.masterelection.StandardRoleListener;
 import org.apache.hugegraph.metrics.MetricsUtil;
 import org.apache.hugegraph.metrics.ServerReporter;
 import org.apache.hugegraph.rpc.RpcClientProvider;
@@ -88,14 +85,11 @@ public final class GraphManager {
     private final HugeAuthenticator authenticator;
     private final RpcServer rpcServer;
     private final RpcClientProvider rpcClient;
-    private final HugeConfig conf;
-
-    private RoleElectionStateMachine roleStateWorker;
-    private GlobalMasterInfo globalMasterInfo;
 
-    private Id server;
-    private NodeRole role;
+    private RoleElectionStateMachine roleStateMachine;
+    private GlobaMasterInfo globalNodeRoleInfo;
 
+    private final HugeConfig conf;
     private final EventHub eventHub;
 
     public GraphManager(HugeConfig conf, EventHub hub) {
@@ -104,6 +98,10 @@ public final class GraphManager {
         this.authenticator = HugeAuthenticator.loadAuthenticator(conf);
         this.rpcServer = new RpcServer(conf);
         this.rpcClient = new RpcClientProvider(conf);
+
+        this.roleStateMachine = null;
+        this.globalNodeRoleInfo = new GlobaMasterInfo();
+
         this.eventHub = hub;
         this.conf = conf;
     }
@@ -141,8 +139,7 @@ public final class GraphManager {
         }
     }
 
-    public HugeGraph cloneGraph(String name, String newName,
-                                String configText) {
+    public HugeGraph cloneGraph(String name, String newName, String configText) {
         /*
          * 0. check and modify params
          * 1. create graph instance
@@ -270,6 +267,10 @@ public final class GraphManager {
         return this.authenticator().authManager();
     }
 
+    public GlobaMasterInfo globalNodeRoleInfo() {
+        return this.globalNodeRoleInfo;
+    }
+
     public void close() {
         for (Graph graph : this.graphs.values()) {
             try {
@@ -280,8 +281,8 @@ public final class GraphManager {
         }
         this.destroyRpcServer();
         this.unlistenChanges();
-        if (this.roleStateWorker != null) {
-            this.roleStateWorker.shutdown();
+        if (this.roleStateMachine != null) {
+            this.roleStateMachine.shutdown();
         }
     }
 
@@ -414,8 +415,7 @@ public final class GraphManager {
             LOG.info("RpcServer is not enabled, skip wait graphs ready");
             return;
         }
-        com.alipay.remoting.rpc.RpcServer remotingRpcServer =
-                                          this.remotingRpcServer();
+        com.alipay.remoting.rpc.RpcServer remotingRpcServer = this.remotingRpcServer();
         for (String graphName : this.graphs.keySet()) {
             HugeGraph graph = this.graph(graphName);
             graph.waitReady(remotingRpcServer);
@@ -433,7 +433,7 @@ public final class GraphManager {
                 if (this.requireAuthentication()) {
                     String token = config.get(ServerOptions.AUTH_ADMIN_TOKEN);
                     try {
-                        this.authenticator.initAdminUser(token);
+                        this.authenticator().initAdminUser(token);
                     } catch (Exception e) {
                         throw new BackendException(
                                   "The backend store of '%s' can't " +
@@ -455,65 +455,57 @@ public final class GraphManager {
     }
 
     private void serverStarted(HugeConfig config) {
-        String server = config.get(ServerOptions.SERVER_ID);
+        String serverId = config.get(ServerOptions.SERVER_ID);
         String role = config.get(ServerOptions.SERVER_ROLE);
-        E.checkArgument(StringUtils.isNotEmpty(server),
+        E.checkArgument(StringUtils.isNotEmpty(serverId),
                         "The server name can't be null or empty");
         E.checkArgument(StringUtils.isNotEmpty(role),
                         "The server role can't be null or empty");
-        this.server = IdGenerator.of(server);
-        this.role = NodeRole.valueOf(role.toUpperCase());
 
-        boolean supportRoleStateWorker = this.supportRoleStateWorker();
-        if (supportRoleStateWorker) {
-            this.role = NodeRole.WORKER;
+        NodeRole serverRole = NodeRole.valueOf(role.toUpperCase());
+        boolean supportRoleElection = !serverRole.computer() &&
+                                      this.supportRoleElection();
+        if (supportRoleElection) {
+            // Init any server as Worker role, then do role election
+            serverRole = NodeRole.WORKER;
         }
 
+        this.globalNodeRoleInfo.serverId(IdGenerator.of(serverId));
+        this.globalNodeRoleInfo.initServerRole(serverRole);
+
         for (String graph : this.graphs()) {
             HugeGraph hugegraph = this.graph(graph);
             assert hugegraph != null;
-            hugegraph.serverStarted(this.server, this.role);
+            hugegraph.serverStarted(this.globalNodeRoleInfo);
         }
 
-        if (supportRoleStateWorker) {
-            this.initRoleStateWorker();
+        if (supportRoleElection) {
+            this.initRoleStateMachine();
         }
     }
 
-    private void initRoleStateWorker() {
-        E.checkArgument(this.roleStateWorker == null, "Repetition init");
-        Executor applyThread = Executors.newSingleThreadExecutor();
-        this.roleStateWorker = this.authenticator().graph().roleElectionStateMachine();
-        this.globalMasterInfo = new GlobalMasterInfo();
-        StandardStateMachineCallback stateMachineCallback = new StandardStateMachineCallback(
-                                                                TaskManager.instance(),
-                                                                this.globalMasterInfo);
-        applyThread.execute(() -> {
-            this.roleStateWorker.apply(stateMachineCallback);
-        });
-    }
-
-    public GlobalMasterInfo globalMasterInfo() {
-        return this.globalMasterInfo;
+    private void initRoleStateMachine() {
+        E.checkArgument(this.roleStateMachine == null,
+                        "Repeated initialization of role state worker");
+        this.globalNodeRoleInfo.supportElection(true);
+        this.roleStateMachine = this.authenticator().graph().roleElectionStateMachine();
+        StandardRoleListener listener = new StandardRoleListener(TaskManager.instance(),
+                                                                 this.globalNodeRoleInfo);
+        this.roleStateMachine.start(listener);
     }
 
-    private boolean supportRoleStateWorker() {
-        if (this.role.computer()) {
-            return false;
-        }
-
+    private boolean supportRoleElection() {
         try {
             if (!(this.authenticator() instanceof StandardAuthenticator)) {
                 LOG.info("{} authenticator does not support role election currently",
                          this.authenticator().getClass().getSimpleName());
                 return false;
             }
+            return true;
         } catch (IllegalStateException e) {
-            LOG.info("Unconfigured StandardAuthenticator, not support role election currently");
+            LOG.info("{}, does not support role election currently", e.getMessage());
             return false;
         }
-
-        return true;
     }
 
     private void addMetrics(HugeConfig config) {
@@ -591,7 +583,7 @@ public final class GraphManager {
             graph = (HugeGraph) GraphFactory.open(config);
 
             // Init graph and start it
-            graph.create(this.graphsDir, this.server, this.role);
+            graph.create(this.graphsDir, this.globalNodeRoleInfo);
         } catch (Throwable e) {
             LOG.error("Failed to create graph '{}' due to: {}",
                       name, e.getMessage(), e);
diff --git a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/HugeGraph.java b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/HugeGraph.java
index cd287c47b..19ec24345 100644
--- a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/HugeGraph.java
+++ b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/HugeGraph.java
@@ -30,6 +30,7 @@ import org.apache.hugegraph.backend.store.BackendStoreInfo;
 import org.apache.hugegraph.backend.store.raft.RaftGroupManager;
 import org.apache.hugegraph.config.HugeConfig;
 import org.apache.hugegraph.config.TypedOption;
+import org.apache.hugegraph.masterelection.GlobaMasterInfo;
 import org.apache.hugegraph.masterelection.RoleElectionStateMachine;
 import org.apache.hugegraph.rpc.RpcServiceConfig4Client;
 import org.apache.hugegraph.rpc.RpcServiceConfig4Server;
@@ -44,12 +45,11 @@ import org.apache.hugegraph.structure.HugeFeatures;
 import org.apache.hugegraph.task.TaskScheduler;
 import org.apache.hugegraph.traversal.optimize.HugeCountStepStrategy;
 import org.apache.hugegraph.traversal.optimize.HugeGraphStepStrategy;
-import org.apache.hugegraph.traversal.optimize.HugeVertexStepStrategy;
 import org.apache.hugegraph.traversal.optimize.HugePrimaryKeyStrategy;
+import org.apache.hugegraph.traversal.optimize.HugeVertexStepStrategy;
 import org.apache.hugegraph.type.HugeType;
 import org.apache.hugegraph.type.define.GraphMode;
 import org.apache.hugegraph.type.define.GraphReadMode;
-import org.apache.hugegraph.type.define.NodeRole;
 import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategies;
 import org.apache.tinkerpop.gremlin.structure.Edge;
 import org.apache.tinkerpop.gremlin.structure.Graph;
@@ -201,7 +201,7 @@ public interface HugeGraph extends Graph {
 
     void waitReady(RpcServer rpcServer);
 
-    void serverStarted(Id serverId, NodeRole serverRole);
+    void serverStarted(GlobaMasterInfo serverInfo);
 
     boolean started();
 
@@ -221,7 +221,7 @@ public interface HugeGraph extends Graph {
 
     void resumeSnapshot();
 
-    void create(String configPath, Id server, NodeRole role);
+    void create(String configPath, GlobaMasterInfo serverInfo);
 
     void drop();
 
diff --git a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/StandardHugeGraph.java b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/StandardHugeGraph.java
index db37d0a4b..c180f3b63 100644
--- a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/StandardHugeGraph.java
+++ b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/StandardHugeGraph.java
@@ -51,7 +51,6 @@ import org.apache.hugegraph.backend.store.BackendStoreProvider;
 import org.apache.hugegraph.backend.store.raft.RaftBackendStoreProvider;
 import org.apache.hugegraph.backend.store.raft.RaftGroupManager;
 import org.apache.hugegraph.backend.store.ram.RamTable;
-import org.apache.hugegraph.task.EphemeralJobQueue;
 import org.apache.hugegraph.backend.tx.GraphTransaction;
 import org.apache.hugegraph.backend.tx.SchemaTransaction;
 import org.apache.hugegraph.config.CoreOptions;
@@ -64,6 +63,7 @@ import org.apache.hugegraph.io.HugeGraphIoRegistry;
 import org.apache.hugegraph.job.EphemeralJob;
 import org.apache.hugegraph.masterelection.ClusterRoleStore;
 import org.apache.hugegraph.masterelection.Config;
+import org.apache.hugegraph.masterelection.GlobaMasterInfo;
 import org.apache.hugegraph.masterelection.RoleElectionConfig;
 import org.apache.hugegraph.masterelection.RoleElectionOptions;
 import org.apache.hugegraph.masterelection.RoleElectionStateMachine;
@@ -84,13 +84,13 @@ import org.apache.hugegraph.structure.HugeEdgeProperty;
 import org.apache.hugegraph.structure.HugeFeatures;
 import org.apache.hugegraph.structure.HugeVertex;
 import org.apache.hugegraph.structure.HugeVertexProperty;
+import org.apache.hugegraph.task.EphemeralJobQueue;
 import org.apache.hugegraph.task.ServerInfoManager;
 import org.apache.hugegraph.task.TaskManager;
 import org.apache.hugegraph.task.TaskScheduler;
 import org.apache.hugegraph.type.HugeType;
 import org.apache.hugegraph.type.define.GraphMode;
 import org.apache.hugegraph.type.define.GraphReadMode;
-import org.apache.hugegraph.type.define.NodeRole;
 import org.apache.hugegraph.util.ConfigUtil;
 import org.apache.hugegraph.util.DateUtil;
 import org.apache.hugegraph.util.E;
@@ -267,15 +267,15 @@ public class StandardHugeGraph implements HugeGraph {
     }
 
     @Override
-    public void serverStarted(Id serverId, NodeRole serverRole) {
+    public void serverStarted(GlobaMasterInfo serverInfo) {
         LOG.info("Init system info for graph '{}'", this.name);
         this.initSystemInfo();
 
         LOG.info("Init server info [{}-{}] for graph '{}'...",
-                 serverId, serverRole, this.name);
-        this.serverInfoManager().initServerInfo(serverId, serverRole);
+                 serverInfo.serverId(), serverInfo.serverRole(), this.name);
+        this.serverInfoManager().initServerInfo(serverInfo);
 
-        this.initRoleStateWorker(serverId);
+        this.initRoleStateMachine(serverInfo.serverId());
 
         // TODO: check necessary?
         LOG.info("Check olap property-key tables for graph '{}'", this.name);
@@ -291,16 +291,18 @@ public class StandardHugeGraph implements HugeGraph {
         this.started = true;
     }
 
-    private void initRoleStateWorker(Id serverId) {
-        Config roleStateMachineConfig = new RoleElectionConfig(serverId.toString(),
-                                            this.configuration.get(RoleElectionOptions.NODE_EXTERNAL_URL),
-                                            this.configuration.get(RoleElectionOptions.EXCEEDS_FAIL_COUNT),
-                                            this.configuration.get(RoleElectionOptions.RANDOM_TIMEOUT_MILLISECOND),
-                                            this.configuration.get(RoleElectionOptions.HEARTBEAT_INTERVAL_SECOND),
-                                            this.configuration.get(RoleElectionOptions.MASTER_DEAD_TIMES),
-                                            this.configuration.get(RoleElectionOptions.BASE_TIMEOUT_MILLISECOND));
-        ClusterRoleStore clusterRoleStore = new StandardClusterRoleStore(this.params);
-        this.roleElectionStateMachine = new StandardRoleElectionStateMachine(roleStateMachineConfig, clusterRoleStore);
+    private void initRoleStateMachine(Id serverId) {
+        HugeConfig conf = this.configuration;
+        Config roleConfig = new RoleElectionConfig(serverId.toString(),
+                            conf.get(RoleElectionOptions.NODE_EXTERNAL_URL),
+                            conf.get(RoleElectionOptions.EXCEEDS_FAIL_COUNT),
+                            conf.get(RoleElectionOptions.RANDOM_TIMEOUT_MILLISECOND),
+                            conf.get(RoleElectionOptions.HEARTBEAT_INTERVAL_SECOND),
+                            conf.get(RoleElectionOptions.MASTER_DEAD_TIMES),
+                            conf.get(RoleElectionOptions.BASE_TIMEOUT_MILLISECOND));
+        ClusterRoleStore roleStore = new StandardClusterRoleStore(this.params);
+        this.roleElectionStateMachine = new StandardRoleElectionStateMachine(roleConfig, 
+                                                                             roleStore);
     }
 
     @Override
@@ -399,8 +401,7 @@ public class StandardHugeGraph implements HugeGraph {
         try {
             this.storeProvider.truncate();
             // TODO: remove this after serverinfo saved in etcd
-            this.serverStarted(this.serverInfoManager().selfServerId(),
-                               this.serverInfoManager().selfServerRole());
+            this.serverStarted(this.serverInfoManager().serverInfo());
         } finally {
             LockUtil.unlock(this.name, LockUtil.GRAPH_LOCK);
         }
@@ -974,9 +975,9 @@ public class StandardHugeGraph implements HugeGraph {
     }
 
     @Override
-    public void create(String configPath, Id server, NodeRole role) {
+    public void create(String configPath, GlobaMasterInfo serverInfo) {
         this.initBackend();
-        this.serverStarted(server, role);
+        this.serverStarted(serverInfo);
 
         // Write config to disk file
         String confPath = ConfigUtil.writeToFile(configPath, this.name(),
@@ -1052,8 +1053,7 @@ public class StandardHugeGraph implements HugeGraph {
     }
 
     private ServerInfoManager serverInfoManager() {
-        ServerInfoManager manager = this.taskManager
-                                        .getServerInfoManager(this.params);
+        ServerInfoManager manager = this.taskManager.getServerInfoManager(this.params);
         E.checkState(manager != null,
                      "Can't find server info manager for graph '%s'", this);
         return manager;
diff --git a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/job/computer/AbstractComputer.java b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/job/computer/AbstractComputer.java
index a40d0001b..11207ebae 100644
--- a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/job/computer/AbstractComputer.java
+++ b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/job/computer/AbstractComputer.java
@@ -32,16 +32,15 @@ import org.apache.commons.configuration2.io.FileHandler;
 import org.apache.commons.configuration2.tree.ImmutableNode;
 import org.apache.commons.configuration2.tree.NodeHandler;
 import org.apache.commons.configuration2.tree.NodeModel;
-import org.apache.hugegraph.type.define.Directions;
-import org.apache.hugegraph.util.ParameterUtil;
-import org.slf4j.Logger;
-
 import org.apache.hugegraph.HugeException;
 import org.apache.hugegraph.job.ComputerJob;
 import org.apache.hugegraph.job.Job;
 import org.apache.hugegraph.traversal.algorithm.HugeTraverser;
+import org.apache.hugegraph.type.define.Directions;
 import org.apache.hugegraph.util.E;
 import org.apache.hugegraph.util.Log;
+import org.apache.hugegraph.util.ParameterUtil;
+import org.slf4j.Logger;
 
 public abstract class AbstractComputer implements Computer {
 
@@ -85,7 +84,6 @@ public abstract class AbstractComputer implements Computer {
 
     @Override
     public Object call(Job<Object> job, Map<String, Object> parameters) {
-
         this.checkAndCollectParameters(parameters);
         // Read configuration
         try {
diff --git a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/masterelection/GlobaMasterInfo.java b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/masterelection/GlobaMasterInfo.java
new file mode 100644
index 000000000..dd8700a00
--- /dev/null
+++ b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/masterelection/GlobaMasterInfo.java
@@ -0,0 +1,119 @@
+/*
+ * 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.hugegraph.masterelection;
+
+import org.apache.hugegraph.backend.id.Id;
+import org.apache.hugegraph.backend.id.IdGenerator;
+import org.apache.hugegraph.type.define.NodeRole;
+import org.apache.hugegraph.util.E;
+
+// TODO: rename to GlobaNodeRoleInfo
+public final class GlobaMasterInfo {
+
+    private final static NodeInfo NO_MASTER = new NodeInfo(false, "");
+
+    private volatile boolean supportElection;
+    private volatile NodeInfo masterNodeInfo;
+
+    private volatile Id serverId;
+    private volatile NodeRole serverRole;
+
+    public GlobaMasterInfo() {
+        this(NO_MASTER);
+    }
+
+    public GlobaMasterInfo(NodeInfo masterInfo) {
+        this.supportElection = false;
+        this.masterNodeInfo = masterInfo;
+
+        this.serverId = null;
+        this.serverRole = null;
+    }
+
+    public void supportElection(boolean featureSupport) {
+        this.supportElection = featureSupport;
+    }
+
+    public boolean supportElection() {
+        return this.supportElection;
+    }
+
+    public void resetMasterInfo() {
+        this.masterNodeInfo = NO_MASTER;
+    }
+
+    public void masterInfo(boolean isMaster, String nodeUrl) {
+        // final can avoid instruction rearrangement, visibility can be ignored
+        this.masterNodeInfo = new NodeInfo(isMaster, nodeUrl);
+    }
+
+    public NodeInfo masterInfo() {
+        return this.masterNodeInfo;
+    }
+
+    public Id serverId() {
+        return this.serverId;
+    }
+
+    public NodeRole serverRole() {
+        return this.serverRole;
+    }
+
+    public void serverId(Id id) {
+        this.serverId = id;
+    }
+
+    public void initServerRole(NodeRole role) {
+        E.checkArgument(role != null, "The server role can't be null");
+        E.checkArgument(this.serverRole == null,
+                        "The server role can't be init twice");
+        this.serverRole = role;
+    }
+
+    public void changeServerRole(NodeRole role) {
+        E.checkArgument(role != null, "The server role can't be null");
+        this.serverRole = role;
+    }
+
+    public static GlobaMasterInfo master(String serverId) {
+        NodeInfo masterInfo = new NodeInfo(true, serverId);
+        GlobaMasterInfo serverInfo = new GlobaMasterInfo(masterInfo);
+        serverInfo.serverId = IdGenerator.of(serverId);
+        serverInfo.serverRole = NodeRole.MASTER;
+        return serverInfo;
+    }
+
+    public static class NodeInfo {
+
+        private final boolean isMaster;
+        private final String nodeUrl;
+
+        public NodeInfo(boolean isMaster, String url) {
+            this.isMaster = isMaster;
+            this.nodeUrl = url;
+        }
+
+        public boolean isMaster() {
+            return this.isMaster;
+        }
+
+        public String nodeUrl() {
+            return this.nodeUrl;
+        }
+    }
+}
diff --git a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/masterelection/GlobalMasterInfo.java b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/masterelection/GlobalMasterInfo.java
deleted file mode 100644
index d7dd127af..000000000
--- a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/masterelection/GlobalMasterInfo.java
+++ /dev/null
@@ -1,66 +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.hugegraph.masterelection;
-
-public class GlobalMasterInfo {
-
-    private NodeInfo nodeInfo;
-    private volatile boolean featureSupport;
-
-    public GlobalMasterInfo() {
-        this.featureSupport = false;
-        this.nodeInfo = new NodeInfo(false, "");
-    }
-
-    public final void nodeInfo(boolean isMaster, String url) {
-        // final can avoid instruction rearrangement, visibility can be ignored
-        final NodeInfo tmp = new NodeInfo(isMaster, url);
-        this.nodeInfo = tmp;
-    }
-
-    public final NodeInfo nodeInfo() {
-        return this.nodeInfo;
-    }
-
-    public void isFeatureSupport(boolean featureSupport) {
-        this.featureSupport = featureSupport;
-    }
-
-    public boolean isFeatureSupport() {
-        return this.featureSupport;
-    }
-
-    public static class NodeInfo {
-
-        private final boolean isMaster;
-        private final String url;
-
-        public NodeInfo(boolean isMaster, String url) {
-            this.isMaster = isMaster;
-            this.url = url;
-        }
-
-        public boolean isMaster() {
-            return this.isMaster;
-        }
-
-        public String url() {
-            return this.url;
-        }
-    }
-}
diff --git a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/masterelection/RoleElectionStateMachine.java b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/masterelection/RoleElectionStateMachine.java
index 920bc104f..2a33d1bf6 100644
--- a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/masterelection/RoleElectionStateMachine.java
+++ b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/masterelection/RoleElectionStateMachine.java
@@ -21,5 +21,5 @@ public interface RoleElectionStateMachine {
 
     void shutdown();
 
-    void apply(StateMachineCallback stateMachineCallback);
+    void start(RoleListener callback);
 }
diff --git a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/masterelection/StateMachineCallback.java b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/masterelection/RoleListener.java
similarity index 96%
rename from hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/masterelection/StateMachineCallback.java
rename to hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/masterelection/RoleListener.java
index 35abbe340..e99db4c16 100644
--- a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/masterelection/StateMachineCallback.java
+++ b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/masterelection/RoleListener.java
@@ -17,7 +17,7 @@
 
 package org.apache.hugegraph.masterelection;
 
-public interface StateMachineCallback {
+public interface RoleListener {
 
     void onAsRoleMaster(StateMachineContext context);
 
diff --git a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/masterelection/StandardRoleElectionStateMachine.java b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/masterelection/StandardRoleElectionStateMachine.java
index aa284def6..a0e2601d4 100644
--- a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/masterelection/StandardRoleElectionStateMachine.java
+++ b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/masterelection/StandardRoleElectionStateMachine.java
@@ -19,6 +19,8 @@ package org.apache.hugegraph.masterelection;
 
 import java.security.SecureRandom;
 import java.util.Optional;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
 import java.util.concurrent.locks.LockSupport;
 
 import org.apache.hugegraph.util.E;
@@ -29,25 +31,36 @@ public class StandardRoleElectionStateMachine implements RoleElectionStateMachin
 
     private static final Logger LOG = Log.logger(StandardRoleElectionStateMachine.class);
 
-    private volatile boolean shutdown;
     private final Config config;
+    private final ClusterRoleStore roleStore;
+    private final ExecutorService applyThread;
+
+    private volatile boolean shutdown;
     private volatile RoleState state;
-    private final ClusterRoleStore clusterRoleStore;
 
-    public StandardRoleElectionStateMachine(Config config, ClusterRoleStore clusterRoleStore) {
+    public StandardRoleElectionStateMachine(Config config, ClusterRoleStore roleStore) {
         this.config = config;
-        this.clusterRoleStore = clusterRoleStore;
+        this.roleStore = roleStore;
+        this.applyThread = Executors.newSingleThreadExecutor();
         this.state = new UnknownState(null);
         this.shutdown = false;
     }
 
     @Override
     public void shutdown() {
+        if (this.shutdown) {
+            return;
+        }
         this.shutdown = true;
+        this.applyThread.shutdown();
     }
 
     @Override
-    public void apply(StateMachineCallback stateMachineCallback) {
+    public void start(RoleListener stateMachineCallback) {
+        this.applyThread.execute(() -> this.apply(stateMachineCallback));
+    }
+
+    private void apply(RoleListener stateMachineCallback) {
         int failCount = 0;
         StateMachineContextImpl context = new StateMachineContextImpl(this);
         while (!this.shutdown) {
@@ -73,13 +86,17 @@ public class StandardRoleElectionStateMachine implements RoleElectionStateMachin
         }
     }
 
+    protected ClusterRoleStore roleStore() {
+        return this.roleStore;
+    }
+
     private interface RoleState {
 
         SecureRandom SECURE_RANDOM = new SecureRandom();
 
         RoleState transform(StateMachineContext context);
 
-        Callback callback(StateMachineCallback callback);
+        Callback callback(RoleListener callback);
 
         static void heartBeatPark(StateMachineContext context) {
             long heartBeatIntervalSecond = context.config().heartBeatIntervalSecond();
@@ -110,7 +127,7 @@ public class StandardRoleElectionStateMachine implements RoleElectionStateMachin
 
         @Override
         public RoleState transform(StateMachineContext context) {
-            ClusterRoleStore adapter = context.adapter();
+            ClusterRoleStore adapter = context.roleStore();
             Optional<ClusterRole> clusterRoleOpt = adapter.query();
             if (!clusterRoleOpt.isPresent()) {
                 context.reset();
@@ -137,7 +154,7 @@ public class StandardRoleElectionStateMachine implements RoleElectionStateMachin
         }
 
         @Override
-        public Callback callback(StateMachineCallback callback) {
+        public Callback callback(RoleListener callback) {
             return callback::unknown;
         }
     }
@@ -158,7 +175,7 @@ public class StandardRoleElectionStateMachine implements RoleElectionStateMachin
         }
 
         @Override
-        public Callback callback(StateMachineCallback callback) {
+        public Callback callback(RoleListener callback) {
             return callback::onAsRoleAbdication;
         }
     }
@@ -175,7 +192,7 @@ public class StandardRoleElectionStateMachine implements RoleElectionStateMachin
         public RoleState transform(StateMachineContext context) {
             this.clusterRole.increaseClock();
             RoleState.heartBeatPark(context);
-            if (context.adapter().updateIfNodePresent(this.clusterRole)) {
+            if (context.roleStore().updateIfNodePresent(this.clusterRole)) {
                 return this;
             }
             context.reset();
@@ -184,7 +201,7 @@ public class StandardRoleElectionStateMachine implements RoleElectionStateMachin
         }
 
         @Override
-        public Callback callback(StateMachineCallback callback) {
+        public Callback callback(RoleListener callback) {
             return callback::onAsRoleMaster;
         }
     }
@@ -216,7 +233,7 @@ public class StandardRoleElectionStateMachine implements RoleElectionStateMachin
         }
 
         @Override
-        public Callback callback(StateMachineCallback callback) {
+        public Callback callback(RoleListener callback) {
             return callback::onAsRoleWorker;
         }
 
@@ -255,7 +272,7 @@ public class StandardRoleElectionStateMachine implements RoleElectionStateMachin
                                                       context.config().url(), epoch);
             // The master failover completed
             context.epoch(clusterRole.epoch());
-            if (context.adapter().updateIfNodePresent(clusterRole)) {
+            if (context.roleStore().updateIfNodePresent(clusterRole)) {
                 context.master(new MasterServerInfoImpl(clusterRole.node(), clusterRole.url()));
                 return new MasterState(clusterRole);
             } else {
@@ -264,7 +281,7 @@ public class StandardRoleElectionStateMachine implements RoleElectionStateMachin
         }
 
         @Override
-        public Callback callback(StateMachineCallback callback) {
+        public Callback callback(RoleListener callback) {
             return callback::onAsRoleCandidate;
         }
     }
@@ -303,8 +320,8 @@ public class StandardRoleElectionStateMachine implements RoleElectionStateMachin
         }
 
         @Override
-        public ClusterRoleStore adapter() {
-            return this.machine.adapter();
+        public ClusterRoleStore roleStore() {
+            return this.machine.roleStore();
         }
 
         @Override
@@ -348,8 +365,4 @@ public class StandardRoleElectionStateMachine implements RoleElectionStateMachin
             return this.node;
         }
     }
-
-    protected ClusterRoleStore adapter() {
-        return this.clusterRoleStore;
-    }
 }
diff --git a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/masterelection/StandardStateMachineCallback.java b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/masterelection/StandardRoleListener.java
similarity index 67%
rename from hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/masterelection/StandardStateMachineCallback.java
rename to hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/masterelection/StandardRoleListener.java
index 28e01d291..311ad5290 100644
--- a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/masterelection/StandardStateMachineCallback.java
+++ b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/masterelection/StandardRoleListener.java
@@ -23,84 +23,83 @@ import org.apache.hugegraph.task.TaskManager;
 import org.apache.hugegraph.util.Log;
 import org.slf4j.Logger;
 
-public class StandardStateMachineCallback implements StateMachineCallback {
+public class StandardRoleListener implements RoleListener {
 
-    private static final Logger LOG = Log.logger(StandardStateMachineCallback.class);
+    private static final Logger LOG = Log.logger(StandardRoleListener.class);
 
     private final TaskManager taskManager;
 
-    private final GlobalMasterInfo globalMasterInfo;
+    private final GlobaMasterInfo roleInfo;
 
-    private boolean isMaster = false;
+    private volatile boolean selfIsMaster;
 
-    public StandardStateMachineCallback(TaskManager taskManager, 
-                                        GlobalMasterInfo globalMasterInfo) {
+    public StandardRoleListener(TaskManager taskManager, 
+                                GlobaMasterInfo roleInfo) {
         this.taskManager = taskManager;
-        this.taskManager.enableRoleElected(true);
-        this.globalMasterInfo = globalMasterInfo;
-        this.globalMasterInfo.isFeatureSupport(true);
+        this.taskManager.enableRoleElection();
+        this.roleInfo = roleInfo;
+        this.selfIsMaster = false;
     }
 
     @Override
     public void onAsRoleMaster(StateMachineContext context) {
-        if (!isMaster) {
+        if (!selfIsMaster) {
             this.taskManager.onAsRoleMaster();
             LOG.info("Server {} change to master role", context.config().node());
         }
-        this.initGlobalMasterInfo(context);
-        this.isMaster = true;
+        this.updateMasterInfo(context);
+        this.selfIsMaster = true;
     }
 
     @Override
     public void onAsRoleWorker(StateMachineContext context) {
-        if (isMaster) {
+        if (this.selfIsMaster) {
             this.taskManager.onAsRoleWorker();
             LOG.info("Server {} change to worker role", context.config().node());
         }
-        this.initGlobalMasterInfo(context);
-        this.isMaster = false;
+        this.updateMasterInfo(context);
+        this.selfIsMaster = false;
     }
 
     @Override
     public void onAsRoleCandidate(StateMachineContext context) {
+        // pass
     }
 
     @Override
-    public void unknown(StateMachineContext context) {
-        if (isMaster) {
+    public void onAsRoleAbdication(StateMachineContext context) {
+        if (this.selfIsMaster) {
             this.taskManager.onAsRoleWorker();
             LOG.info("Server {} change to worker role", context.config().node());
         }
-        this.initGlobalMasterInfo(context);
+        this.updateMasterInfo(context);
+        this.selfIsMaster = false;
+    }
 
-        isMaster = false;
+    @Override
+    public void error(StateMachineContext context, Throwable e) {
+        LOG.error("Server {} exception occurred", context.config().node(), e);
     }
 
     @Override
-    public void onAsRoleAbdication(StateMachineContext context) {
-        if (isMaster) {
+    public void unknown(StateMachineContext context) {
+        if (this.selfIsMaster) {
             this.taskManager.onAsRoleWorker();
             LOG.info("Server {} change to worker role", context.config().node());
         }
-        this.initGlobalMasterInfo(context);
-
-        isMaster = false;
-    }
+        this.updateMasterInfo(context);
 
-    @Override
-    public void error(StateMachineContext context, Throwable e) {
-        LOG.error("Server {} exception occurred", context.config().node(), e);
+        this.selfIsMaster = false;
     }
 
-    public void initGlobalMasterInfo(StateMachineContext context) {
+    public void updateMasterInfo(StateMachineContext context) {
         StateMachineContext.MasterServerInfo master = context.master();
         if (master == null) {
-            this.globalMasterInfo.nodeInfo(false, "");
+            this.roleInfo.resetMasterInfo();
             return;
         }
 
         boolean isMaster = Objects.equals(context.node(), master.node());
-        String url = master.url();
-        this.globalMasterInfo.nodeInfo(isMaster, url);
+        this.roleInfo.masterInfo(isMaster, master.url());
     }
 }
diff --git a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/masterelection/StateMachineContext.java b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/masterelection/StateMachineContext.java
index a3eaf8962..587cd417f 100644
--- a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/masterelection/StateMachineContext.java
+++ b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/masterelection/StateMachineContext.java
@@ -33,7 +33,7 @@ public interface StateMachineContext {
 
     void master(MasterServerInfo info);
 
-    ClusterRoleStore adapter();
+    ClusterRoleStore roleStore();
 
     void reset();
 
diff --git a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/task/ServerInfoManager.java b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/task/ServerInfoManager.java
index e8cccf88e..d264aab0e 100644
--- a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/task/ServerInfoManager.java
+++ b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/task/ServerInfoManager.java
@@ -37,6 +37,7 @@ import org.apache.hugegraph.backend.tx.GraphTransaction;
 import org.apache.hugegraph.exception.ConnectionException;
 import org.apache.hugegraph.iterator.ListIterator;
 import org.apache.hugegraph.iterator.MapperIterator;
+import org.apache.hugegraph.masterelection.GlobaMasterInfo;
 import org.apache.hugegraph.schema.PropertyKey;
 import org.apache.hugegraph.schema.VertexLabel;
 import org.apache.hugegraph.structure.HugeVertex;
@@ -61,8 +62,7 @@ public class ServerInfoManager {
     private final HugeGraphParams graph;
     private final ExecutorService dbExecutor;
 
-    private Id selfServerId;
-    private NodeRole selfServerRole;
+    private GlobaMasterInfo globalServerInfo;
 
     private volatile boolean onlySingleNode;
     private volatile boolean closed;
@@ -75,8 +75,7 @@ public class ServerInfoManager {
         this.graph = graph;
         this.dbExecutor = dbExecutor;
 
-        this.selfServerId = null;
-        this.selfServerRole = NodeRole.MASTER;
+        this.globalServerInfo = null;
 
         this.onlySingleNode = false;
         this.closed = false;
@@ -103,40 +102,24 @@ public class ServerInfoManager {
         return true;
     }
 
-    public synchronized void forceInitServerInfo(Id server, NodeRole role) {
-        if (this.closed) {
-            return;
-        }
-
-        E.checkArgument(server != null && role != null,
-                        "The server id or role can't be null");
-        this.selfServerId = server;
-        this.selfServerRole = role;
-
-        this.saveServerInfo(this.selfServerId, this.selfServerRole);
-    }
-
-    public synchronized void initServerInfo(Id server, NodeRole role) {
-        E.checkArgument(server != null && role != null,
-                        "The server id or role can't be null");
-        this.selfServerId = server;
-        this.selfServerRole = role;
+    public synchronized void initServerInfo(GlobaMasterInfo serverInfo) {
+        E.checkArgument(serverInfo != null, "The global node info can't be null");
+        this.globalServerInfo = serverInfo;
+        Id serverId = this.globalServerInfo.serverId();
 
-        HugeServerInfo existed = this.serverInfo(server);
+        HugeServerInfo existed = this.serverInfo(serverId);
         E.checkArgument(existed == null || !existed.alive(),
                         "The server with name '%s' already in cluster",
-                        server);
-        if (role.master()) {
+                        serverId);
+        if (this.globalServerInfo.serverRole().master()) {
             String page = this.supportsPaging() ? PageInfo.PAGE_NONE : null;
             do {
-                Iterator<HugeServerInfo> servers = this.serverInfos(PAGE_SIZE,
-                                                                    page);
+                Iterator<HugeServerInfo> servers = this.serverInfos(PAGE_SIZE, page);
                 while (servers.hasNext()) {
                     existed = servers.next();
-                    E.checkArgument(!existed.role().master() ||
-                                    !existed.alive(),
-                                    "Already existed master '%s' in current " +
-                                    "cluster", existed.id());
+                    E.checkArgument(!existed.role().master() || !existed.alive(),
+                                    "Already existed master '%s' in current cluster", 
+                                    existed.id());
                 }
                 if (page != null) {
                     page = PageInfo.pageInfo(servers);
@@ -145,19 +128,39 @@ public class ServerInfoManager {
         }
 
         // TODO: save ServerInfo at AuthServer
-        this.saveServerInfo(this.selfServerId, this.selfServerRole);
+        this.saveServerInfo(this.selfServerId(), this.selfServerRole());
+    }
+
+    public synchronized void changeServerRole(NodeRole serverRole) {
+        if (this.closed) {
+            return;
+        }
+
+        this.globalServerInfo.changeServerRole(serverRole);
+
+        this.saveServerInfo(this.selfServerId(), this.selfServerRole());
+    }
+
+    public GlobaMasterInfo serverInfo() {
+        return this.globalServerInfo;
     }
 
     public Id selfServerId() {
-        return this.selfServerId;
+        if (this.globalServerInfo == null) {
+            return null;
+        }
+        return this.globalServerInfo.serverId();
     }
 
     public NodeRole selfServerRole() {
-        return this.selfServerRole;
+        if (this.globalServerInfo == null) {
+            return null;
+        }
+        return this.globalServerInfo.serverRole();
     }
 
     public boolean master() {
-        return this.selfServerRole != null && this.selfServerRole.master();
+        return this.selfServerRole() != null && this.selfServerRole().master();
     }
 
     public boolean onlySingleNode() {
@@ -167,10 +170,9 @@ public class ServerInfoManager {
 
     public void heartbeat() {
         HugeServerInfo serverInfo = this.selfServerInfo();
-        if (serverInfo == null && this.selfServerId != null &&
-            this.selfServerRole != NodeRole.MASTER) {
-            serverInfo = this.saveServerInfo(this.selfServerId,
-                                             this.selfServerRole);
+        if (serverInfo == null && this.selfServerId() != null &&
+            this.selfServerRole() != NodeRole.MASTER) {
+            serverInfo = this.saveServerInfo(this.selfServerId(), this.selfServerRole());
         }
         serverInfo.updateTime(DateUtil.now());
         this.save(serverInfo);
@@ -310,9 +312,9 @@ public class ServerInfoManager {
     }
 
     private HugeServerInfo selfServerInfo() {
-        HugeServerInfo selfServerInfo = this.serverInfo(this.selfServerId);
+        HugeServerInfo selfServerInfo = this.serverInfo(this.selfServerId());
         if (selfServerInfo == null) {
-            LOG.warn("ServerInfo is missing: {}", this.selfServerId);
+            LOG.warn("ServerInfo is missing: {}", this.selfServerId());
         }
         return selfServerInfo;
     }
@@ -335,8 +337,8 @@ public class ServerInfoManager {
          * backend store, initServerInfo() is not called in this case, so
          * this.selfServerId is null at this time.
          */
-        if (this.selfServerId != null && this.graph.initialized()) {
-            return this.removeServerInfo(this.selfServerId);
+        if (this.selfServerId() != null && this.graph.initialized()) {
+            return this.removeServerInfo(this.selfServerId());
         }
         return null;
     }
diff --git a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/task/StandardTaskScheduler.java b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/task/StandardTaskScheduler.java
index 9eda3f6b0..bf0a16314 100644
--- a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/task/StandardTaskScheduler.java
+++ b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/task/StandardTaskScheduler.java
@@ -177,32 +177,32 @@ public class StandardTaskScheduler implements TaskScheduler {
     public <V> Future<?> schedule(HugeTask<V> task) {
         E.checkArgumentNotNull(task, "Task can't be null");
 
+        /*
+         * Just submit to queue if status=QUEUED (means re-schedule task)
+         * NOTE: schedule() method may be called multi times by
+         * HugeTask.checkDependenciesSuccess() method
+         */
         if (task.status() == TaskStatus.QUEUED) {
-            /*
-             * Just submit to queue if status=QUEUED (means re-schedule task)
-             * NOTE: schedule() method may be called multi times by
-             * HugeTask.checkDependenciesSuccess() method
-             */
             return this.resubmitTask(task);
         }
 
+        /*
+         * Due to EphemeralJob won't be serialized and deserialized through
+         * shared storage, submit EphemeralJob immediately on any node
+         */
         if (task.callable() instanceof EphemeralJob) {
-            /*
-             * Due to EphemeralJob won't be serialized and deserialized through
-             * shared storage, submit EphemeralJob immediately on master
-             * NOTE: don't need to save EphemeralJob task
-             */
+            // NOTE: we don't need to save EphemeralJob task
             task.status(TaskStatus.QUEUED);
             return this.submitTask(task);
         }
 
-        // Only check if not EphemeralJob
+        // Check this is on master for normal task schedule
         this.checkOnMasterNode("schedule");
 
         if (this.serverManager().onlySingleNode() && !task.computer()) {
             /*
              * Speed up for single node, submit task immediately,
-             * this code can be removed without affecting logic
+             * this code can be removed without affecting code logic
              */
             task.status(TaskStatus.QUEUED);
             task.server(this.serverManager().selfServerId());
@@ -303,10 +303,10 @@ public class StandardTaskScheduler implements TaskScheduler {
         return this.serverManager;
     }
 
-    protected synchronized void scheduleTasks() {
+    protected synchronized void scheduleTasksOnMaster() {
         // Master server schedule all scheduling tasks to suitable worker nodes
-        Collection<HugeServerInfo> scheduleInfos = this.serverManager()
-                                                       .allServerInfos();
+        Collection<HugeServerInfo> serverInfos = this.serverManager()
+                                                     .allServerInfos();
         String page = this.supportsPaging() ? PageInfo.PAGE_NONE : null;
         do {
             Iterator<HugeTask<Object>> tasks = this.tasks(TaskStatus.SCHEDULING,
@@ -323,7 +323,7 @@ public class StandardTaskScheduler implements TaskScheduler {
                 }
 
                 HugeServerInfo server = this.serverManager().pickWorkerNode(
-                                        scheduleInfos, task);
+                                        serverInfos, task);
                 if (server == null) {
                     LOG.info("The master can't find suitable servers to " +
                              "execute task '{}', wait for next schedule",
@@ -348,7 +348,8 @@ public class StandardTaskScheduler implements TaskScheduler {
             }
         } while (page != null);
 
-        this.serverManager().updateServerInfos(scheduleInfos);
+        // Save to store
+        this.serverManager().updateServerInfos(serverInfos);
     }
 
     protected void executeTasksOnWorker(Id server) {
diff --git a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/task/TaskManager.java b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/task/TaskManager.java
index 0ad96f443..bb3af44f4 100644
--- a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/task/TaskManager.java
+++ b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/task/TaskManager.java
@@ -243,19 +243,8 @@ public final class TaskManager {
         return size;
     }
 
-    protected void notifyNewTask(HugeTask<?> task) {
-        Queue<Runnable> queue = ((ThreadPoolExecutor) this.schedulerExecutor)
-                                                          .getQueue();
-        if (queue.size() <= 1) {
-            /*
-             * Notify to schedule tasks initiatively when have new task
-             * It's OK to not notify again if there are more than one task in
-             * queue(like two, one is timer task, one is immediate task),
-             * we don't want too many immediate tasks to be inserted into queue,
-             * one notify will cause all the tasks to be processed.
-             */
-            this.schedulerExecutor.submit(this::scheduleOrExecuteJob);
-        }
+    public void enableRoleElection() {
+        this.enableRoleElected = true;
     }
 
     public void onAsRoleMaster() {
@@ -263,7 +252,7 @@ public final class TaskManager {
             for (TaskScheduler entry : this.schedulers.values()) {
                 StandardTaskScheduler scheduler = (StandardTaskScheduler) entry;
                 ServerInfoManager serverInfoManager = scheduler.serverManager();
-                serverInfoManager.forceInitServerInfo(serverInfoManager.selfServerId(), NodeRole.MASTER);
+                serverInfoManager.changeServerRole(NodeRole.MASTER);
             }
         } catch (Throwable e) {
             LOG.error("Exception occurred when change to master role", e);
@@ -276,7 +265,7 @@ public final class TaskManager {
             for (TaskScheduler entry : this.schedulers.values()) {
                 StandardTaskScheduler scheduler = (StandardTaskScheduler) entry;
                 ServerInfoManager serverInfoManager = scheduler.serverManager();
-                serverInfoManager.forceInitServerInfo(serverInfoManager.selfServerId(), NodeRole.WORKER);
+                serverInfoManager.changeServerRole(NodeRole.WORKER);
             }
         } catch (Throwable e) {
             LOG.error("Exception occurred when change to worker role", e);
@@ -284,8 +273,19 @@ public final class TaskManager {
         }
     }
 
-    public void enableRoleElected(boolean enableRoleElected) {
-        this.enableRoleElected = enableRoleElected;
+    protected void notifyNewTask(HugeTask<?> task) {
+        Queue<Runnable> queue = ((ThreadPoolExecutor) this.schedulerExecutor)
+                                                          .getQueue();
+        if (queue.size() <= 1) {
+            /*
+             * Notify to schedule tasks initiatively when have new task
+             * It's OK to not notify again if there are more than one task in
+             * queue(like two, one is timer task, one is immediate task),
+             * we don't want too many immediate tasks to be inserted into queue,
+             * one notify will cause all the tasks to be processed.
+             */
+            this.schedulerExecutor.submit(this::scheduleOrExecuteJob);
+        }
     }
 
     private void scheduleOrExecuteJob() {
@@ -332,21 +332,21 @@ public final class TaskManager {
             serverManager.heartbeat();
 
             /*
-             * Master schedule tasks to suitable servers.
-             * Worker maybe become Master, so Master also need perform tasks assigned by
-             * previous Master when enableRoleElected is true.
-             * However, the master only needs to take the assignment,
-             * because the master stays the same when enableRoleElected is false.
-             * There is no suitable server when these tasks are created
+             * Master will schedule tasks to suitable servers.
+             * Note a Worker may become to a Master, so elected-Master also needs to
+             * execute tasks assigned by previous Master when enableRoleElected=true.
+             * However, when enableRoleElected=false, a Master is only set by the
+             * config assignment, assigned-Master always stays the same state.
              */
             if (serverManager.master()) {
-                scheduler.scheduleTasks();
+                scheduler.scheduleTasksOnMaster();
                 if (!this.enableRoleElected && !serverManager.onlySingleNode()) {
+                    // assigned-Master + non-single-node don't need to execute tasks
                     return;
                 }
             }
 
-            // Schedule queued tasks scheduled to current server
+            // Execute queued tasks scheduled to current server
             scheduler.executeTasksOnWorker(serverManager.selfServerId());
 
             // Cancel tasks scheduled to current server
diff --git a/hugegraph-server/hugegraph-example/src/main/java/org/apache/hugegraph/example/ExampleUtil.java b/hugegraph-server/hugegraph-example/src/main/java/org/apache/hugegraph/example/ExampleUtil.java
index 7cb148262..16b14a757 100644
--- a/hugegraph-server/hugegraph-example/src/main/java/org/apache/hugegraph/example/ExampleUtil.java
+++ b/hugegraph-server/hugegraph-example/src/main/java/org/apache/hugegraph/example/ExampleUtil.java
@@ -20,18 +20,17 @@ package org.apache.hugegraph.example;
 import java.io.File;
 import java.util.Iterator;
 import java.util.concurrent.TimeoutException;
-import org.slf4j.Logger;
 
 import org.apache.hugegraph.HugeException;
 import org.apache.hugegraph.HugeFactory;
 import org.apache.hugegraph.HugeGraph;
-import org.apache.hugegraph.backend.id.IdGenerator;
 import org.apache.hugegraph.dist.RegisterUtil;
+import org.apache.hugegraph.masterelection.GlobaMasterInfo;
 import org.apache.hugegraph.perf.PerfUtil;
 import org.apache.hugegraph.task.HugeTask;
 import org.apache.hugegraph.task.TaskScheduler;
-import org.apache.hugegraph.type.define.NodeRole;
 import org.apache.hugegraph.util.Log;
+import org.slf4j.Logger;
 
 public class ExampleUtil {
     private static final Logger LOG = Log.logger(ExampleUtil.class);
@@ -81,7 +80,7 @@ public class ExampleUtil {
             graph.clearBackend();
         }
         graph.initBackend();
-        graph.serverStarted(IdGenerator.of("server1"), NodeRole.MASTER);
+        graph.serverStarted(GlobaMasterInfo.master("server1"));
 
         return graph;
     }
diff --git a/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/core/BaseCoreTest.java b/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/core/BaseCoreTest.java
index d51e1b595..a21b575bc 100644
--- a/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/core/BaseCoreTest.java
+++ b/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/core/BaseCoreTest.java
@@ -21,13 +21,12 @@ import java.util.Random;
 
 import org.apache.hugegraph.HugeGraph;
 import org.apache.hugegraph.HugeGraphParams;
-import org.apache.hugegraph.backend.id.IdGenerator;
 import org.apache.hugegraph.backend.store.BackendFeatures;
 import org.apache.hugegraph.dist.RegisterUtil;
+import org.apache.hugegraph.masterelection.GlobaMasterInfo;
 import org.apache.hugegraph.schema.SchemaManager;
 import org.apache.hugegraph.testutil.Utils;
 import org.apache.hugegraph.testutil.Whitebox;
-import org.apache.hugegraph.type.define.NodeRole;
 import org.apache.hugegraph.util.Log;
 import org.apache.tinkerpop.gremlin.structure.Edge;
 import org.apache.tinkerpop.gremlin.structure.Vertex;
@@ -66,7 +65,7 @@ public class BaseCoreTest {
         graph = Utils.open();
         graph.clearBackend();
         graph.initBackend();
-        graph.serverStarted(IdGenerator.of("server1"), NodeRole.MASTER);
+        graph.serverStarted(GlobaMasterInfo.master("server-test"));
     }
 
     @AfterClass
diff --git a/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/core/MultiGraphsTest.java b/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/core/MultiGraphsTest.java
index 23fb122f4..a340713ce 100644
--- a/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/core/MultiGraphsTest.java
+++ b/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/core/MultiGraphsTest.java
@@ -31,8 +31,8 @@ import org.apache.hugegraph.backend.id.IdGenerator;
 import org.apache.hugegraph.backend.store.BackendStoreInfo;
 import org.apache.hugegraph.backend.store.rocksdb.RocksDBOptions;
 import org.apache.hugegraph.config.CoreOptions;
-import org.apache.hugegraph.exception.ConnectionException;
 import org.apache.hugegraph.exception.ExistedException;
+import org.apache.hugegraph.masterelection.GlobaMasterInfo;
 import org.apache.hugegraph.schema.EdgeLabel;
 import org.apache.hugegraph.schema.IndexLabel;
 import org.apache.hugegraph.schema.PropertyKey;
@@ -40,7 +40,6 @@ import org.apache.hugegraph.schema.SchemaManager;
 import org.apache.hugegraph.schema.VertexLabel;
 import org.apache.hugegraph.testutil.Assert;
 import org.apache.hugegraph.testutil.Utils;
-import org.apache.hugegraph.type.define.NodeRole;
 import org.apache.tinkerpop.gremlin.structure.T;
 import org.apache.tinkerpop.gremlin.structure.Vertex;
 import org.apache.tinkerpop.gremlin.structure.util.GraphFactory;
@@ -87,9 +86,9 @@ public class MultiGraphsTest extends BaseCoreTest {
             graph.initBackend();
         }
         HugeGraph g1 = graphs.get(0);
-        g1.serverStarted(IdGenerator.of("server-g2"), NodeRole.MASTER);
+        g1.serverStarted(GlobaMasterInfo.master("server-g2"));
         HugeGraph g2 = graphs.get(1);
-        g2.serverStarted(IdGenerator.of("server-g3"), NodeRole.MASTER);
+        g2.serverStarted(GlobaMasterInfo.master("server-g3"));
 
         SchemaManager schema = g1.schema();
 
@@ -209,8 +208,8 @@ public class MultiGraphsTest extends BaseCoreTest {
         }
         HugeGraph g1 = graphs.get(0);
         HugeGraph g2 = graphs.get(1);
-        g1.serverStarted(IdGenerator.of("server-g1c"), NodeRole.MASTER);
-        g2.serverStarted(IdGenerator.of("server-g2c"), NodeRole.MASTER);
+        g1.serverStarted(GlobaMasterInfo.master("server-g1c"));
+        g2.serverStarted(GlobaMasterInfo.master("server-g2c"));
 
         g1.schema().propertyKey("id").asInt().create();
         g2.schema().propertyKey("id").asText().create();
diff --git a/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/core/RoleElectionStateMachineTest.java b/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/core/RoleElectionStateMachineTest.java
index 9fbbb5e62..3eb059f06 100644
--- a/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/core/RoleElectionStateMachineTest.java
+++ b/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/core/RoleElectionStateMachineTest.java
@@ -35,7 +35,7 @@ import org.apache.hugegraph.masterelection.ClusterRoleStore;
 import org.apache.hugegraph.masterelection.Config;
 import org.apache.hugegraph.masterelection.RoleElectionStateMachine;
 import org.apache.hugegraph.masterelection.StandardRoleElectionStateMachine;
-import org.apache.hugegraph.masterelection.StateMachineCallback;
+import org.apache.hugegraph.masterelection.RoleListener;
 import org.apache.hugegraph.masterelection.StateMachineContext;
 import org.apache.hugegraph.testutil.Assert;
 import org.apache.hugegraph.testutil.Utils;
@@ -143,7 +143,7 @@ public class RoleElectionStateMachineTest {
         final int MAX_COUNT = 200;
         final List<LogEntry> logRecords = Collections.synchronizedList(new ArrayList<>(MAX_COUNT));
         final List<String> masterNodes = Collections.synchronizedList(new ArrayList<>(MAX_COUNT));
-        final StateMachineCallback callback = new StateMachineCallback() {
+        final RoleListener callback = new RoleListener() {
 
             @Override
             public void onAsRoleMaster(StateMachineContext context) {
@@ -264,7 +264,7 @@ public class RoleElectionStateMachineTest {
             RoleElectionStateMachine stateMachine =
                                      new StandardRoleElectionStateMachine(config, clusterRoleStore);
             machines[1] = stateMachine;
-            stateMachine.apply(callback);
+            stateMachine.start(callback);
             stop.countDown();
         });
 
@@ -273,7 +273,7 @@ public class RoleElectionStateMachineTest {
             RoleElectionStateMachine stateMachine =
                                      new StandardRoleElectionStateMachine(config, clusterRoleStore);
             machines[2] = stateMachine;
-            stateMachine.apply(callback);
+            stateMachine.start(callback);
             stop.countDown();
         });
 
@@ -282,7 +282,7 @@ public class RoleElectionStateMachineTest {
             RoleElectionStateMachine stateMachine =
                                      new StandardRoleElectionStateMachine(config, clusterRoleStore);
             machines[3] = stateMachine;
-            stateMachine.apply(callback);
+            stateMachine.start(callback);
             stop.countDown();
         });
 
diff --git a/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/tinkerpop/TestGraph.java b/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/tinkerpop/TestGraph.java
index c6dcff4a8..f9f344f70 100644
--- a/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/tinkerpop/TestGraph.java
+++ b/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/tinkerpop/TestGraph.java
@@ -24,27 +24,24 @@ import java.util.List;
 import java.util.Set;
 
 import org.apache.commons.configuration2.Configuration;
-import org.apache.tinkerpop.gremlin.process.computer.GraphComputer;
-import org.apache.tinkerpop.gremlin.structure.Edge;
-import org.apache.tinkerpop.gremlin.structure.Graph;
-import org.apache.tinkerpop.gremlin.structure.T;
-import org.apache.tinkerpop.gremlin.structure.Transaction;
-import org.apache.tinkerpop.gremlin.structure.Vertex;
-import org.apache.tinkerpop.gremlin.structure.io.Io;
-
 import org.apache.hugegraph.HugeGraph;
-import org.apache.hugegraph.backend.id.Id;
-import org.apache.hugegraph.backend.id.IdGenerator;
 import org.apache.hugegraph.backend.store.BackendStoreInfo;
 import org.apache.hugegraph.io.HugeGraphIoRegistry;
 import org.apache.hugegraph.io.HugeGraphSONModule;
+import org.apache.hugegraph.masterelection.GlobaMasterInfo;
 import org.apache.hugegraph.perf.PerfUtil.Watched;
 import org.apache.hugegraph.schema.PropertyKey;
 import org.apache.hugegraph.schema.SchemaManager;
 import org.apache.hugegraph.task.TaskScheduler;
 import org.apache.hugegraph.testutil.Whitebox;
 import org.apache.hugegraph.type.define.IdStrategy;
-import org.apache.hugegraph.type.define.NodeRole;
+import org.apache.tinkerpop.gremlin.process.computer.GraphComputer;
+import org.apache.tinkerpop.gremlin.structure.Edge;
+import org.apache.tinkerpop.gremlin.structure.Graph;
+import org.apache.tinkerpop.gremlin.structure.T;
+import org.apache.tinkerpop.gremlin.structure.Transaction;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.apache.tinkerpop.gremlin.structure.io.Io;
 
 import com.google.common.collect.ImmutableSet;
 
@@ -85,8 +82,7 @@ public class TestGraph implements Graph {
             assert sysInfo.exists() && !this.graph.closed();
         }
 
-        Id id = IdGenerator.of("server-tinkerpop");
-        this.graph.serverStarted(id, NodeRole.MASTER);
+        this.graph.serverStarted(GlobaMasterInfo.master("server-tinkerpop"));
 
         this.initedBackend = true;
     }
diff --git a/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/unit/core/SecurityManagerTest.java b/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/unit/core/SecurityManagerTest.java
index 403bc62e9..1029b797e 100644
--- a/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/unit/core/SecurityManagerTest.java
+++ b/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/unit/core/SecurityManagerTest.java
@@ -32,23 +32,22 @@ import java.util.HashMap;
 import java.util.Map;
 import java.util.concurrent.TimeoutException;
 
-import org.junit.AfterClass;
-import org.junit.BeforeClass;
-import org.junit.Test;
-
 import org.apache.hugegraph.HugeException;
 import org.apache.hugegraph.HugeFactory;
 import org.apache.hugegraph.HugeGraph;
-import org.apache.hugegraph.backend.id.IdGenerator;
 import org.apache.hugegraph.config.HugeConfig;
 import org.apache.hugegraph.job.GremlinJob;
 import org.apache.hugegraph.job.JobBuilder;
+import org.apache.hugegraph.masterelection.GlobaMasterInfo;
 import org.apache.hugegraph.security.HugeSecurityManager;
 import org.apache.hugegraph.task.HugeTask;
 import org.apache.hugegraph.testutil.Assert;
-import org.apache.hugegraph.type.define.NodeRole;
 import org.apache.hugegraph.unit.FakeObjects;
 import org.apache.hugegraph.util.JsonUtil;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
 import com.google.common.collect.ImmutableMap;
 
 public class SecurityManagerTest {
@@ -319,7 +318,7 @@ public class SecurityManagerTest {
             graph.clearBackend();
         }
         graph.initBackend();
-        graph.serverStarted(IdGenerator.of("server1"), NodeRole.MASTER);
+        graph.serverStarted(GlobaMasterInfo.master("server1"));
 
         return graph;
     }