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

vaughn pushed a commit to branch zy_dev
in repository https://gitbox.apache.org/repos/asf/incubator-hugegraph.git

commit 54723e62157129e9d3f519f61592524791a2fca9
Author: vaughn <[email protected]>
AuthorDate: Tue Feb 28 15:42:34 2023 +0800

    chore:redirect CUD task to master
---
 .../hugegraph/api/filter/RedirectFilter.java       | 76 ++++++++++++++++++++++
 .../api/filter/RedirectFilterDynamicFeature.java   | 31 ++++-----
 .../org/apache/hugegraph/api/job/AlgorithmAPI.java |  2 +
 .../org/apache/hugegraph/api/job/ComputerAPI.java  |  2 +
 .../org/apache/hugegraph/api/job/GremlinAPI.java   |  2 +
 .../org/apache/hugegraph/api/job/RebuildAPI.java   |  2 +
 .../java/org/apache/hugegraph/api/job/TaskAPI.java |  3 +
 .../apache/hugegraph/api/schema/EdgeLabelAPI.java  |  4 ++
 .../apache/hugegraph/api/schema/IndexLabelAPI.java |  4 ++
 .../hugegraph/api/schema/PropertyKeyAPI.java       |  4 ++
 .../hugegraph/api/schema/VertexLabelAPI.java       |  4 ++
 .../apache/hugegraph/server/ApplicationConfig.java |  3 +
 .../org/apache/hugegraph/StandardHugeGraph.java    |  1 +
 .../org/apache/hugegraph/config/CoreOptions.java   |  8 +++
 .../java/org/apache/hugegraph/election/Config.java |  2 +
 ...teMachineContext.java => GlobalMasterInfo.java} | 38 ++++++++---
 .../election/HugeRoleStateMachineConfig.java       |  9 ++-
 .../apache/hugegraph/election/RoleTypeData.java    | 13 +++-
 .../election/StandardRoleElectionStateMachine.java | 41 +++++++++++-
 .../election/StandardRoleTypeDataAdapter.java      |  9 ++-
 .../election/StandardStateMachineCallback.java     | 20 ++++++
 .../hugegraph/election/StateMachineContext.java    | 10 +++
 .../travis/conf-raft1/rest-server.properties       |  1 +
 .../travis/conf-raft2/rest-server.properties       |  1 +
 .../travis/conf-raft3/rest-server.properties       |  1 +
 .../core/RoleElectionStateMachineTest.java         |  7 +-
 26 files changed, 268 insertions(+), 30 deletions(-)

diff --git 
a/hugegraph-api/src/main/java/org/apache/hugegraph/api/filter/RedirectFilter.java
 
b/hugegraph-api/src/main/java/org/apache/hugegraph/api/filter/RedirectFilter.java
new file mode 100644
index 000000000..e6c7e2d98
--- /dev/null
+++ 
b/hugegraph-api/src/main/java/org/apache/hugegraph/api/filter/RedirectFilter.java
@@ -0,0 +1,76 @@
+/*
+ * 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.api.filter;
+
+import java.io.IOException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import jakarta.ws.rs.NameBinding;
+import jakarta.ws.rs.container.ContainerRequestContext;
+import jakarta.ws.rs.container.ContainerRequestFilter;
+import jakarta.ws.rs.core.Response;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.http.client.utils.URIBuilder;
+import org.apache.hugegraph.election.GlobalMasterInfo;
+import org.apache.hugegraph.util.Log;
+import org.slf4j.Logger;
+
+public class RedirectFilter implements ContainerRequestFilter {
+
+    private static final Logger LOG = Log.logger(RedirectFilter.class);
+
+    @Override
+    public void filter(ContainerRequestContext requestContext) throws 
IOException {
+        GlobalMasterInfo instance = GlobalMasterInfo.instance();
+        if (!instance.isFeatureSupport()) {
+            return;
+        }
+
+        String url = "";
+        synchronized (instance) {
+            if (instance.isMaster() || StringUtils.isEmpty(instance.url())) {
+                return;
+            }
+            url = instance.url();
+        }
+
+        URI redirectUri = null;
+        try {
+            URIBuilder redirectURIBuilder = new 
URIBuilder(requestContext.getUriInfo().getAbsolutePath());
+            String[] host = url.split(":");
+            redirectURIBuilder.setHost(host[0]);
+            if (host.length == 2 && StringUtils.isNotEmpty(host[1].trim())) {
+                redirectURIBuilder.setPort(Integer.parseInt(host[1].trim()));
+            }
+
+            redirectUri = redirectURIBuilder.build();
+        } catch (URISyntaxException e) {
+            LOG.error("Redirect request exception occurred", e);
+            return;
+        }
+        
requestContext.abortWith(Response.temporaryRedirect(redirectUri).build());
+    }
+
+    @NameBinding
+    @Retention(RetentionPolicy.RUNTIME)
+    public @interface RedirectMasterRole {
+    }
+}
diff --git 
a/hugegraph-core/src/main/java/org/apache/hugegraph/election/Config.java 
b/hugegraph-api/src/main/java/org/apache/hugegraph/api/filter/RedirectFilterDynamicFeature.java
similarity index 59%
copy from hugegraph-core/src/main/java/org/apache/hugegraph/election/Config.java
copy to 
hugegraph-api/src/main/java/org/apache/hugegraph/api/filter/RedirectFilterDynamicFeature.java
index 8afa3084b..0b6269358 100644
--- a/hugegraph-core/src/main/java/org/apache/hugegraph/election/Config.java
+++ 
b/hugegraph-api/src/main/java/org/apache/hugegraph/api/filter/RedirectFilterDynamicFeature.java
@@ -15,19 +15,20 @@
  * under the License.
  */
 
-package org.apache.hugegraph.election;
-
-public interface Config {
-
-    String node();
-
-    int exceedsFailCount();
-
-    long randomTimeoutMillisecond();
-
-    long heartBeatIntervalSecond();
-
-    int exceedsWorkerCount();
-
-    long baseTimeoutMillisecond();
+package org.apache.hugegraph.api.filter;
+
+import jakarta.ws.rs.container.DynamicFeature;
+import jakarta.ws.rs.container.ResourceInfo;
+import jakarta.ws.rs.core.FeatureContext;
+import jakarta.ws.rs.ext.Provider;
+
+@Provider
+public class RedirectFilterDynamicFeature implements DynamicFeature {
+
+    @Override
+    public void configure(ResourceInfo resourceInfo, FeatureContext context) {
+        if 
(resourceInfo.getResourceMethod().isAnnotationPresent(RedirectFilter.RedirectMasterRole.class))
 {
+            context.register(RedirectFilter.class);
+        }
+    }
 }
diff --git 
a/hugegraph-api/src/main/java/org/apache/hugegraph/api/job/AlgorithmAPI.java 
b/hugegraph-api/src/main/java/org/apache/hugegraph/api/job/AlgorithmAPI.java
index c9b8dbf9b..ebb172a9e 100644
--- a/hugegraph-api/src/main/java/org/apache/hugegraph/api/job/AlgorithmAPI.java
+++ b/hugegraph-api/src/main/java/org/apache/hugegraph/api/job/AlgorithmAPI.java
@@ -19,6 +19,7 @@ package org.apache.hugegraph.api.job;
 
 import java.util.Map;
 
+import org.apache.hugegraph.api.filter.RedirectFilter;
 import org.apache.hugegraph.core.GraphManager;
 import org.apache.hugegraph.server.RestServer;
 import org.slf4j.Logger;
@@ -56,6 +57,7 @@ public class AlgorithmAPI extends API {
     @Status(Status.CREATED)
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON_WITH_CHARSET)
+    @RedirectFilter.RedirectMasterRole
     public Map<String, Id> post(@Context GraphManager manager,
                                 @PathParam("graph") String graph,
                                 @PathParam("name") String algorithm,
diff --git 
a/hugegraph-api/src/main/java/org/apache/hugegraph/api/job/ComputerAPI.java 
b/hugegraph-api/src/main/java/org/apache/hugegraph/api/job/ComputerAPI.java
index 42b79a67a..88b229bdf 100644
--- a/hugegraph-api/src/main/java/org/apache/hugegraph/api/job/ComputerAPI.java
+++ b/hugegraph-api/src/main/java/org/apache/hugegraph/api/job/ComputerAPI.java
@@ -29,6 +29,7 @@ import jakarta.ws.rs.PathParam;
 import jakarta.ws.rs.Produces;
 import jakarta.ws.rs.core.Context;
 
+import org.apache.hugegraph.api.filter.RedirectFilter;
 import org.apache.hugegraph.core.GraphManager;
 import org.slf4j.Logger;
 
@@ -58,6 +59,7 @@ public class ComputerAPI extends API {
     @Status(Status.CREATED)
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON_WITH_CHARSET)
+    @RedirectFilter.RedirectMasterRole
     public Map<String, Id> post(@Context GraphManager manager,
                                 @PathParam("graph") String graph,
                                 @PathParam("name") String computer,
diff --git 
a/hugegraph-api/src/main/java/org/apache/hugegraph/api/job/GremlinAPI.java 
b/hugegraph-api/src/main/java/org/apache/hugegraph/api/job/GremlinAPI.java
index 6a47ec5ad..c343d2df2 100644
--- a/hugegraph-api/src/main/java/org/apache/hugegraph/api/job/GremlinAPI.java
+++ b/hugegraph-api/src/main/java/org/apache/hugegraph/api/job/GremlinAPI.java
@@ -35,6 +35,7 @@ import jakarta.ws.rs.PathParam;
 import jakarta.ws.rs.Produces;
 import jakarta.ws.rs.core.Context;
 
+import org.apache.hugegraph.api.filter.RedirectFilter;
 import org.apache.hugegraph.core.GraphManager;
 import org.apache.hugegraph.define.Checkable;
 import org.apache.hugegraph.metrics.MetricsUtil;
@@ -58,6 +59,7 @@ import com.google.common.collect.ImmutableMap;
 @Path("graphs/{graph}/jobs/gremlin")
 @Singleton
 @Tag(name = "GremlinAPI")
[email protected]
 public class GremlinAPI extends API {
 
     private static final Logger LOG = Log.logger(GremlinAPI.class);
diff --git 
a/hugegraph-api/src/main/java/org/apache/hugegraph/api/job/RebuildAPI.java 
b/hugegraph-api/src/main/java/org/apache/hugegraph/api/job/RebuildAPI.java
index 354a72945..0ac93811e 100644
--- a/hugegraph-api/src/main/java/org/apache/hugegraph/api/job/RebuildAPI.java
+++ b/hugegraph-api/src/main/java/org/apache/hugegraph/api/job/RebuildAPI.java
@@ -28,6 +28,7 @@ import jakarta.ws.rs.PathParam;
 import jakarta.ws.rs.Produces;
 import jakarta.ws.rs.core.Context;
 
+import org.apache.hugegraph.api.filter.RedirectFilter;
 import org.apache.hugegraph.api.filter.StatusFilter.Status;
 import org.apache.hugegraph.core.GraphManager;
 import org.slf4j.Logger;
@@ -42,6 +43,7 @@ import com.google.common.collect.ImmutableMap;
 @Path("graphs/{graph}/jobs/rebuild")
 @Singleton
 @Tag(name = "RebuildAPI")
[email protected]
 public class RebuildAPI extends API {
 
     private static final Logger LOG = Log.logger(RebuildAPI.class);
diff --git 
a/hugegraph-api/src/main/java/org/apache/hugegraph/api/job/TaskAPI.java 
b/hugegraph-api/src/main/java/org/apache/hugegraph/api/job/TaskAPI.java
index 67a445e2c..30f8d3bdd 100644
--- a/hugegraph-api/src/main/java/org/apache/hugegraph/api/job/TaskAPI.java
+++ b/hugegraph-api/src/main/java/org/apache/hugegraph/api/job/TaskAPI.java
@@ -39,6 +39,7 @@ import jakarta.ws.rs.QueryParam;
 import jakarta.ws.rs.core.Context;
 
 import org.apache.groovy.util.Maps;
+import org.apache.hugegraph.api.filter.RedirectFilter;
 import org.apache.hugegraph.api.filter.StatusFilter.Status;
 import org.apache.hugegraph.core.GraphManager;
 import org.slf4j.Logger;
@@ -132,6 +133,7 @@ public class TaskAPI extends API {
     @DELETE
     @Timed
     @Path("{id}")
+    @RedirectFilter.RedirectMasterRole
     public void delete(@Context GraphManager manager,
                        @PathParam("graph") String graph,
                        @PathParam("id") long id) {
@@ -147,6 +149,7 @@ public class TaskAPI extends API {
     @Path("{id}")
     @Status(Status.ACCEPTED)
     @Produces(APPLICATION_JSON_WITH_CHARSET)
+    @RedirectFilter.RedirectMasterRole
     public Map<String, Object> update(@Context GraphManager manager,
                                       @PathParam("graph") String graph,
                                       @PathParam("id") long id,
diff --git 
a/hugegraph-api/src/main/java/org/apache/hugegraph/api/schema/EdgeLabelAPI.java 
b/hugegraph-api/src/main/java/org/apache/hugegraph/api/schema/EdgeLabelAPI.java
index 02ce5a6f1..5ec2785e2 100644
--- 
a/hugegraph-api/src/main/java/org/apache/hugegraph/api/schema/EdgeLabelAPI.java
+++ 
b/hugegraph-api/src/main/java/org/apache/hugegraph/api/schema/EdgeLabelAPI.java
@@ -36,6 +36,7 @@ import jakarta.ws.rs.QueryParam;
 import jakarta.ws.rs.core.Context;
 
 import org.apache.commons.collections.CollectionUtils;
+import org.apache.hugegraph.api.filter.RedirectFilter;
 import org.apache.hugegraph.core.GraphManager;
 import org.apache.hugegraph.define.Checkable;
 import org.slf4j.Logger;
@@ -68,6 +69,7 @@ public class EdgeLabelAPI extends API {
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON_WITH_CHARSET)
     @RolesAllowed({"admin", "$owner=$graph $action=edge_label_write"})
+    @RedirectFilter.RedirectMasterRole
     public String create(@Context GraphManager manager,
                          @PathParam("graph") String graph,
                          JsonEdgeLabel jsonEdgeLabel) {
@@ -86,6 +88,7 @@ public class EdgeLabelAPI extends API {
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON_WITH_CHARSET)
     @RolesAllowed({"admin", "$owner=$graph $action=edge_label_write"})
+    @RedirectFilter.RedirectMasterRole
     public String update(@Context GraphManager manager,
                          @PathParam("graph") String graph,
                          @PathParam("name") String name,
@@ -156,6 +159,7 @@ public class EdgeLabelAPI extends API {
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON_WITH_CHARSET)
     @RolesAllowed({"admin", "$owner=$graph $action=edge_label_delete"})
+    @RedirectFilter.RedirectMasterRole
     public Map<String, Id> delete(@Context GraphManager manager,
                                   @PathParam("graph") String graph,
                                   @PathParam("name") String name) {
diff --git 
a/hugegraph-api/src/main/java/org/apache/hugegraph/api/schema/IndexLabelAPI.java
 
b/hugegraph-api/src/main/java/org/apache/hugegraph/api/schema/IndexLabelAPI.java
index 33710bd4c..16be06e51 100644
--- 
a/hugegraph-api/src/main/java/org/apache/hugegraph/api/schema/IndexLabelAPI.java
+++ 
b/hugegraph-api/src/main/java/org/apache/hugegraph/api/schema/IndexLabelAPI.java
@@ -36,6 +36,7 @@ import jakarta.ws.rs.QueryParam;
 import jakarta.ws.rs.core.Context;
 
 import org.apache.commons.collections.CollectionUtils;
+import org.apache.hugegraph.api.filter.RedirectFilter;
 import org.apache.hugegraph.core.GraphManager;
 import org.apache.hugegraph.define.Checkable;
 import org.slf4j.Logger;
@@ -70,6 +71,7 @@ public class IndexLabelAPI extends API {
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON_WITH_CHARSET)
     @RolesAllowed({"admin", "$owner=$graph $action=index_label_write"})
+    @RedirectFilter.RedirectMasterRole
     public String create(@Context GraphManager manager,
                          @PathParam("graph") String graph,
                          JsonIndexLabel jsonIndexLabel) {
@@ -88,6 +90,7 @@ public class IndexLabelAPI extends API {
     @Path("{name}")
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON_WITH_CHARSET)
+    @RedirectFilter.RedirectMasterRole
     public String update(@Context GraphManager manager,
                          @PathParam("graph") String graph,
                          @PathParam("name") String name,
@@ -157,6 +160,7 @@ public class IndexLabelAPI extends API {
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON_WITH_CHARSET)
     @RolesAllowed({"admin", "$owner=$graph $action=index_label_delete"})
+    @RedirectFilter.RedirectMasterRole
     public Map<String, Id> delete(@Context GraphManager manager,
                                   @PathParam("graph") String graph,
                                   @PathParam("name") String name) {
diff --git 
a/hugegraph-api/src/main/java/org/apache/hugegraph/api/schema/PropertyKeyAPI.java
 
b/hugegraph-api/src/main/java/org/apache/hugegraph/api/schema/PropertyKeyAPI.java
index c7ddd6665..893dcd9c6 100644
--- 
a/hugegraph-api/src/main/java/org/apache/hugegraph/api/schema/PropertyKeyAPI.java
+++ 
b/hugegraph-api/src/main/java/org/apache/hugegraph/api/schema/PropertyKeyAPI.java
@@ -36,6 +36,7 @@ import jakarta.ws.rs.QueryParam;
 import jakarta.ws.rs.core.Context;
 
 import org.apache.commons.collections.CollectionUtils;
+import org.apache.hugegraph.api.filter.RedirectFilter;
 import org.apache.hugegraph.core.GraphManager;
 import org.apache.hugegraph.define.Checkable;
 import org.slf4j.Logger;
@@ -73,6 +74,7 @@ public class PropertyKeyAPI extends API {
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON_WITH_CHARSET)
     @RolesAllowed({"admin", "$owner=$graph $action=property_key_write"})
+    @RedirectFilter.RedirectMasterRole
     public String create(@Context GraphManager manager,
                          @PathParam("graph") String graph,
                          JsonPropertyKey jsonPropertyKey) {
@@ -93,6 +95,7 @@ public class PropertyKeyAPI extends API {
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON_WITH_CHARSET)
     @RolesAllowed({"admin", "$owner=$graph $action=property_key_write"})
+    @RedirectFilter.RedirectMasterRole
     public String update(@Context GraphManager manager,
                          @PathParam("graph") String graph,
                          @PathParam("name") String name,
@@ -178,6 +181,7 @@ public class PropertyKeyAPI extends API {
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON_WITH_CHARSET)
     @RolesAllowed({"admin", "$owner=$graph $action=property_key_delete"})
+    @RedirectFilter.RedirectMasterRole
     public Map<String, Id> delete(@Context GraphManager manager,
                                   @PathParam("graph") String graph,
                                   @PathParam("name") String name) {
diff --git 
a/hugegraph-api/src/main/java/org/apache/hugegraph/api/schema/VertexLabelAPI.java
 
b/hugegraph-api/src/main/java/org/apache/hugegraph/api/schema/VertexLabelAPI.java
index 8c62490ab..0ad5a5d8e 100644
--- 
a/hugegraph-api/src/main/java/org/apache/hugegraph/api/schema/VertexLabelAPI.java
+++ 
b/hugegraph-api/src/main/java/org/apache/hugegraph/api/schema/VertexLabelAPI.java
@@ -36,6 +36,7 @@ import jakarta.ws.rs.QueryParam;
 import jakarta.ws.rs.core.Context;
 
 import org.apache.commons.collections.CollectionUtils;
+import org.apache.hugegraph.api.filter.RedirectFilter;
 import org.apache.hugegraph.core.GraphManager;
 import org.apache.hugegraph.define.Checkable;
 import org.slf4j.Logger;
@@ -68,6 +69,7 @@ public class VertexLabelAPI extends API {
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON_WITH_CHARSET)
     @RolesAllowed({"admin", "$owner=$graph $action=vertex_label_write"})
+    @RedirectFilter.RedirectMasterRole
     public String create(@Context GraphManager manager,
                          @PathParam("graph") String graph,
                          JsonVertexLabel jsonVertexLabel) {
@@ -87,6 +89,7 @@ public class VertexLabelAPI extends API {
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON_WITH_CHARSET)
     @RolesAllowed({"admin", "$owner=$graph $action=vertex_label_write"})
+    @RedirectFilter.RedirectMasterRole
     public String update(@Context GraphManager manager,
                          @PathParam("graph") String graph,
                          @PathParam("name") String name,
@@ -159,6 +162,7 @@ public class VertexLabelAPI extends API {
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON_WITH_CHARSET)
     @RolesAllowed({"admin", "$owner=$graph $action=vertex_label_delete"})
+    @RedirectFilter.RedirectMasterRole
     public Map<String, Id> delete(@Context GraphManager manager,
                                   @PathParam("graph") String graph,
                                   @PathParam("name") String name) {
diff --git 
a/hugegraph-api/src/main/java/org/apache/hugegraph/server/ApplicationConfig.java
 
b/hugegraph-api/src/main/java/org/apache/hugegraph/server/ApplicationConfig.java
index 3bbe3048c..838e4b810 100644
--- 
a/hugegraph-api/src/main/java/org/apache/hugegraph/server/ApplicationConfig.java
+++ 
b/hugegraph-api/src/main/java/org/apache/hugegraph/server/ApplicationConfig.java
@@ -17,6 +17,7 @@
 
 package org.apache.hugegraph.server;
 
+import org.apache.hugegraph.api.filter.RedirectFilterDynamicFeature;
 import org.apache.tinkerpop.gremlin.server.util.MetricManager;
 import org.glassfish.hk2.api.Factory;
 import org.glassfish.hk2.api.MultiException;
@@ -67,6 +68,8 @@ public class ApplicationConfig extends ResourceConfig {
         // Register to use the jsr250 annotations @RolesAllowed
         register(RolesAllowedDynamicFeature.class);
 
+        register(RedirectFilterDynamicFeature.class);
+
         // Register HugeConfig to context
         register(new ConfFactory(conf));
 
diff --git 
a/hugegraph-core/src/main/java/org/apache/hugegraph/StandardHugeGraph.java 
b/hugegraph-core/src/main/java/org/apache/hugegraph/StandardHugeGraph.java
index 688b5ba8e..6153c7791 100644
--- a/hugegraph-core/src/main/java/org/apache/hugegraph/StandardHugeGraph.java
+++ b/hugegraph-core/src/main/java/org/apache/hugegraph/StandardHugeGraph.java
@@ -288,6 +288,7 @@ public class StandardHugeGraph implements HugeGraph {
 
     private void initRoleStateWorker(Id serverId) {
         Config roleStateMachineConfig = new 
HugeRoleStateMachineConfig(serverId.toString(),
+                                            
this.configuration.get(CoreOptions.NODE_EXTERNAL_URL),
                                             
this.configuration.get(CoreOptions.EXCEEDS_FAIL_COUNT),
                                             
this.configuration.get(CoreOptions.RANDOM_TIMEOUT_MILLISECOND),
                                             
this.configuration.get(CoreOptions.HEARTBEAT_INTERVAL_SECOUND),
diff --git 
a/hugegraph-core/src/main/java/org/apache/hugegraph/config/CoreOptions.java 
b/hugegraph-core/src/main/java/org/apache/hugegraph/config/CoreOptions.java
index 862cabb45..d6cfcf0bc 100644
--- a/hugegraph-core/src/main/java/org/apache/hugegraph/config/CoreOptions.java
+++ b/hugegraph-core/src/main/java/org/apache/hugegraph/config/CoreOptions.java
@@ -635,6 +635,14 @@ public class CoreOptions extends OptionHolder {
                     2
             );
 
+    public static final ConfigOption<String> NODE_EXTERNAL_URL =
+            new ConfigOption<>(
+                    "server.role.node_external_url",
+                    "The url of external accessibility",
+                    disallowEmpty(),
+                    "127.0.0.1:8080"
+            );
+
     public static final ConfigOption<Integer> RANDOM_TIMEOUT_MILLISECOND =
             new ConfigOption<>(
                     "server.role.random_timeout",
diff --git 
a/hugegraph-core/src/main/java/org/apache/hugegraph/election/Config.java 
b/hugegraph-core/src/main/java/org/apache/hugegraph/election/Config.java
index 8afa3084b..1618c1b19 100644
--- a/hugegraph-core/src/main/java/org/apache/hugegraph/election/Config.java
+++ b/hugegraph-core/src/main/java/org/apache/hugegraph/election/Config.java
@@ -21,6 +21,8 @@ public interface Config {
 
     String node();
 
+    String url();
+
     int exceedsFailCount();
 
     long randomTimeoutMillisecond();
diff --git 
a/hugegraph-core/src/main/java/org/apache/hugegraph/election/StateMachineContext.java
 
b/hugegraph-core/src/main/java/org/apache/hugegraph/election/GlobalMasterInfo.java
similarity index 50%
copy from 
hugegraph-core/src/main/java/org/apache/hugegraph/election/StateMachineContext.java
copy to 
hugegraph-core/src/main/java/org/apache/hugegraph/election/GlobalMasterInfo.java
index e314a352c..2ecb1e743 100644
--- 
a/hugegraph-core/src/main/java/org/apache/hugegraph/election/StateMachineContext.java
+++ 
b/hugegraph-core/src/main/java/org/apache/hugegraph/election/GlobalMasterInfo.java
@@ -17,19 +17,41 @@
 
 package org.apache.hugegraph.election;
 
-public interface StateMachineContext {
+public class GlobalMasterInfo {
 
-    Integer epoch();
+    private boolean isMaster;
+    private String url;
 
-    String node();
+    private volatile boolean featureSupport;
 
-    RoleElectionStateMachine stateMachine();
+    private static GlobalMasterInfo instance = new GlobalMasterInfo();
 
-    void epoch(Integer epoch);
+    public static GlobalMasterInfo instance() {
+        return instance;
+    }
 
-    Config config();
+    private GlobalMasterInfo() {
+        this.featureSupport = false;
+    }
 
-    RoleTypeDataAdapter adapter();
+    public synchronized void set(boolean isMaster, String url) {
+        this.isMaster = isMaster;
+        this.url = url;
+    }
 
-    void reset();
+    public synchronized boolean isMaster() {
+        return this.isMaster;
+    }
+
+    public synchronized String url() {
+        return this.url;
+    }
+
+    public void isFeatureSupport(boolean featureSupport) {
+        this.featureSupport = featureSupport;
+    }
+
+    public boolean isFeatureSupport() {
+        return this.featureSupport;
+    }
 }
diff --git 
a/hugegraph-core/src/main/java/org/apache/hugegraph/election/HugeRoleStateMachineConfig.java
 
b/hugegraph-core/src/main/java/org/apache/hugegraph/election/HugeRoleStateMachineConfig.java
index 322c9b747..d99ce967a 100644
--- 
a/hugegraph-core/src/main/java/org/apache/hugegraph/election/HugeRoleStateMachineConfig.java
+++ 
b/hugegraph-core/src/main/java/org/apache/hugegraph/election/HugeRoleStateMachineConfig.java
@@ -20,16 +20,18 @@ package org.apache.hugegraph.election;
 public class HugeRoleStateMachineConfig implements Config {
 
     private String node;
+    private String url;
     private int exceedsFailCount;
     private long randomTimeoutMillisecond;
     private long heartBeatIntervalSecond;
     private int exceedsWorkerCount;
     private long baseTimeoutMillisecond;
 
-    public HugeRoleStateMachineConfig(String node, int exceedsFailCount,
+    public HugeRoleStateMachineConfig(String node, String url, int 
exceedsFailCount,
                                       long randomTimeoutMillisecond, long 
heartBeatIntervalSecond,
                                       int exceedsWorkerCount, long 
baseTimeoutMillisecond) {
         this.node = node;
+        this.url = url;
         this.exceedsFailCount = exceedsFailCount;
         this.randomTimeoutMillisecond = randomTimeoutMillisecond;
         this.heartBeatIntervalSecond = heartBeatIntervalSecond;
@@ -43,6 +45,11 @@ public class HugeRoleStateMachineConfig implements Config {
         return this.node;
     }
 
+    @Override
+    public String url() {
+        return this.url;
+    }
+
     @Override
     public int exceedsFailCount() {
         return this.exceedsFailCount;
diff --git 
a/hugegraph-core/src/main/java/org/apache/hugegraph/election/RoleTypeData.java 
b/hugegraph-core/src/main/java/org/apache/hugegraph/election/RoleTypeData.java
index 66f47e792..a8bb768f6 100644
--- 
a/hugegraph-core/src/main/java/org/apache/hugegraph/election/RoleTypeData.java
+++ 
b/hugegraph-core/src/main/java/org/apache/hugegraph/election/RoleTypeData.java
@@ -25,12 +25,15 @@ public class RoleTypeData {
     private long clock;
     private int epoch;
 
-    public RoleTypeData(String node, int epoch) {
-        this(node, epoch, 1);
+    private String url;
+
+    public RoleTypeData(String node, String url, int epoch) {
+        this(node, url, epoch, 1);
     }
 
-    public RoleTypeData(String node, int epoch, long clock) {
+    public RoleTypeData(String node, String url, int epoch, long clock) {
         this.node = node;
+        this.url = url;
         this.epoch = epoch;
         this.clock = clock;
     }
@@ -59,6 +62,10 @@ public class RoleTypeData {
         return this.node;
     }
 
+    public String url() {
+        return this.url;
+    }
+
     @Override
     public boolean equals(Object obj) {
         if (this == obj) {
diff --git 
a/hugegraph-core/src/main/java/org/apache/hugegraph/election/StandardRoleElectionStateMachine.java
 
b/hugegraph-core/src/main/java/org/apache/hugegraph/election/StandardRoleElectionStateMachine.java
index bc66d7918..0af2483bd 100644
--- 
a/hugegraph-core/src/main/java/org/apache/hugegraph/election/StandardRoleElectionStateMachine.java
+++ 
b/hugegraph-core/src/main/java/org/apache/hugegraph/election/StandardRoleElectionStateMachine.java
@@ -120,6 +120,8 @@ public class StandardRoleElectionStateMachine implements 
RoleElectionStateMachin
             }
 
             context.epoch(roleTypeData.epoch());
+            context.master(new StateMachineContextImpl.MasterServerInfoImpl(
+                               roleTypeData.node(), roleTypeData.url()));
             if (roleTypeData.isMaster(context.node())) {
                 return new MasterState(roleTypeData);
             } else {
@@ -143,6 +145,7 @@ public class StandardRoleElectionStateMachine implements 
RoleElectionStateMachin
 
         @Override
         public RoleState transform(StateMachineContext context) {
+            context.master(null);
             RoleState.heartBeatPark(context);
             return new UnknownState(this.epoch).transform(context);
         }
@@ -241,10 +244,13 @@ public class StandardRoleElectionStateMachine implements 
RoleElectionStateMachin
         public RoleState transform(StateMachineContext context) {
             RoleState.randomPark(context);
             int epoch = this.epoch == null ? 1 : this.epoch;
-            RoleTypeData roleTypeData = new 
RoleTypeData(context.config().node(), epoch);
+            RoleTypeData roleTypeData = new 
RoleTypeData(context.config().node(),
+                                                         
context.config().url(), epoch);
             //failover to master success
             context.epoch(roleTypeData.epoch());
             if (context.adapter().updateIfNodePresent(roleTypeData)) {
+                context.master(new 
StateMachineContextImpl.MasterServerInfoImpl(
+                               roleTypeData.node(), roleTypeData.url()));
                 return new MasterState(roleTypeData);
             } else {
                 return new UnknownState(epoch).transform(context);
@@ -263,11 +269,18 @@ public class StandardRoleElectionStateMachine implements 
RoleElectionStateMachin
         private final String node;
         private final StandardRoleElectionStateMachine machine;
 
+        private MasterServerInfo masterServerInfo;
+
         public StateMachineContextImpl(StandardRoleElectionStateMachine 
machine) {
             this.node = machine.config.node();
             this.machine = machine;
         }
 
+        @Override
+        public void master(MasterServerInfo info) {
+            this.masterServerInfo = info;
+        }
+
         @Override
         public Integer epoch() {
             return this.epoch;
@@ -293,6 +306,11 @@ public class StandardRoleElectionStateMachine implements 
RoleElectionStateMachin
             return this.machine.config;
         }
 
+        @Override
+        public MasterServerInfo master() {
+            return this.masterServerInfo;
+        }
+
         @Override
         public RoleElectionStateMachine stateMachine() {
             return this.machine;
@@ -302,6 +320,27 @@ public class StandardRoleElectionStateMachine implements 
RoleElectionStateMachin
         public void reset() {
             this.epoch = null;
         }
+
+        private static class MasterServerInfoImpl implements MasterServerInfo {
+
+            private final String node;
+            private final String url;
+
+            public MasterServerInfoImpl(String node, String url) {
+                this.node = node;
+                this.url = url;
+            }
+
+            @Override
+            public String url() {
+                return this.url;
+            }
+
+            @Override
+            public String node() {
+                return this.node;
+            }
+        }
     }
 
     protected RoleTypeDataAdapter adapter() {
diff --git 
a/hugegraph-core/src/main/java/org/apache/hugegraph/election/StandardRoleTypeDataAdapter.java
 
b/hugegraph-core/src/main/java/org/apache/hugegraph/election/StandardRoleTypeDataAdapter.java
index 4b917f9f1..7fde15b96 100644
--- 
a/hugegraph-core/src/main/java/org/apache/hugegraph/election/StandardRoleTypeDataAdapter.java
+++ 
b/hugegraph-core/src/main/java/org/apache/hugegraph/election/StandardRoleTypeDataAdapter.java
@@ -88,6 +88,9 @@ public class StandardRoleTypeDataAdapter implements 
RoleTypeDataAdapter {
         list.add(P.NODE);
         list.add(stateData.node());
 
+        list.add(P.URL);
+        list.add(stateData.url());
+
         list.add(P.CLOCK);
         list.add(stateData.clock());
 
@@ -111,10 +114,11 @@ public class StandardRoleTypeDataAdapter implements 
RoleTypeDataAdapter {
 
     private RoleTypeData from(Vertex vertex) {
         String node = (String) vertex.property(P.NODE).value();
+        String url = (String) vertex.property(P.URL).value();
         Long clock = (Long) vertex.property(P.CLOCK).value();
         Integer epoch = (Integer) vertex.property(P.EPOCH).value();
 
-        RoleTypeData roleTypeData = new RoleTypeData(node, epoch, clock);
+        RoleTypeData roleTypeData = new RoleTypeData(node, url, epoch, clock);
         return roleTypeData;
     }
 
@@ -146,6 +150,8 @@ public class StandardRoleTypeDataAdapter implements 
RoleTypeDataAdapter {
 
         public static final String EPOCH = Graph.Hidden.hide("role_epoch");
 
+        public static final String URL = Graph.Hidden.hide("role_url");
+
         public static final String TYPE = Graph.Hidden.hide("role_type");
     }
 
@@ -177,6 +183,7 @@ public class StandardRoleTypeDataAdapter implements 
RoleTypeDataAdapter {
             List<String> props = new ArrayList<>();
 
             props.add(createPropertyKey(P.NODE, DataType.TEXT));
+            props.add(createPropertyKey(P.URL, DataType.TEXT));
             props.add(createPropertyKey(P.CLOCK, DataType.LONG));
             props.add(createPropertyKey(P.EPOCH, DataType.INT));
             props.add(createPropertyKey(P.TYPE, DataType.TEXT));
diff --git 
a/hugegraph-core/src/main/java/org/apache/hugegraph/election/StandardStateMachineCallback.java
 
b/hugegraph-core/src/main/java/org/apache/hugegraph/election/StandardStateMachineCallback.java
index 3db938d00..a572ffd08 100644
--- 
a/hugegraph-core/src/main/java/org/apache/hugegraph/election/StandardStateMachineCallback.java
+++ 
b/hugegraph-core/src/main/java/org/apache/hugegraph/election/StandardStateMachineCallback.java
@@ -21,6 +21,8 @@ import org.apache.hugegraph.task.TaskManager;
 import org.apache.hugegraph.util.Log;
 import org.slf4j.Logger;
 
+import java.util.Objects;
+
 public class StandardStateMachineCallback implements StateMachineCallback {
 
     private static final Logger LOG = 
Log.logger(StandardStateMachineCallback.class);
@@ -32,12 +34,14 @@ public class StandardStateMachineCallback implements 
StateMachineCallback {
     public StandardStateMachineCallback(TaskManager taskManager) {
         this.taskManager = taskManager;
         this.taskManager.enableRoleElected(true);
+        GlobalMasterInfo.instance().isFeatureSupport(true);
     }
 
     @Override
     public void onAsRoleMaster(StateMachineContext context) {
         if (!isMaster) {
             this.taskManager.onAsRoleMaster();
+            this.initGlobalMasterInfo(context);
             LOG.info("Server {} change to master role", 
context.config().node());
         }
         this.isMaster = true;
@@ -47,6 +51,7 @@ public class StandardStateMachineCallback implements 
StateMachineCallback {
     public void onAsRoleWorker(StateMachineContext context) {
         if (isMaster) {
             this.taskManager.onAsRoleWorker();
+            this.initGlobalMasterInfo(context);
             LOG.info("Server {} change to worker role", 
context.config().node());
         }
 
@@ -57,6 +62,7 @@ public class StandardStateMachineCallback implements 
StateMachineCallback {
     public void onAsRoleCandidate(StateMachineContext context) {
         if (isMaster) {
             this.taskManager.onAsRoleWorker();
+            this.initGlobalMasterInfo(context);
             LOG.info("Server {} change to worker role", 
context.config().node());
         }
 
@@ -67,6 +73,7 @@ public class StandardStateMachineCallback implements 
StateMachineCallback {
     public void unknown(StateMachineContext context) {
         if (isMaster) {
             this.taskManager.onAsRoleWorker();
+            this.initGlobalMasterInfo(context);
             LOG.info("Server {} change to worker role", 
context.config().node());
         }
 
@@ -77,6 +84,7 @@ public class StandardStateMachineCallback implements 
StateMachineCallback {
     public void onAsRoleAbdication(StateMachineContext context) {
         if (isMaster) {
             this.taskManager.onAsRoleWorker();
+            this.initGlobalMasterInfo(context);
             LOG.info("Server {} change to worker role", 
context.config().node());
         }
 
@@ -87,4 +95,16 @@ public class StandardStateMachineCallback implements 
StateMachineCallback {
     public void error(StateMachineContext context, Throwable e) {
         LOG.error("Server {} exception occurred", context.config().node(), e);
     }
+
+    public void initGlobalMasterInfo(StateMachineContext context) {
+        StateMachineContext.MasterServerInfo master = context.master();
+        if (master == null) {
+            GlobalMasterInfo.instance().set(false, null);
+            return;
+        }
+
+        boolean isMaster = Objects.equals(context.node(), master.node());
+        String url = master.url();
+        GlobalMasterInfo.instance().set(isMaster, url);
+    }
 }
diff --git 
a/hugegraph-core/src/main/java/org/apache/hugegraph/election/StateMachineContext.java
 
b/hugegraph-core/src/main/java/org/apache/hugegraph/election/StateMachineContext.java
index e314a352c..cd9ac57f3 100644
--- 
a/hugegraph-core/src/main/java/org/apache/hugegraph/election/StateMachineContext.java
+++ 
b/hugegraph-core/src/main/java/org/apache/hugegraph/election/StateMachineContext.java
@@ -29,7 +29,17 @@ public interface StateMachineContext {
 
     Config config();
 
+    MasterServerInfo master();
+
+    void master(MasterServerInfo info);
+
     RoleTypeDataAdapter adapter();
 
     void reset();
+
+    interface MasterServerInfo {
+
+        String url();
+        String node();
+    }
 }
diff --git 
a/hugegraph-dist/src/assembly/travis/conf-raft1/rest-server.properties 
b/hugegraph-dist/src/assembly/travis/conf-raft1/rest-server.properties
index ac9806192..5afc6c9c2 100644
--- a/hugegraph-dist/src/assembly/travis/conf-raft1/rest-server.properties
+++ b/hugegraph-dist/src/assembly/travis/conf-raft1/rest-server.properties
@@ -16,6 +16,7 @@
 #
 
 restserver.url=http://127.0.0.1:8080
+server.role.node_external_url=127.0.0.1:8080
 gremlinserver.url=http://127.0.0.1:8181
 graphs=conf/graphs
 auth.authenticator=org.apache.hugegraph.auth.StandardAuthenticator
diff --git 
a/hugegraph-dist/src/assembly/travis/conf-raft2/rest-server.properties 
b/hugegraph-dist/src/assembly/travis/conf-raft2/rest-server.properties
index b5ffe9114..305800df5 100644
--- a/hugegraph-dist/src/assembly/travis/conf-raft2/rest-server.properties
+++ b/hugegraph-dist/src/assembly/travis/conf-raft2/rest-server.properties
@@ -16,6 +16,7 @@
 #
 
 restserver.url=http://127.0.0.1:8082
+server.role.node_external_url=127.0.0.1:8082
 gremlinserver.url=http://127.0.0.1:8182
 graphs=conf/graphs
 auth.authenticator=org.apache.hugegraph.auth.StandardAuthenticator
diff --git 
a/hugegraph-dist/src/assembly/travis/conf-raft3/rest-server.properties 
b/hugegraph-dist/src/assembly/travis/conf-raft3/rest-server.properties
index 89a10f6bf..d54f1430d 100644
--- a/hugegraph-dist/src/assembly/travis/conf-raft3/rest-server.properties
+++ b/hugegraph-dist/src/assembly/travis/conf-raft3/rest-server.properties
@@ -16,6 +16,7 @@
 #
 
 restserver.url=http://127.0.0.1:8083
+server.role.node_external_url=127.0.0.1:8083
 gremlinserver.url=http://127.0.0.1:8183
 graphs=conf/graphs
 auth.authenticator=org.apache.hugegraph.auth.StandardAuthenticator
diff --git 
a/hugegraph-test/src/main/java/org/apache/hugegraph/core/RoleElectionStateMachineTest.java
 
b/hugegraph-test/src/main/java/org/apache/hugegraph/core/RoleElectionStateMachineTest.java
index 736608106..b39213a0a 100644
--- 
a/hugegraph-test/src/main/java/org/apache/hugegraph/core/RoleElectionStateMachineTest.java
+++ 
b/hugegraph-test/src/main/java/org/apache/hugegraph/core/RoleElectionStateMachineTest.java
@@ -106,6 +106,11 @@ public class RoleElectionStateMachineTest {
             return this.node;
         }
 
+        @Override
+        public String url() {
+            return "http://127.0.0.1:8080";;
+        }
+
         @Override
         public int exceedsFailCount() {
             return 2;
@@ -211,7 +216,7 @@ public class RoleElectionStateMachineTest {
                 if (stateData == null) {
                     return null;
                 }
-                return new RoleTypeData(stateData.node(), stateData.epoch(), 
stateData.clock());
+                return new RoleTypeData(stateData.node(), stateData.url(), 
stateData.epoch(), stateData.clock());
             }
 
             @Override


Reply via email to