m = new HashMap<>();
+ m.put(STATUS_KEY, -1);
+ m.put(ERROR_KEY,
+ exception == null || exception.getMessage() == null ? "" : exception.getMessage());
+ return toJSON(m);
}
public String toJSON(Object object) {
diff --git a/hugegraph-pd/hg-pd-service/src/main/java/org/apache/hugegraph/pd/rest/GraphAPI.java b/hugegraph-pd/hg-pd-service/src/main/java/org/apache/hugegraph/pd/rest/GraphAPI.java
index 0c25d78c38..7c340f4c49 100644
--- a/hugegraph-pd/hg-pd-service/src/main/java/org/apache/hugegraph/pd/rest/GraphAPI.java
+++ b/hugegraph-pd/hg-pd-service/src/main/java/org/apache/hugegraph/pd/rest/GraphAPI.java
@@ -31,6 +31,7 @@
import org.apache.hugegraph.pd.grpc.Metapb;
import org.apache.hugegraph.pd.grpc.Pdpb;
import org.apache.hugegraph.pd.model.GraphRestRequest;
+import org.apache.hugegraph.pd.model.GraphStatistics;
import org.apache.hugegraph.pd.model.RestApiResponse;
import org.apache.hugegraph.pd.service.PDRestService;
import org.apache.hugegraph.pd.service.PDService;
@@ -43,7 +44,6 @@
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
-import lombok.Data;
import lombok.extern.slf4j.Slf4j;
@RestController
@@ -56,6 +56,14 @@ public class GraphAPI extends API {
@Autowired
PDService pdService;
+ /**
+ * Get partition size range
+ *
+ * This interface is used to obtain the minimum and maximum values of partition sizes in the current system.
+ *
+ * @return RestApiResponse object containing the partition size range
+ * @throws PDException If an exception occurs while obtaining the partition size range, a PDException exception is thrown.
+ */
@GetMapping(value = "/graph/partitionSizeRange", produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public RestApiResponse getPartitionSizeRange() {
@@ -72,6 +80,15 @@ public RestApiResponse getPartitionSizeRange() {
}
}
+ /**
+ * Get all graph information
+ * This interface uses a GET request to obtain all graph information and filters out graphs whose names end with “/g”.
+ * The information of these graphs is encapsulated in a RestApiResponse object and returned.
+ *
+ * @return A RestApiResponse object containing the filtered graph information
+ * The returned object includes a “graphs” field, whose value is a list containing GraphStatistics objects
+ * @throws PDException If an exception occurs while retrieving graph information, a PDException exception is thrown
+ */
@GetMapping(value = "/graphs", produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public RestApiResponse getGraphs() {
@@ -81,7 +98,7 @@ public RestApiResponse getGraphs() {
List resultGraphs = new ArrayList<>();
for (Metapb.Graph graph : graphs) {
if ((graph.getGraphName() != null) && (graph.getGraphName().endsWith("/g"))) {
- resultGraphs.add(new GraphStatistics(graph));
+ resultGraphs.add(new GraphStatistics(graph, pdRestService, pdService));
}
}
HashMap dataMap = new HashMap<>();
@@ -99,6 +116,21 @@ public RestApiResponse getGraphs() {
return response;
}
+ /**
+ * Set graph information
+ *
+ * Receive a GraphRestRequest object via an HTTP POST request, parse the graph name from the request URL,
+ * and use the pdRestService service to obtain the current graph information.
+ * If the current graph does not exist, create a new graph object;
+ * if it exists, update the current graph object information (such as the number of partitions).
+ * Finally, use the pdRestService service to update the graph information and return the updated graph information in JSON format.
+ *
+ * @param body GraphRestRequest object containing graph information
+ * @param request HTTP request object used to obtain the graph name from the request URL
+ * @return A JSON string containing the updated graph information
+ * @throws PDException If a PD exception occurs while retrieving or updating the graph information, a PDException exception is thrown
+ * @throws Exception If other exceptions occur while processing the request, an Exception exception is thrown
+ */
@PostMapping(value = "/graph/**", consumes = MediaType.APPLICATION_JSON_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
@@ -126,12 +158,21 @@ public String setGraph(@RequestBody GraphRestRequest body, HttpServletRequest re
}
}
+ /**
+ * Get graph information
+ *
+ * Retrieves information about a specified graph via an HTTP GET request and returns it in JSON format.
+ *
+ * @param request HTTP request object used to retrieve the graph name from the request URL
+ * @return RestApiResponse object containing graph information
+ * @throws UnsupportedEncodingException Thrown if an unsupported encoding exception occurs during URL decoding
+ */
@GetMapping(value = "/graph/**", produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public RestApiResponse getGraph(HttpServletRequest request) throws
UnsupportedEncodingException {
RestApiResponse response = new RestApiResponse();
- GraphStatistics statistics = null;
+ GraphStatistics statistics;
String requestURL = request.getRequestURL().toString();
final String prefix = "/graph/";
final int limit = 2;
@@ -140,7 +181,7 @@ public RestApiResponse getGraph(HttpServletRequest request) throws
try {
Metapb.Graph graph = pdRestService.getGraph(graphName);
if (graph != null) {
- statistics = new GraphStatistics(graph);
+ statistics = new GraphStatistics(graph, pdRestService, pdService);
response.setData(statistics);
} else {
response.setData(new HashMap());
@@ -155,136 +196,4 @@ public RestApiResponse getGraph(HttpServletRequest request) throws
}
return response;
}
-
- @Data
- class Shard {
-
- long partitionId;
- long storeId;
- String state;
- String role;
- int progress;
-
- public Shard(Metapb.ShardStats shardStats, long partitionId) {
- this.role = String.valueOf(shardStats.getRole());
- this.storeId = shardStats.getStoreId();
- this.state = String.valueOf(shardStats.getState());
- this.partitionId = partitionId;
- this.progress = shardStats.getProgress();
- }
-
- public Shard(Metapb.Shard shard, long partitionId) {
- this.role = String.valueOf(shard.getRole());
- this.storeId = shard.getStoreId();
- this.state = Metapb.ShardState.SState_Normal.name();
- this.progress = 0;
- this.partitionId = partitionId;
- }
-
- }
-
- @Data
- class Partition {
-
- int partitionId;
- String graphName;
- String workState;
- long startKey;
- long endKey;
- List shards;
- long dataSize;
-
- public Partition(Metapb.Partition pt, Metapb.PartitionStats partitionStats) {
- if (pt != null) {
- partitionId = pt.getId();
- startKey = pt.getStartKey();
- endKey = pt.getEndKey();
- workState = String.valueOf(pt.getState());
- graphName = pt.getGraphName();
- final int postfixLength = 2;
- graphName = graphName.substring(0, graphName.length() - postfixLength);
- if (partitionStats != null) {
- List shardStatsList = partitionStats.getShardStatsList();
- List shardsList = new ArrayList<>();
- for (Metapb.ShardStats shardStats : shardStatsList) {
- Shard shard = new Shard(shardStats, partitionId);
- shardsList.add(shard);
- }
- this.shards = shardsList;
- } else {
- List shardsList = new ArrayList<>();
- try {
- var shardGroup = pdService.getStoreNodeService().getShardGroup(pt.getId());
- if (shardGroup != null) {
- for (Metapb.Shard shard1 : shardGroup.getShardsList()) {
- shardsList.add(new Shard(shard1, partitionId));
- }
- } else {
- log.error("GraphAPI.Partition(), get shard group: {} returns null",
- pt.getId());
- }
- } catch (PDException e) {
- log.error("Partition init failed, error: {}", e.getMessage());
- }
- this.shards = shardsList;
- }
-
- }
- }
- }
-
- @Data
- class GraphStatistics {
-
- // Graph statistics
- String graphName;
- long partitionCount;
- String state;
- List partitions;
- long dataSize;
- //todo
- int nodeCount;
- int edgeCount;
- long keyCount;
-
- public GraphStatistics(Metapb.Graph graph) throws PDException {
- if (graph == null) {
- return;
- }
- Map partition2DataSize = new HashMap<>();
- graphName = graph.getGraphName();
- partitionCount = graph.getPartitionCount();
- state = String.valueOf(graph.getState());
- // The amount of data and the number of keys
- List stores = pdRestService.getStores(graphName);
- for (Metapb.Store store : stores) {
- List graphStatsList = store.getStats().getGraphStatsList();
- for (Metapb.GraphStats graphStats : graphStatsList) {
- if ((graphName.equals(graphStats.getGraphName()))
- && (Metapb.ShardRole.Leader.equals(graphStats.getRole()))) {
- keyCount += graphStats.getApproximateKeys();
- dataSize += graphStats.getApproximateSize();
- partition2DataSize.put(graphStats.getPartitionId(),
- graphStats.getApproximateSize());
- }
- }
- }
- List resultPartitionList = new ArrayList<>();
- List tmpPartitions = pdRestService.getPartitions(graphName);
- if ((tmpPartitions != null) && (!tmpPartitions.isEmpty())) {
- // The partition information to be returned
- for (Metapb.Partition partition : tmpPartitions) {
- Metapb.PartitionStats partitionStats = pdRestService
- .getPartitionStats(graphName, partition.getId());
- Partition pt = new Partition(partition, partitionStats);
- pt.dataSize = partition2DataSize.getOrDefault(partition.getId(), 0L);
- resultPartitionList.add(pt);
- }
- }
- partitions = resultPartitionList;
- // Hide /g /m /s after the title of the graph
- final int postfixLength = 2;
- graphName = graphName.substring(0, graphName.length() - postfixLength);
- }
- }
}
diff --git a/hugegraph-pd/hg-pd-service/src/main/java/org/apache/hugegraph/pd/rest/GraphSpaceAPI.java b/hugegraph-pd/hg-pd-service/src/main/java/org/apache/hugegraph/pd/rest/GraphSpaceAPI.java
index 388f842e74..d5fbef72c3 100644
--- a/hugegraph-pd/hg-pd-service/src/main/java/org/apache/hugegraph/pd/rest/GraphSpaceAPI.java
+++ b/hugegraph-pd/hg-pd-service/src/main/java/org/apache/hugegraph/pd/rest/GraphSpaceAPI.java
@@ -46,6 +46,13 @@ public class GraphSpaceAPI extends API {
@Autowired
PDRestService pdRestService;
+ /**
+ * Get the list of graph spaces.
+ * Get the list of graph spaces via a GET request and return the results in JSON format.
+ *
+ * @return JSON format string of graph spaces.
+ * @throws PDException When an exception occurs while getting the list of graph spaces.
+ */
@GetMapping(value = "/graph-spaces", produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public String getGraphSpaces() {
@@ -58,6 +65,19 @@ public String getGraphSpaces() {
}
}
+ /**
+ * Set graph space configuration
+ *
+ * Set the configuration information of the graph space, including the graph space name and storage limits, through a POST request.
+ * The request URL format is “/graph-spaces/**”, where “**” represents the name of the graph space,
+ * which will be used after URL decoding in the request body. The request and response content types are both JSON.
+ *
+ * @param body Request body containing graph space configuration information, type is GraphSpaceRestRequest
+ * @param request HTTP request object used to obtain the request URL
+ * @return JSON string containing the configured graph space information, or error information in case of an exception
+ * @throws PDException If an exception occurs while setting the graph space configuration, it will be caught and returned as a JSON representation of the exception.
+ * @throws Exception If other exceptions occur while decoding the URL or processing the request, they will be caught and returned as a JSON representation of the exception.
+ */
@PostMapping(value = "/graph-spaces/**", consumes = MediaType.APPLICATION_JSON_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
@@ -80,6 +100,16 @@ public String setGraphSpace(@RequestBody GraphSpaceRestRequest body,
}
}
+ /**
+ * Get graph space information
+ *
+ * Get information about the specified graph space via an HTTP GET request and return it in JSON format.
+ *
+ * @param request HTTP request object used to obtain the request URL
+ * @return JSON string containing graph space information or error information
+ * @throws PDException If an exception occurs while obtaining graph space information, a PDException exception will be thrown
+ * @throws Exception If other exceptions occur while decoding the URL or processing the request, an Exception exception will be thrown
+ */
@GetMapping(value = "/graph-spaces/**", produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public String getGraphSpace(HttpServletRequest request) {
diff --git a/hugegraph-pd/hg-pd-service/src/main/java/org/apache/hugegraph/pd/rest/IndexAPI.java b/hugegraph-pd/hg-pd-service/src/main/java/org/apache/hugegraph/pd/rest/IndexAPI.java
index 61f3c5a2c6..a0448965f1 100644
--- a/hugegraph-pd/hg-pd-service/src/main/java/org/apache/hugegraph/pd/rest/IndexAPI.java
+++ b/hugegraph-pd/hg-pd-service/src/main/java/org/apache/hugegraph/pd/rest/IndexAPI.java
@@ -50,6 +50,15 @@ public class IndexAPI extends API {
@Autowired
PDRestService pdRestService;
+ /**
+ * Get brief system statistics
+ * This interface uses a GET request to obtain brief system statistics, including leader addresses, cluster status, storage size, number of graphs, and number of partitions.
+ *
+ * @return A BriefStatistics object containing the system's brief statistical information
+ * @throws PDException If an exception occurs while retrieving statistical information, a PDException exception is thrown
+ * @throws ExecutionException If a task execution exception occurs, an ExecutionException exception is thrown
+ * @throws InterruptedException If a thread is interrupted while waiting, an InterruptedException exception is thrown
+ */
@GetMapping(value = "/", produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public BriefStatistics index() throws PDException, ExecutionException, InterruptedException {
@@ -64,6 +73,16 @@ public BriefStatistics index() throws PDException, ExecutionException, Interrupt
}
+ /**
+ * Get cluster statistics
+ * Obtain various statistics about the cluster by calling related services, including node status, member list, storage information, graph information, etc.,
+ * and return them as a Statistics object.
+ *
+ * @return A RestApiResponse object containing cluster statistics
+ * @throws InterruptedException If the thread is interrupted while waiting, this exception is thrown
+ * @throws ExecutionException If an exception occurs during task execution, this exception is thrown
+ * @throws PDException If an exception occurs while processing cluster statistics, such as service call failure or data processing errors, a PDException exception is thrown
+ */
@GetMapping(value = "/v1/cluster", produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public RestApiResponse cluster() throws InterruptedException, ExecutionException {
diff --git a/hugegraph-pd/hg-pd-service/src/main/java/org/apache/hugegraph/pd/rest/MemberAPI.java b/hugegraph-pd/hg-pd-service/src/main/java/org/apache/hugegraph/pd/rest/MemberAPI.java
index c6542c47ae..4a796c37ce 100644
--- a/hugegraph-pd/hg-pd-service/src/main/java/org/apache/hugegraph/pd/rest/MemberAPI.java
+++ b/hugegraph-pd/hg-pd-service/src/main/java/org/apache/hugegraph/pd/rest/MemberAPI.java
@@ -61,17 +61,28 @@ public class MemberAPI extends API {
@Autowired
PDService pdService;
+ /**
+ * Get member information
+ *
+ * Retrieves all member information for the current PD cluster via an HTTP GET request and returns it in JSON format.
+ *
+ * @return A RestApiResponse object containing member information
+ * @throws InterruptedException If the thread is interrupted while waiting, this exception is thrown
+ * @throws ExecutionException If the task execution fails, this exception is thrown
+ */
@GetMapping(value = "/members", produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public RestApiResponse getMembers() throws InterruptedException, ExecutionException {
String leaderGrpcAddress = RaftEngine.getInstance().getLeaderGrpcAddress();
- CallStreamObserverWrap response = new CallStreamObserverWrap<>();
- pdService.getMembers(Pdpb.GetMembersRequest.newBuilder().build(), response);
+ CallStreamObserverWrap response =
+ new CallStreamObserverWrap<>();
+ pdService.getMembersAndClusterState(Pdpb.GetMembersRequest.newBuilder().build(), response);
List members = new ArrayList<>();
Member leader = null;
Map stateCountMap = new HashMap<>();
- for (Metapb.Member member : response.get().get(0).getMembersList()) {
+ Pdpb.MembersAndClusterState membersAndClusterState = response.get().get(0);
+ for (Metapb.Member member : membersAndClusterState.getMembersList()) {
String stateKey = member.getState().name();
stateCountMap.put(stateKey, stateCountMap.getOrDefault(stateKey, 0) + 1);
Member member1 = new Member(member);
@@ -81,7 +92,7 @@ public RestApiResponse getMembers() throws InterruptedException, ExecutionExcept
member1.role = member.getRole().name();
members.add(member1);
}
- String state = pdService.getStoreNodeService().getClusterStats().getState().toString();
+ String state = membersAndClusterState.getState().toString();
HashMap resultMap = new HashMap<>();
resultMap.put("state", state);
resultMap.put("pdList", members);
@@ -93,6 +104,15 @@ public RestApiResponse getMembers() throws InterruptedException, ExecutionExcept
return new RestApiResponse(resultMap, Pdpb.ErrorType.OK, Pdpb.ErrorType.OK.name());
}
+ /**
+ * Change the Peer list in the PD cluster
+ * Receive a request body containing the Peer list to be changed via an HTTP POST request, and call the corresponding service to change the Peer list in the PD cluster
+ *
+ * @param body Request body containing the list of Peers to be modified, of type PeerRestRequest
+ * @param request HTTP request object, of type HttpServletRequest
+ * @return Returns a JSON string containing the modification results
+ * @throws Exception If an exception occurs during request processing, service invocation, or Peer list modification, it is captured and returned as the JSON representation of the exception
+ */
@PostMapping(value = "/members/change", consumes = MediaType.APPLICATION_JSON_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
diff --git a/hugegraph-pd/hg-pd-service/src/main/java/org/apache/hugegraph/pd/rest/PartitionAPI.java b/hugegraph-pd/hg-pd-service/src/main/java/org/apache/hugegraph/pd/rest/PartitionAPI.java
index 5fd10cf790..5d6731fb55 100644
--- a/hugegraph-pd/hg-pd-service/src/main/java/org/apache/hugegraph/pd/rest/PartitionAPI.java
+++ b/hugegraph-pd/hg-pd-service/src/main/java/org/apache/hugegraph/pd/rest/PartitionAPI.java
@@ -56,6 +56,15 @@ public class PartitionAPI extends API {
@Autowired
PDRestService pdRestService;
+
+
+ /**
+ * Get advanced partition information
+ *
+ * This interface is used to obtain advanced partition information in the system, including graph information, key-value count, data size, etc. for each partition.
+ *
+ * @return RestApiResponse object containing advanced partition information
+ */
@GetMapping(value = "/highLevelPartitions", produces = MediaType.APPLICATION_JSON_VALUE)
public RestApiResponse getHighLevelPartitions() {
// Information about multiple graphs under the partition
@@ -90,6 +99,7 @@ public RestApiResponse getHighLevelPartitions() {
partition2DataSize.getOrDefault(graphStats.getPartitionId(),
0L)
+ graphStats.getApproximateSize());
+ // Graph information under the structure partition
if (partitions2GraphsMap.get(graphStats.getPartitionId()) == null) {
partitions2GraphsMap.put(graphStats.getPartitionId(),
new HashMap());
@@ -132,13 +142,12 @@ public RestApiResponse getHighLevelPartitions() {
partition2DataSize.getOrDefault(resultPartition.partitionId, 0L);
for (ShardStats shard : resultPartition.shards) {
// Assign values to the address and partition information of the replica
- shard.address = storesMap.get(shard.storeId).getAddress();
- shard.partitionId = partition.getId();
- }
- if ((partitionStats != null) && (partitionStats.getLeader() != null)) {
- long storeId = partitionStats.getLeader().getStoreId();
- resultPartition.leaderAddress =
- storesMap.get(storeId).getAddress();
+ Metapb.Store s = storesMap.get(shard.storeId);
+ shard.address = (s != null) ? s.getAddress() : "";
+ if (s == null) {
+ log.error("store not found for shard storeId={}, partitionId={}",
+ shard.storeId, partition.getId());
+ }
}
resultPartitionsMap.put(partition.getId(), resultPartition);
}
@@ -163,7 +172,7 @@ public RestApiResponse getHighLevelPartitions() {
postfixLength);
graphsList.add(tmpGraph);
}
- graphsList.sort((o1, o2) -> o1.graphName.compareTo(o2.graphName));
+ graphsList.sort(Comparator.comparing(o -> o.graphName));
currentPartition.graphs = graphsList;
}
List resultPartitionList = new ArrayList<>();
@@ -179,6 +188,17 @@ public RestApiResponse getHighLevelPartitions() {
return new RestApiResponse(dataMap, Pdpb.ErrorType.OK, Pdpb.ErrorType.OK.name());
}
+ /**
+ * Get partition information
+ *
+ * Retrieve all partition information, as well as the Raft node status and shard index information for each partition, by calling the pdRestService service.
+ * Then iterate through each partition to construct a partition object, including the partition name, ID, shard list, etc.
+ * For each shard, retrieve its status, progress, role, and other information via the pdRestService service, and populate the shard object with this data.
+ * Finally, add the constructed partition objects to the list and sort them by partition name and ID.
+ *
+ * @return A RestApiResponse object containing partition information
+ * @throws PDException If an exception occurs while retrieving partition information, a PDException exception is thrown
+ */
@GetMapping(value = "/partitions", produces = MediaType.APPLICATION_JSON_VALUE)
public RestApiResponse getPartitions() {
try {
@@ -236,7 +256,6 @@ public RestApiResponse getPartitions() {
role = shard.getRole();
address = pdRestService.getStore(
shard.getStoreId()).getAddress();
- partitionId = partition.getId();
if (finalShardStats.containsKey(shard.getStoreId())) {
state = finalShardStats.get(shard.getStoreId()).getState().toString();
progress = finalShardStats.get(shard.getStoreId()).getProgress();
@@ -269,6 +288,14 @@ public RestApiResponse getPartitions() {
}
}
+ /**
+ * Get partitions and their statistics
+ *
+ * This interface is used to get all partitions corresponding to the graph and their statistics, and returns them in JSON format.
+ *
+ * @return JSON string containing partitions and their statistics
+ * @throws PDException If an exception occurs while getting partitions or statistics, a PDException exception is thrown.
+ */
@GetMapping(value = "/partitionsAndStats", produces = MediaType.APPLICATION_JSON_VALUE)
public String getPartitionsAndStats() {
//for debug use, return partition && partitionStats
@@ -288,9 +315,10 @@ public String getPartitionsAndStats() {
graph2Partitions.put(graph.getGraphName(), partitionList);
graph2PartitionStats.put(graph.getGraphName(), partitionStatsList);
}
- String builder = "{\"partitions\":" + toJSON(graph2Partitions) +
- ",\"partitionStats\":" + toJSON(graph2PartitionStats) + "}";
- return builder;
+ StringBuilder builder = new StringBuilder();
+ builder.append("{\"partitions\":").append(toJSON(graph2Partitions));
+ builder.append(",\"partitionStats\":").append(toJSON(graph2PartitionStats)).append("}");
+ return builder.toString();
} catch (PDException e) {
log.error("PD exception:" + e);
return toJSON(e);
@@ -307,6 +335,14 @@ private Map getShardStats(Metapb.PartitionStats partiti
return stats;
}
+ /**
+ * Get partition log
+ * Request log records for a specified time range and return a JSON-formatted response.
+ *
+ * @param request Request body containing the requested time range, including start and end times
+ * @return Returns a JSON string containing partition log records. If no records are found, returns a JSON string containing error information
+ * @throws PDException If an exception occurs while retrieving partition logs, captures and returns a JSON string containing exception information
+ */
@PostMapping(value = "/partitions/log", consumes = MediaType.APPLICATION_JSON_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
@@ -329,6 +365,35 @@ public String getPartitionLog(@RequestBody TimeRangeRequest request) {
}
}
+ /**
+ * Reset all partition states
+ * Access the “/resetPartitionState” path via a GET request to reset all partition states
+ *
+ * @return If the operation is successful, returns the string “OK”; if an exception occurs, returns a JSON string containing the exception information
+ * @throws PDException If an exception occurs while resetting the partition state, it is caught and a JSON string containing the exception information is returned
+ */
+ @GetMapping(value = "/resetPartitionState", produces = MediaType.APPLICATION_JSON_VALUE)
+ public String resetPartitionState() {
+ try {
+ for (Metapb.Partition partition : pdRestService.getPartitions("")) {
+ pdRestService.resetPartitionState(partition);
+ }
+ } catch (PDException e) {
+ return toJSON(e);
+ }
+ return "OK";
+ }
+
+ /**
+ * Retrieve system statistics
+ * This interface obtains system statistics via a GET request and returns a Statistics object containing the statistical data
+ * The URL path is ‘/’, with the response data type being application/json
+ *
+ * @return A Statistics object containing system statistics
+ * @throws PDException Throws a PDException if an exception occurs while retrieving statistics
+ * @throws ExecutionException Throws an ExecutionException if a task execution exception occurs
+ * @throws InterruptedException Throws an InterruptedException if the thread is interrupted while waiting
+ */
@GetMapping(value = "/", produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public Statistics getStatistics() throws PDException, ExecutionException, InterruptedException {
diff --git a/hugegraph-pd/hg-pd-service/src/main/java/org/apache/hugegraph/pd/rest/PromTargetsAPI.java b/hugegraph-pd/hg-pd-service/src/main/java/org/apache/hugegraph/pd/rest/PromTargetsAPI.java
deleted file mode 100644
index 9f16181291..0000000000
--- a/hugegraph-pd/hg-pd-service/src/main/java/org/apache/hugegraph/pd/rest/PromTargetsAPI.java
+++ /dev/null
@@ -1,92 +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.pd.rest;
-
-import java.util.Collections;
-import java.util.List;
-import java.util.Optional;
-
-import org.apache.hugegraph.pd.model.PromTargetsModel;
-import org.apache.hugegraph.pd.service.PromTargetsService;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.http.MediaType;
-import org.springframework.http.ResponseEntity;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-
-import lombok.extern.slf4j.Slf4j;
-
-/**
- * TODO: ensure if we need this class & method (seems used for prometheus)
- */
-@RestController
-@Slf4j
-@RequestMapping("/v1/prom")
-public class PromTargetsAPI {
-
- @Autowired
- private PromTargetsService service;
-
- @GetMapping(value = "/targets/{appName}", produces = MediaType.APPLICATION_JSON_VALUE)
- public ResponseEntity> getPromTargets(@PathVariable(value = "appName",
- required = true)
- String appName) {
- return ResponseEntity.of(Optional.ofNullable(this.service.getTargets(appName)));
- }
-
- @GetMapping(value = "/targets-all", produces = MediaType.APPLICATION_JSON_VALUE)
- public ResponseEntity> getPromAllTargets() {
- return ResponseEntity.of(Optional.ofNullable(this.service.getAllTargets()));
- }
-
- @GetMapping(value = "/demo/targets/{appName}", produces = MediaType.APPLICATION_JSON_VALUE)
- public List getDemoTargets(@PathVariable(value = "appName",
- required = true) String targetType) {
- // TODO: ensure the IP addr is correct & useful
- PromTargetsModel model = null;
- switch (targetType) {
- case "node":
- model = PromTargetsModel.of()
- .addTarget("10.14.139.26:8100")
- .addTarget("10.14.139.27:8100")
- .addTarget("10.14.139.28:8100")
- .setMetricsPath("/metrics")
- .setScheme("http");
- break;
- case "store":
- model = PromTargetsModel.of()
- .addTarget("172.20.94.98:8521")
- .addTarget("172.20.94.98:8522")
- .addTarget("172.20.94.98:8523")
- .setMetricsPath("/actuator/prometheus")
- .setScheme("http");
- break;
- case "pd":
- model = PromTargetsModel.of()
- .addTarget("172.20.94.98:8620")
- .setMetricsPath("/actuator/prometheus");
-
- break;
- default:
-
- }
- return Collections.singletonList(model);
- }
-}
diff --git a/hugegraph-pd/hg-pd-service/src/main/java/org/apache/hugegraph/pd/rest/RegistryAPI.java b/hugegraph-pd/hg-pd-service/src/main/java/org/apache/hugegraph/pd/rest/RegistryAPI.java
index 482eac40a0..8cf02a1a86 100644
--- a/hugegraph-pd/hg-pd-service/src/main/java/org/apache/hugegraph/pd/rest/RegistryAPI.java
+++ b/hugegraph-pd/hg-pd-service/src/main/java/org/apache/hugegraph/pd/rest/RegistryAPI.java
@@ -33,6 +33,7 @@
import org.apache.hugegraph.pd.grpc.Pdpb.GetMembersResponse;
import org.apache.hugegraph.pd.grpc.discovery.NodeInfo;
import org.apache.hugegraph.pd.grpc.discovery.Query;
+import org.apache.hugegraph.pd.license.LicenseVerifierService;
import org.apache.hugegraph.pd.model.RegistryQueryRestRequest;
import org.apache.hugegraph.pd.model.RegistryRestRequest;
import org.apache.hugegraph.pd.model.RegistryRestResponse;
@@ -60,6 +61,18 @@ public class RegistryAPI extends API {
@Autowired
PDService pdService;
+ /**
+ * Register nodes with the registry center
+ *
+ * Registers node information with the registry center via a POST request and returns the registration result.
+ * The request's Content-Type is application/json, and the response's Content-Type is also application/json.
+ *
+ * @param body The request body containing registration information, including application name, version, address, tags, and registration interval, etc.
+ * @param request The HTTP request object used to obtain request-related information
+ * @return Returns the response information from the registration center, including whether the registration was successful and any error messages.
+ * @throws PDException If an exception occurs during registration (such as parameter errors), it is captured and handled, and the corresponding error message is returned.
+ * @throws PDRuntimeException If an exception occurs during runtime (such as license verification failure), it is captured and handled, and the corresponding error message is returned.
+ */
@PostMapping(value = "/registry", consumes = MediaType.APPLICATION_JSON_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
@@ -85,6 +98,15 @@ public RegistryRestResponse register(@RequestBody RegistryRestRequest body,
return registryResponse;
}
+ /**
+ * Get registration information
+ * Get registration information that matches the query conditions via an HTTP POST request
+ *
+ * @param body Request body containing query conditions, including application name, tags, version, and other information
+ * @param request HTTP request object used to receive request-related information
+ * @return Returns a response object containing registration information RegistryRestResponse
+ * @throws Exception If an exception occurs during request processing, the exception will be caught and a warning log will be recorded, and the response object will contain error information
+ */
@PostMapping(value = "/registryInfo", consumes = MediaType.APPLICATION_JSON_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
@@ -111,6 +133,18 @@ public RegistryRestResponse getInfo(@RequestBody RegistryQueryRestRequest body,
return response;
}
+ /**
+ * Retrieve all registration information
+ * This interface retrieves all registration information via a GET request, including
+ * standard registration details, PD member information, and Store member information.
+ * It encapsulates this information within a RegistryRestResponse object for return.
+ *
+ * @param request HTTP request object
+ * @return RegistryRestResponse object containing all registration information and response
+ * data such as error types
+ * @throws Exception If an exception occurs during request processing, it will be caught and
+ * a warning log recorded, while the response error type will be set to UNRECOGNIZED
+ */
@GetMapping(value = "/allInfo", consumes = MediaType.APPLICATION_JSON_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
@@ -164,6 +198,19 @@ private LinkedList getMembers() throws Exception {
return members;
}
+ /**
+ * Retrieve licence information
+ * Obtains the licence context information via an HTTP GET request and returns it
+ * encapsulated within a response object.
+ *
+ * @param request HTTP request object
+ * @return RegistryRestResponse Response object containing licence information.
+ * If licence information is successfully retrieved, errorType is OK and the data field
+ * contains the licence context;
+ * If an exception occurs, errorType is UNRECOGNIZED and includes the exception message.
+ * @throws Exception If an exception occurs while processing the request or retrieving
+ * licence information, it is caught and a warning log is recorded.
+ */
@GetMapping(value = "/license", consumes = MediaType.APPLICATION_JSON_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
@@ -171,9 +218,8 @@ public RegistryRestResponse getLicenseInfo(HttpServletRequest request) {
RegistryRestResponse response = new RegistryRestResponse();
try {
response.setErrorType(Pdpb.ErrorType.OK);
- // TODO: uncomment later
- //LicenseVerifierService licenseVerifierService = pdService.getLicenseVerifierService();
- //response.setData(licenseVerifierService.getContext());
+ LicenseVerifierService licenseVerifierService = pdService.getLicenseVerifierService();
+ response.setData(licenseVerifierService.getContext());
} catch (Exception e) {
log.warn(e.getMessage());
response.setErrorType(Pdpb.ErrorType.UNRECOGNIZED);
@@ -182,6 +228,18 @@ public RegistryRestResponse getLicenseInfo(HttpServletRequest request) {
return response;
}
+ /**
+ * Retrieve Licence Machine Information
+ * This interface obtains machine information related to the licence via a GET request,
+ * returning the data in JSON format.
+ *
+ * @param request HTTP request object to receive client request information
+ * @return RegistryRestResponse Response object containing licence machine information.
+ * Returns machine details upon successful retrieval; otherwise returns error information.
+ * @throws Exception If an exception occurs during request processing or licence machine
+ * information retrieval, it will be caught and a warning log recorded, whilst returning a
+ * response object containing exception details.
+ */
@GetMapping(value = "/license/machineInfo", consumes = MediaType.APPLICATION_JSON_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
@@ -189,9 +247,8 @@ public RegistryRestResponse getLicenseMachineInfo(HttpServletRequest request) {
RegistryRestResponse response = new RegistryRestResponse();
try {
response.setErrorType(Pdpb.ErrorType.OK);
- // TODO: uncomment later
- //LicenseVerifierService licenseVerifierService = pdService.getLicenseVerifierService();
- //response.setData(licenseVerifierService.getIpAndMac());
+ LicenseVerifierService licenseVerifierService = pdService.getLicenseVerifierService();
+ response.setData(licenseVerifierService.getIpAndMac());
} catch (Exception e) {
log.warn(e.getMessage());
response.setErrorType(Pdpb.ErrorType.UNRECOGNIZED);
diff --git a/hugegraph-pd/hg-pd-service/src/main/java/org/apache/hugegraph/pd/rest/SDConfigAPI.java b/hugegraph-pd/hg-pd-service/src/main/java/org/apache/hugegraph/pd/rest/SDConfigAPI.java
new file mode 100644
index 0000000000..dc631b12fd
--- /dev/null
+++ b/hugegraph-pd/hg-pd-service/src/main/java/org/apache/hugegraph/pd/rest/SDConfigAPI.java
@@ -0,0 +1,128 @@
+/*
+ * 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.pd.rest;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+
+import org.apache.hugegraph.pd.model.SDConfig;
+import org.apache.hugegraph.pd.service.SDConfigService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import lombok.extern.slf4j.Slf4j;
+@RestController
+@Slf4j
+@RequestMapping("/v1/prom")
+public class SDConfigAPI {
+
+ @Autowired
+ private SDConfigService service;
+
+ /**
+ * Get Prometheus monitoring targets based on application name
+ * Use a GET request to get a list of corresponding Prometheus monitoring targets based on
+ * the provided application name
+ * The URL path is: /targets/{appName}, and the response data type is JSON
+ *
+ * @param appName Application name, this parameter is a path variable and is required
+ * @return ResponseEntity object containing the JSON-formatted response of the Prometheus
+ * monitoring target list
+ */
+ @GetMapping(value = "/targets/{appName}", produces = MediaType.APPLICATION_JSON_VALUE)
+ public ResponseEntity> getPromTargets(
+ @PathVariable(value = "appName", required = true) String appName) {
+ return ResponseEntity.of(Optional.ofNullable(this.service.getTargets(appName)));
+ }
+
+ /**
+ * Get all target configuration interfaces.
+ * Get a list of all target configurations via a GET request and return it in JSON format.
+ *
+ * @return ResponseEntity encapsulated List object containing all target configurations.
+ */
+ @GetMapping(value = "/targets-all", produces = MediaType.APPLICATION_JSON_VALUE)
+ public ResponseEntity> getPromAllTargets() {
+ return ResponseEntity.of(Optional.ofNullable(this.service.getAllTargets()));
+ }
+
+ /**
+ * Get sample monitoring targets based on application name
+ * Based on the input application name (targetType), return the corresponding list of monitoring target configurations.
+ * Supported application types are “node”, ‘store’, and “pd”, which correspond to different monitoring target configurations.
+ * If the input application name is invalid, returns a list containing empty SDConfig objects.
+ *
+ * @param targetType Application type, supporting “node”, ‘store’, and “pd” types
+ * @return A list of SDConfig objects containing monitoring targets. If targetType is an invalid type, returns a list containing empty SDConfig objects
+ */
+ @GetMapping(value = "/demo/targets/{appName}", produces = MediaType.APPLICATION_JSON_VALUE)
+ public List getDemoTargets(
+ @PathVariable(value = "appName", required = true) String targetType) {
+
+ SDConfig model = null;
+ switch (targetType) {
+ case "node":
+ model = SDConfig.of()
+ .addTarget("10.14.139.26:8100")
+ .addTarget("10.14.139.27:8100")
+ .addTarget("10.14.139.28:8100")
+ .setMetricsPath("/metrics")
+ .setScheme("http");
+ break;
+ case "store":
+ model = SDConfig.of()
+ .addTarget("172.20.94.98:8521")
+ .addTarget("172.20.94.98:8522")
+ .addTarget("172.20.94.98:8523")
+ .setMetricsPath("/actuator/prometheus")
+ .setScheme("http");
+ break;
+ case "pd":
+ model = SDConfig.of()
+ .addTarget("172.20.94.98:8620")
+ .setMetricsPath("/actuator/prometheus");
+
+ break;
+ default:
+ }
+ return model == null ? Collections.emptyList() : Collections.singletonList(model);
+ }
+
+ /**
+ * Get service discovery configuration
+ * Get service discovery configuration information based on application name and path
+ *
+ * @param appName Application name, request parameter, used to specify the application for which to get the configuration
+ * @param path Optional parameter, request parameter, specifies the path for which to get the service discovery configuration
+ * @return ResponseEntity object, contains a list of service discovery configurations, returned in JSON format
+ */
+ @GetMapping(value = "/sd_config", produces = MediaType.APPLICATION_JSON_VALUE)
+ public ResponseEntity> getSDConfig(@RequestParam(value = "appName") String appName,
+ @RequestParam(value = "path", required = false)
+ String path) {
+ return ResponseEntity.of(Optional.ofNullable(this.service.getConfigs(appName, path)));
+ }
+
+}
diff --git a/hugegraph-pd/hg-pd-service/src/main/java/org/apache/hugegraph/pd/rest/StoreAPI.java b/hugegraph-pd/hg-pd-service/src/main/java/org/apache/hugegraph/pd/rest/StoreAPI.java
index 10c783f7db..9d7211e3c9 100644
--- a/hugegraph-pd/hg-pd-service/src/main/java/org/apache/hugegraph/pd/rest/StoreAPI.java
+++ b/hugegraph-pd/hg-pd-service/src/main/java/org/apache/hugegraph/pd/rest/StoreAPI.java
@@ -17,6 +17,7 @@
package org.apache.hugegraph.pd.rest;
+import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
@@ -235,6 +236,19 @@ public String getStoreMonitorDataText(@PathVariable long storeId) {
}
}
+ /**
+ * Retrieve shard group cache information
+ * This interface obtains shard group cache information via a GET request and returns a
+ * JSON-formatted string
+ *
+ * @return JSON string containing shard group cache information
+ */
+ @GetMapping(value = "/shardGroupsCache", produces = MediaType.APPLICATION_JSON_VALUE)
+ @ResponseBody
+ public String getShardGroupsCache() {
+ return toJSON(new ArrayList<>(pdRestService.getShardGroupCache().values()), "shardGroups");
+ }
+
@Data
class Partition {
@@ -262,7 +276,7 @@ class Partition {
class StoreStatistics {
// store statistics
- long storeId;
+ String storeId;
String address;
String raftAddress;
String version;
@@ -286,7 +300,7 @@ class StoreStatistics {
StoreStatistics(Metapb.Store store) {
if (store != null) {
- storeId = store.getId();
+ storeId = String.valueOf(store.getId());
address = store.getAddress();
raftAddress = store.getRaftAddress();
state = String.valueOf(store.getState());
@@ -357,4 +371,16 @@ class StoreStatistics {
}
}
+ /**
+ * Check Service Health Status
+ * This interface is used to check the health status of the service by accessing the /health
+ * path via a GET request.
+ *
+ * @return Returns a string indicating the service's health status. Typically, an empty
+ * string indicates the service is healthy.
+ */
+ @GetMapping(value = "/health", produces = MediaType.TEXT_PLAIN_VALUE)
+ public Serializable checkHealthy() {
+ return "";
+ }
}
diff --git a/hugegraph-pd/hg-pd-service/src/main/java/org/apache/hugegraph/pd/rest/TestAPI.java b/hugegraph-pd/hg-pd-service/src/main/java/org/apache/hugegraph/pd/rest/TestAPI.java
index e4ee1c1411..a0e22213f5 100644
--- a/hugegraph-pd/hg-pd-service/src/main/java/org/apache/hugegraph/pd/rest/TestAPI.java
+++ b/hugegraph-pd/hg-pd-service/src/main/java/org/apache/hugegraph/pd/rest/TestAPI.java
@@ -31,6 +31,7 @@
import org.apache.hugegraph.pd.meta.MetadataFactory;
import org.apache.hugegraph.pd.meta.QueueStore;
import org.apache.hugegraph.pd.pulse.PDPulseSubject;
+import org.apache.hugegraph.pd.watch.ChangeType;
import org.apache.hugegraph.pd.watch.PDWatchSubject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
@@ -93,7 +94,7 @@ public String notifyClient() {
@GetMapping(value = "/partition", produces = MediaType.TEXT_PLAIN_VALUE)
@ResponseBody
public String noticePartition() {
- PDWatchSubject.notifyPartitionChange(PDWatchSubject.ChangeType.ALTER, "graph-test", 99);
+ PDWatchSubject.notifyPartitionChange(ChangeType.ALTER, "graph-test", 99);
return "partition";
}
diff --git a/hugegraph-pd/hg-pd-service/src/main/java/org/apache/hugegraph/pd/rest/interceptor/AuthenticationConfigurer.java b/hugegraph-pd/hg-pd-service/src/main/java/org/apache/hugegraph/pd/rest/interceptor/AuthenticationConfigurer.java
new file mode 100644
index 0000000000..7d10416967
--- /dev/null
+++ b/hugegraph-pd/hg-pd-service/src/main/java/org/apache/hugegraph/pd/rest/interceptor/AuthenticationConfigurer.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hugegraph.pd.rest.interceptor;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+@Configuration
+public class AuthenticationConfigurer implements WebMvcConfigurer {
+
+ @Autowired
+ RestAuthentication restAuthentication;
+
+ @Override
+ public void addInterceptors(InterceptorRegistry registry) {
+ registry.addInterceptor(restAuthentication)
+ .addPathPatterns("/**")
+ .excludePathPatterns("/actuator/*", "/v1/health", "/v1/prom/targets/*");
+ }
+}
diff --git a/hugegraph-pd/hg-pd-service/src/main/java/org/apache/hugegraph/pd/rest/interceptor/RestAuthentication.java b/hugegraph-pd/hg-pd-service/src/main/java/org/apache/hugegraph/pd/rest/interceptor/RestAuthentication.java
new file mode 100644
index 0000000000..fbc129078c
--- /dev/null
+++ b/hugegraph-pd/hg-pd-service/src/main/java/org/apache/hugegraph/pd/rest/interceptor/RestAuthentication.java
@@ -0,0 +1,80 @@
+/*
+ * 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.pd.rest.interceptor;
+
+import java.io.IOException;
+import java.util.function.Function;
+import java.util.function.Supplier;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.hugegraph.pd.rest.API;
+import org.apache.hugegraph.pd.service.interceptor.Authentication;
+import org.springframework.lang.Nullable;
+import org.springframework.stereotype.Service;
+import org.springframework.web.servlet.HandlerInterceptor;
+import org.springframework.web.servlet.ModelAndView;
+
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@Service
+public class RestAuthentication extends Authentication implements HandlerInterceptor {
+
+ private static final String TOKEN_KEY = "Pd-Token";
+ private static final Supplier DEFAULT_HANDLE = () -> true;
+
+ @Override
+ public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
+ Object handler) throws
+ IOException {
+ try {
+ String token = request.getHeader(TOKEN_KEY);
+ String authority = request.getHeader("Authorization");
+
+ if (authority == null) {
+ throw new Exception("Unauthorized!");
+ }
+
+ Function tokenCall = t -> {
+ response.addHeader(TOKEN_KEY, t);
+ return true;
+ };
+ authority = authority.replace("Basic ", "");
+ return authenticate(authority, token, tokenCall, DEFAULT_HANDLE);
+ } catch (Exception e) {
+ response.setContentType("application/json");
+ response.getWriter().println(new API().toJSON(e));
+ response.getWriter().flush();
+ return false;
+ }
+ }
+
+ @Override
+ public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
+ @Nullable
+ ModelAndView modelAndView) {
+ }
+
+ @Override
+ public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
+ Object handler,
+ @Nullable Exception ex) {
+ }
+}
diff --git a/hugegraph-pd/hg-pd-service/src/main/java/org/apache/hugegraph/pd/service/DiscoveryService.java b/hugegraph-pd/hg-pd-service/src/main/java/org/apache/hugegraph/pd/service/DiscoveryService.java
index 08a4e8aa9e..00a652577f 100644
--- a/hugegraph-pd/hg-pd-service/src/main/java/org/apache/hugegraph/pd/service/DiscoveryService.java
+++ b/hugegraph-pd/hg-pd-service/src/main/java/org/apache/hugegraph/pd/service/DiscoveryService.java
@@ -34,6 +34,7 @@
import org.apache.hugegraph.pd.grpc.discovery.NodeInfos;
import org.apache.hugegraph.pd.grpc.discovery.Query;
import org.apache.hugegraph.pd.grpc.discovery.RegisterInfo;
+import org.apache.hugegraph.pd.license.LicenseVerifierService;
import org.apache.hugegraph.pd.raft.RaftEngine;
import org.apache.hugegraph.pd.raft.RaftStateListener;
import org.lognet.springboot.grpc.GRpcService;
@@ -46,16 +47,14 @@
@Slf4j
@GRpcService
public class DiscoveryService extends DiscoveryServiceGrpc.DiscoveryServiceImplBase implements
- ServiceGrpc,
- RaftStateListener {
+ ServiceGrpc {
static final AtomicLong id = new AtomicLong();
private static final String CORES = "cores";
RegistryService register = null;
- //LicenseVerifierService licenseVerifierService;
+ LicenseVerifierService licenseVerifierService;
@Autowired
private PDConfig pdConfig;
- private ManagedChannel channel;
@PostConstruct
public void init() throws PDException {
@@ -63,7 +62,7 @@ public void init() throws PDException {
RaftEngine.getInstance().init(pdConfig.getRaft());
RaftEngine.getInstance().addStateListener(this);
register = new RegistryService(pdConfig);
- //licenseVerifierService = new LicenseVerifierService(pdConfig);
+ licenseVerifierService = new LicenseVerifierService(pdConfig);
}
private Pdpb.ResponseHeader newErrorHeader(PDException e) {
@@ -76,7 +75,7 @@ private Pdpb.ResponseHeader newErrorHeader(PDException e) {
@Override
public void register(NodeInfo request, io.grpc.stub.StreamObserver observer) {
if (!isLeader()) {
- redirectToLeader(null, DiscoveryServiceGrpc.getRegisterMethod(), request, observer);
+ redirectToLeader(DiscoveryServiceGrpc.getRegisterMethod(), request, observer);
return;
}
int outTimes = pdConfig.getDiscovery().getHeartbeatOutTimes();
@@ -100,7 +99,7 @@ public void register(NodeInfo request, io.grpc.stub.StreamObserver
throw new PDException(-1, "core count can not be null");
}
int core = Integer.parseInt(coreCount);
- //licenseVerifierService.verify(core, nodeCount);
+ licenseVerifierService.verify(core, nodeCount);
}
register.register(request, outTimes);
String valueId = request.getId();
@@ -129,18 +128,15 @@ public void register(NodeInfo request, io.grpc.stub.StreamObserver
observer.onCompleted();
}
- @Override
public void getNodes(Query request, io.grpc.stub.StreamObserver responseObserver) {
if (!isLeader()) {
- redirectToLeader(null, DiscoveryServiceGrpc.getGetNodesMethod(), request,
- responseObserver);
+ redirectToLeader(DiscoveryServiceGrpc.getGetNodesMethod(), request, responseObserver);
return;
}
responseObserver.onNext(register.getNodes(request));
responseObserver.onCompleted();
}
- @Override
public boolean isLeader() {
return RaftEngine.getInstance().isLeader();
}
diff --git a/hugegraph-pd/hg-pd-service/src/main/java/org/apache/hugegraph/pd/service/KvServiceGrpcImpl.java b/hugegraph-pd/hg-pd-service/src/main/java/org/apache/hugegraph/pd/service/KvServiceGrpcImpl.java
index 088403fb5a..e49a4dc48b 100644
--- a/hugegraph-pd/hg-pd-service/src/main/java/org/apache/hugegraph/pd/service/KvServiceGrpcImpl.java
+++ b/hugegraph-pd/hg-pd-service/src/main/java/org/apache/hugegraph/pd/service/KvServiceGrpcImpl.java
@@ -63,7 +63,7 @@
public class KvServiceGrpcImpl extends KvServiceGrpc.KvServiceImplBase implements RaftStateListener,
ServiceGrpc {
- private final ManagedChannel channel = null;
+ private ManagedChannel channel = null;
KvService kvService;
AtomicLong count = new AtomicLong();
String msg = "node is not leader,it is necessary to redirect to the leader on the client";
@@ -83,7 +83,7 @@ public void init() {
if (isLeader()) {
subjects.keepClientAlive();
}
- }, 0, KvWatchSubject.WATCH_TTL / 2, TimeUnit.MILLISECONDS);
+ }, 0, KvWatchSubject.WATCH_TTL * 1 / 3, TimeUnit.MILLISECONDS);
}
/**
@@ -92,7 +92,6 @@ public void init() {
* @param request
* @param responseObserver
*/
- @Override
public void put(Kv request, StreamObserver responseObserver) {
if (!isLeader()) {
redirectToLeader(channel, KvServiceGrpc.getPutMethod(), request, responseObserver);
@@ -124,7 +123,6 @@ public void put(Kv request, StreamObserver responseObserver) {
* @param request
* @param responseObserver
*/
- @Override
public void get(K request, StreamObserver responseObserver) {
if (!isLeader()) {
redirectToLeader(channel, KvServiceGrpc.getGetMethod(), request, responseObserver);
@@ -156,7 +154,6 @@ public void get(K request, StreamObserver responseObserver) {
* @param request
* @param responseObserver
*/
- @Override
public void delete(K request, StreamObserver responseObserver) {
if (!isLeader()) {
redirectToLeader(channel, KvServiceGrpc.getDeleteMethod(), request, responseObserver);
@@ -190,7 +187,6 @@ public void delete(K request, StreamObserver responseObserver) {
* @param request
* @param responseObserver
*/
- @Override
public void deletePrefix(K request, StreamObserver responseObserver) {
if (!isLeader()) {
redirectToLeader(channel, KvServiceGrpc.getDeletePrefixMethod(), request,
@@ -228,7 +224,6 @@ public void deletePrefix(K request, StreamObserver responseObserver)
* @param request
* @param responseObserver
*/
- @Override
public void scanPrefix(K request, StreamObserver responseObserver) {
if (!isLeader()) {
redirectToLeader(channel, KvServiceGrpc.getScanPrefixMethod(), request,
@@ -273,7 +268,6 @@ private long getRandomLong() {
* @param request
* @param responseObserver
*/
- @Override
public void watch(WatchRequest request, StreamObserver responseObserver) {
if (!isLeader()) {
responseObserver.onError(new PDException(-1, msg));
@@ -285,6 +279,7 @@ public void watch(WatchRequest request, StreamObserver responseOb
if (!isLeader()) {
try {
responseObserver.onError(new PDException(-1, msg));
+ return;
} catch (IllegalStateException ie) {
} catch (Exception e1) {
@@ -300,7 +295,6 @@ public void watch(WatchRequest request, StreamObserver responseOb
* @param request
* @param responseObserver
*/
- @Override
public void watchPrefix(WatchRequest request, StreamObserver responseObserver) {
if (!isLeader()) {
responseObserver.onError(new PDException(-1, msg));
@@ -312,6 +306,7 @@ public void watchPrefix(WatchRequest request, StreamObserver resp
if (!isLeader()) {
try {
responseObserver.onError(new PDException(-1, msg));
+ return;
} catch (IllegalStateException ie) {
} catch (Exception e1) {
@@ -363,7 +358,6 @@ private void clientWatch(WatchRequest request, StreamObserver res
* @param request
* @param responseObserver
*/
- @Override
public void lock(LockRequest request, StreamObserver responseObserver) {
if (!isLeader()) {
redirectToLeader(channel, KvServiceGrpc.getLockMethod(), request, responseObserver);
@@ -392,7 +386,6 @@ public void lock(LockRequest request, StreamObserver responseObser
responseObserver.onCompleted();
}
- @Override
public void lockWithoutReentrant(LockRequest request,
StreamObserver responseObserver) {
if (!isLeader()) {
@@ -425,7 +418,6 @@ public void lockWithoutReentrant(LockRequest request,
responseObserver.onCompleted();
}
- @Override
public void isLocked(LockRequest request, StreamObserver responseObserver) {
if (!isLeader()) {
redirectToLeader(channel, KvServiceGrpc.getIsLockedMethod(), request, responseObserver);
@@ -455,7 +447,6 @@ public void isLocked(LockRequest request, StreamObserver responseO
* @param request
* @param responseObserver
*/
- @Override
public void unlock(LockRequest request, StreamObserver responseObserver) {
if (!isLeader()) {
redirectToLeader(channel, KvServiceGrpc.getUnlockMethod(), request, responseObserver);
@@ -489,7 +480,6 @@ public void unlock(LockRequest request, StreamObserver responseObs
* @param request
* @param responseObserver
*/
- @Override
public void keepAlive(LockRequest request, StreamObserver responseObserver) {
if (!isLeader()) {
redirectToLeader(channel, KvServiceGrpc.getKeepAliveMethod(), request,
@@ -525,7 +515,6 @@ public void keepAlive(LockRequest request, StreamObserver response
* @param request
* @param responseObserver
*/
- @Override
public void putTTL(TTLRequest request, StreamObserver responseObserver) {
if (!isLeader()) {
redirectToLeader(channel, KvServiceGrpc.getPutTTLMethod(), request, responseObserver);
@@ -554,7 +543,6 @@ public void putTTL(TTLRequest request, StreamObserver responseObser
* @param request
* @param responseObserver
*/
- @Override
public void keepTTLAlive(TTLRequest request, StreamObserver responseObserver) {
if (!isLeader()) {
redirectToLeader(channel, KvServiceGrpc.getKeepTTLAliveMethod(), request,
diff --git a/hugegraph-pd/hg-pd-service/src/main/java/org/apache/hugegraph/pd/service/MetaServiceGrpcImpl.java b/hugegraph-pd/hg-pd-service/src/main/java/org/apache/hugegraph/pd/service/MetaServiceGrpcImpl.java
new file mode 100644
index 0000000000..f6621afb80
--- /dev/null
+++ b/hugegraph-pd/hg-pd-service/src/main/java/org/apache/hugegraph/pd/service/MetaServiceGrpcImpl.java
@@ -0,0 +1,258 @@
+/*
+ * 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.pd.service;
+
+import org.apache.hugegraph.pd.common.PDException;
+import org.apache.hugegraph.pd.grpc.GraphSpaces;
+import org.apache.hugegraph.pd.grpc.Graphs;
+import org.apache.hugegraph.pd.grpc.MetaServiceGrpc;
+import org.apache.hugegraph.pd.grpc.MetaServiceGrpc.MetaServiceImplBase;
+import org.apache.hugegraph.pd.grpc.Metapb.Graph;
+import org.apache.hugegraph.pd.grpc.Metapb.GraphSpace;
+import org.apache.hugegraph.pd.grpc.Metapb.Partition;
+import org.apache.hugegraph.pd.grpc.Metapb.ShardGroup;
+import org.apache.hugegraph.pd.grpc.Metapb.Store;
+import org.apache.hugegraph.pd.grpc.Partitions;
+import org.apache.hugegraph.pd.grpc.Pdpb;
+import org.apache.hugegraph.pd.grpc.ShardGroups;
+import org.apache.hugegraph.pd.grpc.Stores;
+import org.apache.hugegraph.pd.grpc.VoidResponse;
+import org.apache.hugegraph.pd.grpc.common.NoArg;
+import org.lognet.springboot.grpc.GRpcService;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import io.grpc.stub.StreamObserver;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@GRpcService
+public class MetaServiceGrpcImpl extends MetaServiceImplBase implements ServiceGrpc {
+
+ @Autowired
+ private MetadataService metadataService;
+
+ public void getStores(NoArg request, StreamObserver observer) {
+ if (!isLeader()) {
+ redirectToLeader(MetaServiceGrpc.getGetStoresMethod(), request, observer);
+ return;
+ }
+ Stores response;
+ Stores.Builder builder = Stores.newBuilder();
+ try {
+ response = metadataService.getStores();
+ } catch (PDException e) {
+ if (!isLeader()) {
+ redirectToLeader(MetaServiceGrpc.getGetStoresMethod(), request, observer);
+ return;
+ }
+ response = builder.setHeader(getResponseHeader(e)).build();
+ }
+ observer.onNext(response);
+ observer.onCompleted();
+ }
+
+ public void getPartitions(NoArg request, StreamObserver observer) {
+ if (!isLeader()) {
+ redirectToLeader(MetaServiceGrpc.getGetPartitionsMethod(), request, observer);
+ return;
+ }
+ Partitions response;
+ Partitions.Builder builder = Partitions.newBuilder();
+ try {
+ response = metadataService.getPartitions();
+ } catch (PDException e) {
+ if (!isLeader()) {
+ redirectToLeader(MetaServiceGrpc.getGetPartitionsMethod(), request, observer);
+ return;
+ }
+ response = builder.setHeader(getResponseHeader(e)).build();
+ }
+ observer.onNext(response);
+ observer.onCompleted();
+ }
+
+ public void getShardGroups(NoArg request, StreamObserver observer) {
+ if (!isLeader()) {
+ redirectToLeader(MetaServiceGrpc.getGetShardGroupsMethod(), request, observer);
+ return;
+ }
+ ShardGroups response;
+ ShardGroups.Builder builder = ShardGroups.newBuilder();
+ try {
+ response = metadataService.getShardGroups();
+ } catch (PDException e) {
+ if (!isLeader()) {
+ redirectToLeader(MetaServiceGrpc.getGetShardGroupsMethod(), request, observer);
+ return;
+ }
+ response = builder.setHeader(getResponseHeader(e)).build();
+ }
+ observer.onNext(response);
+ observer.onCompleted();
+ }
+
+ public void getGraphSpaces(NoArg request, StreamObserver observer) {
+ if (!isLeader()) {
+ redirectToLeader(MetaServiceGrpc.getGetGraphSpacesMethod(), request, observer);
+ return;
+ }
+ GraphSpaces response;
+ GraphSpaces.Builder builder = GraphSpaces.newBuilder();
+ try {
+ response = metadataService.getGraphSpaces();
+ } catch (PDException e) {
+ if (!isLeader()) {
+ redirectToLeader(MetaServiceGrpc.getGetGraphSpacesMethod(), request, observer);
+ return;
+ }
+ response = builder.setHeader(getResponseHeader(e)).build();
+ }
+ observer.onNext(response);
+ observer.onCompleted();
+ }
+
+ public void getGraphs(NoArg request, StreamObserver observer) {
+ if (!isLeader()) {
+ redirectToLeader(MetaServiceGrpc.getGetGraphsMethod(), request, observer);
+ return;
+ }
+ Graphs response;
+ Graphs.Builder builder = Graphs.newBuilder();
+ try {
+ response = metadataService.getGraphs();
+ } catch (PDException e) {
+ if (!isLeader()) {
+ redirectToLeader(MetaServiceGrpc.getGetGraphsMethod(), request, observer);
+ return;
+ }
+ response = builder.setHeader(getResponseHeader(e)).build();
+ }
+ observer.onNext(response);
+ observer.onCompleted();
+ }
+
+ public void updateStore(Store request, StreamObserver observer) {
+ if (!isLeader()) {
+ redirectToLeader(MetaServiceGrpc.getUpdateStoreMethod(), request, observer);
+ return;
+ }
+ VoidResponse response;
+ VoidResponse.Builder builder = VoidResponse.newBuilder();
+ try {
+ metadataService.updateStore(request);
+ response = builder.build();
+ } catch (PDException e) {
+ if (!isLeader()) {
+ redirectToLeader(MetaServiceGrpc.getUpdateStoreMethod(), request, observer);
+ return;
+ }
+ Pdpb.ResponseHeader header = getResponseHeader(e);
+ response = builder.setHeader(header).build();
+ }
+ observer.onNext(response);
+ observer.onCompleted();
+ }
+
+ public void updatePartition(Partition request, StreamObserver observer) {
+ if (!isLeader()) {
+ redirectToLeader(MetaServiceGrpc.getUpdatePartitionMethod(), request, observer);
+ return;
+ }
+ VoidResponse response;
+ VoidResponse.Builder builder = VoidResponse.newBuilder();
+ try {
+ metadataService.updatePartition(request);
+ response = builder.build();
+ } catch (PDException e) {
+ if (!isLeader()) {
+ redirectToLeader(MetaServiceGrpc.getUpdatePartitionMethod(), request, observer);
+ return;
+ }
+ Pdpb.ResponseHeader header = getResponseHeader(e);
+ response = builder.setHeader(header).build();
+ }
+ observer.onNext(response);
+ observer.onCompleted();
+ }
+
+ public void updateShardGroup(ShardGroup request, StreamObserver observer) {
+ if (!isLeader()) {
+ redirectToLeader(MetaServiceGrpc.getUpdateShardGroupMethod(), request, observer);
+ return;
+ }
+ VoidResponse response;
+ VoidResponse.Builder builder = VoidResponse.newBuilder();
+ try {
+ metadataService.updateShardGroup(request);
+ response = builder.build();
+ } catch (PDException e) {
+ if (!isLeader()) {
+ redirectToLeader(MetaServiceGrpc.getUpdateShardGroupMethod(), request, observer);
+ return;
+ }
+ Pdpb.ResponseHeader header = getResponseHeader(e);
+ response = builder.setHeader(header).build();
+ }
+ observer.onNext(response);
+ observer.onCompleted();
+ }
+
+ public void updateGraphSpace(GraphSpace request, StreamObserver observer) {
+ if (!isLeader()) {
+ redirectToLeader(MetaServiceGrpc.getUpdateGraphSpaceMethod(), request, observer);
+ return;
+ }
+ VoidResponse response;
+ VoidResponse.Builder builder = VoidResponse.newBuilder();
+ try {
+ metadataService.updateGraphSpace(request);
+ response = builder.build();
+ } catch (PDException e) {
+ if (!isLeader()) {
+ redirectToLeader(MetaServiceGrpc.getUpdateGraphSpaceMethod(), request, observer);
+ return;
+ }
+ Pdpb.ResponseHeader header = getResponseHeader(e);
+ response = builder.setHeader(header).build();
+ }
+ observer.onNext(response);
+ observer.onCompleted();
+ }
+
+ public void updateGraph(Graph request, StreamObserver observer) {
+ if (!isLeader()) {
+ redirectToLeader(MetaServiceGrpc.getUpdateGraphMethod(), request, observer);
+ return;
+ }
+ VoidResponse response;
+ VoidResponse.Builder builder = VoidResponse.newBuilder();
+ try {
+ metadataService.updateGraph(request);
+ response = builder.build();
+ } catch (PDException e) {
+ if (!isLeader()) {
+ redirectToLeader(MetaServiceGrpc.getUpdateGraphMethod(), request, observer);
+ return;
+ }
+ Pdpb.ResponseHeader header = getResponseHeader(e);
+ response = builder.setHeader(header).build();
+ }
+ observer.onNext(response);
+ observer.onCompleted();
+ }
+}
diff --git a/hugegraph-pd/hg-pd-service/src/main/java/org/apache/hugegraph/pd/service/PDPulseService.java b/hugegraph-pd/hg-pd-service/src/main/java/org/apache/hugegraph/pd/service/PDPulseService.java
index 04db6ae35c..a297b7e503 100644
--- a/hugegraph-pd/hg-pd-service/src/main/java/org/apache/hugegraph/pd/service/PDPulseService.java
+++ b/hugegraph-pd/hg-pd-service/src/main/java/org/apache/hugegraph/pd/service/PDPulseService.java
@@ -41,14 +41,13 @@
@GRpcService
public class PDPulseService extends HgPdPulseGrpc.HgPdPulseImplBase {
- private static final Supplier> QUEUE_RETRIEVE_FUNCTION =
+ private static Supplier> queueRetrieveFunction =
() -> Collections.emptyList();
- private static final Function QUEUE_ITEM_BOOLEAN_FUNCTION =
- (e) -> true;
- private static final Function QUEUE_REMOVE_FUNCTION = (e) -> true;
+ private static Function queueDurableFunction = (e) -> true;
+ private static final Function queueRemoveFunction = (e) -> true;
@Autowired
private PDConfig pdConfig;
- private QueueStore queueStore = null;
+ private volatile QueueStore queueStore;
public PDPulseService() {
PDPulseSubject.setQueueRetrieveFunction(() -> getQueue());
@@ -108,9 +107,16 @@ private List getQueue() {
}
private QueueStore getQueueStore() {
- if (this.queueStore == null) {
- this.queueStore = MetadataFactory.newQueueStore(pdConfig);
+ QueueStore local = this.queueStore;
+ if (local == null) {
+ synchronized (this) {
+ local = this.queueStore;
+ if (local == null) {
+ local = MetadataFactory.newQueueStore(pdConfig);
+ this.queueStore = local;
+ }
+ }
}
- return this.queueStore;
+ return local;
}
}
diff --git a/hugegraph-pd/hg-pd-service/src/main/java/org/apache/hugegraph/pd/service/PDRestService.java b/hugegraph-pd/hg-pd-service/src/main/java/org/apache/hugegraph/pd/service/PDRestService.java
index 9df8381112..c9d55370cf 100644
--- a/hugegraph-pd/hg-pd-service/src/main/java/org/apache/hugegraph/pd/service/PDRestService.java
+++ b/hugegraph-pd/hg-pd-service/src/main/java/org/apache/hugegraph/pd/service/PDRestService.java
@@ -132,6 +132,10 @@ public List getPartitions(String graphName) {
return partitionService.getPartitions(graphName);
}
+ public Map