| # HugeGraph PD API Reference |
| |
| This document provides comprehensive API reference for HugeGraph PD, including gRPC services, Protocol Buffers definitions, and usage examples. |
| |
| ## Table of Contents |
| |
| - [gRPC Services Overview](#grpc-services-overview) |
| - [Protocol Buffers Definitions](#protocol-buffers-definitions) |
| - [Core gRPC APIs](#core-grpc-apis) |
| - [Java Client Library](#java-client-library) |
| - [REST API](#rest-api) |
| |
| ## gRPC Services Overview |
| |
| HugeGraph PD exposes multiple gRPC services for cluster management and coordination: |
| |
| | Service | Proto File | Description | |
| |---------|------------|-------------| |
| | **PDGrpc** | `pdpb.proto` | Main PD service: store registration, partition queries, member management | |
| | **KvServiceGrpc** | `kv.proto` | Distributed key-value operations for metadata storage | |
| | **HgPdPulseGrpc** | `pd_pulse.proto` | Heartbeat and health monitoring for Store nodes | |
| | **HgPdWatchGrpc** | `pd_watch.proto` | Watch for partition and store change notifications | |
| | **DiscoveryServiceGrpc** | `discovery.proto` | Service discovery and registration | |
| |
| **Proto Location**: `hugegraph-pd/hg-pd-grpc/src/main/proto/` |
| |
| **Generated Stubs**: `hugegraph-pd/hg-pd-grpc/src/main/java/org/apache/hugegraph/pd/grpc/` |
| |
| ## Protocol Buffers Definitions |
| |
| ### Proto Files Structure |
| |
| ``` |
| hg-pd-grpc/src/main/proto/ |
| ├── pdpb.proto # Main PD service RPCs |
| ├── metapb.proto # Core metadata objects (Partition, Shard, Store) |
| ├── meta.proto # Extended metadata definitions |
| ├── pd_common.proto # Common types and enums |
| ├── kv.proto # Key-value service |
| ├── pd_pulse.proto # Heartbeat protocol |
| ├── pd_watch.proto # Watch notification protocol |
| ├── discovery.proto # Service discovery |
| └── metaTask.proto # Task coordination |
| ``` |
| |
| ### Key Message Types |
| |
| #### Partition |
| |
| Represents a data partition in the cluster. |
| |
| ```protobuf |
| message Partition { |
| uint64 id = 1; |
| string graph_name = 2; |
| uint64 start_key = 3; |
| uint64 end_key = 4; |
| repeated Shard shards = 5; |
| PartitionState state = 6; |
| uint64 version = 7; |
| } |
| |
| enum PartitionState { |
| PState_None = 0; |
| PState_Normal = 1; |
| PState_Splitting = 2; |
| PState_Offline = 3; |
| } |
| ``` |
| |
| #### Shard |
| |
| Represents a replica of a partition. |
| |
| ```protobuf |
| message Shard { |
| uint64 store_id = 1; |
| ShardRole role = 2; |
| } |
| |
| enum ShardRole { |
| None = 0; |
| Leader = 1; |
| Follower = 2; |
| Learner = 3; |
| } |
| ``` |
| |
| #### Store |
| |
| Represents a Store node in the cluster. |
| |
| ```protobuf |
| message Store { |
| uint64 id = 1; |
| string address = 2; // gRPC address (host:port) |
| string raft_address = 3; // Raft address for data replication |
| StoreState state = 4; |
| map<string, string> labels = 5; // Topology labels (rack, zone, region) |
| StoreStats stats = 6; |
| int64 last_heartbeat = 7; // Unix timestamp |
| uint64 version = 8; |
| } |
| |
| enum StoreState { |
| Unknown = 0; |
| Up = 1; // Store is online and healthy |
| Offline = 2; // Store is temporarily offline |
| Tombstone = 3; // Store is permanently removed |
| Exiting = 4; // Store is in the process of shutting down |
| } |
| |
| message StoreStats { |
| uint64 capacity = 1; // Total disk capacity (bytes) |
| uint64 available = 2; // Available disk space (bytes) |
| uint32 partition_count = 3; // Number of partitions on this store |
| uint32 leader_count = 4; // Number of partitions where this store is leader |
| } |
| ``` |
| |
| #### Graph |
| |
| Represents a graph in the cluster. |
| |
| ```protobuf |
| message Graph { |
| string graph_name = 1; |
| uint32 partition_count = 2; |
| GraphState state = 3; |
| } |
| |
| enum GraphState { |
| Graph_Normal = 0; |
| Graph_Deleting = 1; |
| } |
| ``` |
| |
| ## Core gRPC APIs |
| |
| ### 1. PD Service (PDGrpc) |
| |
| Main service for cluster management. |
| |
| #### GetMembers |
| |
| Retrieve all PD members in the cluster. |
| |
| **Request**: |
| ```protobuf |
| message GetMembersRequest {} |
| ``` |
| |
| **Response**: |
| ```protobuf |
| message GetMembersResponse { |
| ResponseHeader header = 1; |
| repeated Member members = 2; |
| Member leader = 3; |
| } |
| |
| message Member { |
| string cluster_id = 1; |
| string member_id = 2; |
| string grpc_url = 3; // gRPC endpoint |
| string raft_url = 4; // Raft endpoint |
| MemberState state = 5; |
| } |
| ``` |
| |
| **Java Example**: |
| ```java |
| import org.apache.hugegraph.pd.grpc.PDGrpc; |
| import org.apache.hugegraph.pd.grpc.Pdpb; |
| import io.grpc.ManagedChannel; |
| import io.grpc.ManagedChannelBuilder; |
| |
| // Create gRPC channel |
| ManagedChannel channel = ManagedChannelBuilder |
| .forAddress("localhost", 8686) |
| .usePlaintext() |
| .build(); |
| |
| // Create blocking stub |
| PDGrpc.PDBlockingStub stub = PDGrpc.newBlockingStub(channel); |
| |
| // Get PD members |
| Pdpb.GetMembersRequest request = Pdpb.GetMembersRequest.newBuilder().build(); |
| Pdpb.GetMembersResponse response = stub.getMembers(request); |
| |
| System.out.println("Leader: " + response.getLeader().getGrpcUrl()); |
| for (Pdpb.Member member : response.getMembersList()) { |
| System.out.println("Member: " + member.getGrpcUrl() + " State: " + member.getState()); |
| } |
| |
| // Clean up |
| channel.shutdown(); |
| ``` |
| |
| #### RegisterStore |
| |
| Register a new Store node with PD. |
| |
| **Request**: |
| ```protobuf |
| message RegisterStoreRequest { |
| RequestHeader header = 1; |
| Store store = 2; |
| } |
| ``` |
| |
| **Response**: |
| ```protobuf |
| message RegisterStoreResponse { |
| ResponseHeader header = 1; |
| uint64 store_id = 2; // Assigned store ID |
| } |
| ``` |
| |
| **Java Example**: |
| ```java |
| import org.apache.hugegraph.pd.grpc.Metapb; |
| |
| // Build store information |
| Metapb.Store store = Metapb.Store.newBuilder() |
| .setAddress("192.168.1.100:8500") |
| .setRaftAddress("192.168.1.100:8501") |
| .setState(Metapb.StoreState.Up) |
| .putLabels("zone", "zone-1") |
| .putLabels("rack", "rack-a") |
| .build(); |
| |
| // Register store |
| Pdpb.RegisterStoreRequest request = Pdpb.RegisterStoreRequest.newBuilder() |
| .setStore(store) |
| .build(); |
| |
| Pdpb.RegisterStoreResponse response = stub.registerStore(request); |
| long storeId = response.getStoreId(); |
| System.out.println("Registered store with ID: " + storeId); |
| ``` |
| |
| #### GetStoreInfo |
| |
| Retrieve Store node information. |
| |
| **Request**: |
| ```protobuf |
| message GetStoreInfoRequest { |
| RequestHeader header = 1; |
| uint64 store_id = 2; |
| } |
| ``` |
| |
| **Response**: |
| ```protobuf |
| message GetStoreInfoResponse { |
| ResponseHeader header = 1; |
| Store store = 2; |
| } |
| ``` |
| |
| **Java Example**: |
| ```java |
| Pdpb.GetStoreInfoRequest request = Pdpb.GetStoreInfoRequest.newBuilder() |
| .setStoreId(storeId) |
| .build(); |
| |
| Pdpb.GetStoreInfoResponse response = stub.getStoreInfo(request); |
| Metapb.Store store = response.getStore(); |
| |
| System.out.println("Store " + store.getId() + " at " + store.getAddress()); |
| System.out.println("State: " + store.getState()); |
| System.out.println("Partitions: " + store.getStats().getPartitionCount()); |
| System.out.println("Capacity: " + store.getStats().getCapacity() / (1024*1024*1024) + " GB"); |
| ``` |
| |
| #### GetPartition |
| |
| Retrieve partition information by partition code. |
| |
| **Request**: |
| ```protobuf |
| message GetPartitionRequest { |
| RequestHeader header = 1; |
| string graph_name = 2; |
| uint64 partition_key = 3; // Hash code of the data key |
| } |
| ``` |
| |
| **Response**: |
| ```protobuf |
| message GetPartitionResponse { |
| ResponseHeader header = 1; |
| Partition partition = 2; |
| Shard leader = 3; // Current leader shard |
| } |
| ``` |
| |
| **Java Example**: |
| ```java |
| String graphName = "social_network"; |
| long partitionKey = 12345L; // Hash of vertex/edge key |
| |
| Pdpb.GetPartitionRequest request = Pdpb.GetPartitionRequest.newBuilder() |
| .setGraphName(graphName) |
| .setPartitionKey(partitionKey) |
| .build(); |
| |
| Pdpb.GetPartitionResponse response = stub.getPartition(request); |
| Metapb.Partition partition = response.getPartition(); |
| Metapb.Shard leader = response.getLeader(); |
| |
| System.out.println("Partition " + partition.getId() + " range: [" + |
| partition.getStartKey() + ", " + partition.getEndKey() + ")"); |
| System.out.println("Leader store: " + leader.getStoreId()); |
| System.out.println("Replicas: " + partition.getShardsCount()); |
| ``` |
| |
| #### GetPartitionByCode |
| |
| Retrieve partition by exact partition code (optimized for routing). |
| |
| **Request**: |
| ```protobuf |
| message GetPartitionByCodeRequest { |
| RequestHeader header = 1; |
| string graph_name = 2; |
| uint64 partition_id = 3; |
| } |
| ``` |
| |
| **Response**: |
| ```protobuf |
| message GetPartitionByCodeResponse { |
| ResponseHeader header = 1; |
| Partition partition = 2; |
| } |
| ``` |
| |
| **Java Example**: |
| ```java |
| Pdpb.GetPartitionByCodeRequest request = Pdpb.GetPartitionByCodeRequest.newBuilder() |
| .setGraphName("social_network") |
| .setPartitionId(5) |
| .build(); |
| |
| Pdpb.GetPartitionByCodeResponse response = stub.getPartitionByCode(request); |
| Metapb.Partition partition = response.getPartition(); |
| |
| // Find leader shard |
| Metapb.Shard leader = partition.getShardsList().stream() |
| .filter(s -> s.getRole() == Metapb.ShardRole.Leader) |
| .findFirst() |
| .orElse(null); |
| |
| if (leader != null) { |
| System.out.println("Route query to store: " + leader.getStoreId()); |
| } |
| ``` |
| |
| ### 2. KV Service (KvServiceGrpc) |
| |
| Distributed key-value operations for metadata storage. |
| |
| #### Put |
| |
| Store a key-value pair. |
| |
| **Request**: |
| ```protobuf |
| message PutRequest { |
| string key = 1; |
| bytes value = 2; |
| int64 ttl = 3; // Time-to-live in seconds (0 = no expiration) |
| } |
| ``` |
| |
| **Response**: |
| ```protobuf |
| message PutResponse { |
| ResponseHeader header = 1; |
| } |
| ``` |
| |
| **Java Example**: |
| ```java |
| import org.apache.hugegraph.pd.grpc.kv.KvServiceGrpc; |
| import org.apache.hugegraph.pd.grpc.kv.Kv; |
| |
| KvServiceGrpc.KvServiceBlockingStub kvStub = KvServiceGrpc.newBlockingStub(channel); |
| |
| // Store configuration |
| String key = "config/max_retry_count"; |
| String value = "5"; |
| |
| Kv.PutRequest request = Kv.PutRequest.newBuilder() |
| .setKey(key) |
| .setValue(com.google.protobuf.ByteString.copyFromUtf8(value)) |
| .setTtl(0) // No expiration |
| .build(); |
| |
| Kv.PutResponse response = kvStub.put(request); |
| System.out.println("Stored: " + key); |
| ``` |
| |
| #### Get |
| |
| Retrieve a value by key. |
| |
| **Request**: |
| ```protobuf |
| message GetRequest { |
| string key = 1; |
| } |
| ``` |
| |
| **Response**: |
| ```protobuf |
| message GetResponse { |
| ResponseHeader header = 1; |
| bytes value = 2; |
| } |
| ``` |
| |
| **Java Example**: |
| ```java |
| Kv.GetRequest request = Kv.GetRequest.newBuilder() |
| .setKey("config/max_retry_count") |
| .build(); |
| |
| Kv.GetResponse response = kvStub.get(request); |
| String value = response.getValue().toStringUtf8(); |
| System.out.println("Retrieved value: " + value); |
| ``` |
| |
| #### Scan |
| |
| Range scan for keys matching a prefix. |
| |
| **Request**: |
| ```protobuf |
| message ScanRequest { |
| string start_key = 1; |
| string end_key = 2; |
| int32 limit = 3; // Max number of results |
| } |
| ``` |
| |
| **Response**: |
| ```protobuf |
| message ScanResponse { |
| ResponseHeader header = 1; |
| repeated KvPair kvs = 2; |
| } |
| |
| message KvPair { |
| string key = 1; |
| bytes value = 2; |
| } |
| ``` |
| |
| **Java Example**: |
| ```java |
| // Scan all configuration keys |
| Kv.ScanRequest request = Kv.ScanRequest.newBuilder() |
| .setStartKey("config/") |
| .setEndKey("config/\uffff") // End of prefix range |
| .setLimit(100) |
| .build(); |
| |
| Kv.ScanResponse response = kvStub.scan(request); |
| for (Kv.KvPair kv : response.getKvsList()) { |
| System.out.println(kv.getKey() + " = " + kv.getValue().toStringUtf8()); |
| } |
| ``` |
| |
| ### 3. Pulse Service (HgPdPulseGrpc) |
| |
| Heartbeat and health monitoring for Store nodes. |
| |
| #### Pulse (Streaming) |
| |
| Bidirectional streaming for continuous heartbeat. |
| |
| **Request Stream**: |
| ```protobuf |
| message PulseRequest { |
| PulseType pulse_type = 1; |
| oneof notice { |
| PulseCreatePartition create_partition = 2; |
| PulseTransferLeader transfer_leader = 3; |
| PulseMovePartition move_partition = 4; |
| PulseDeletePartition delete_partition = 5; |
| } |
| } |
| |
| enum PulseType { |
| PULSE_TYPE_UNKNOWN = 0; |
| PULSE_TYPE_STORE_HEARTBEAT = 1; |
| PULSE_TYPE_PARTITION_HEARTBEAT = 2; |
| } |
| ``` |
| |
| **Response Stream**: |
| ```protobuf |
| message PulseResponse { |
| PulseType pulse_type = 1; |
| oneof notice { |
| PulseCreatePartition create_partition = 2; |
| PulseTransferLeader transfer_leader = 3; |
| PulseMovePartition move_partition = 4; |
| PulseDeletePartition delete_partition = 5; |
| } |
| } |
| ``` |
| |
| **Java Example**: |
| ```java |
| import org.apache.hugegraph.pd.grpc.pulse.HgPdPulseGrpc; |
| import org.apache.hugegraph.pd.grpc.pulse.HgPdPulse; |
| import io.grpc.stub.StreamObserver; |
| |
| HgPdPulseGrpc.HgPdPulseStub asyncStub = HgPdPulseGrpc.newStub(channel); |
| |
| // Response handler |
| StreamObserver<HgPdPulse.PulseResponse> responseObserver = new StreamObserver<>() { |
| @Override |
| public void onNext(HgPdPulse.PulseResponse response) { |
| System.out.println("Received instruction: " + response.getPulseType()); |
| // Handle instructions from PD (partition transfer, split, etc.) |
| } |
| |
| @Override |
| public void onError(Throwable t) { |
| System.err.println("Pulse stream error: " + t.getMessage()); |
| } |
| |
| @Override |
| public void onCompleted() { |
| System.out.println("Pulse stream completed"); |
| } |
| }; |
| |
| // Create bidirectional stream |
| StreamObserver<HgPdPulse.PulseRequest> requestObserver = asyncStub.pulse(responseObserver); |
| |
| // Send periodic heartbeat |
| ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); |
| scheduler.scheduleAtFixedRate(() -> { |
| HgPdPulse.PulseRequest heartbeat = HgPdPulse.PulseRequest.newBuilder() |
| .setPulseType(HgPdPulse.PulseType.PULSE_TYPE_STORE_HEARTBEAT) |
| .build(); |
| |
| requestObserver.onNext(heartbeat); |
| }, 0, 10, TimeUnit.SECONDS); |
| ``` |
| |
| ### 4. Watch Service (HgPdWatchGrpc) |
| |
| Watch for partition and store change notifications. |
| |
| #### WatchPartition |
| |
| Watch for partition changes in a graph. |
| |
| **Request**: |
| ```protobuf |
| message WatchPartitionRequest { |
| RequestHeader header = 1; |
| string graph_name = 2; |
| WatchType watch_type = 3; |
| } |
| |
| enum WatchType { |
| WATCH_TYPE_PARTITION_CHANGE = 0; |
| WATCH_TYPE_STORE_CHANGE = 1; |
| } |
| ``` |
| |
| **Response Stream**: |
| ```protobuf |
| message WatchPartitionResponse { |
| ResponseHeader header = 1; |
| WatchChangeType change_type = 2; |
| Partition partition = 3; |
| } |
| |
| enum WatchChangeType { |
| WATCH_CHANGE_TYPE_ADD = 0; |
| WATCH_CHANGE_TYPE_DEL = 1; |
| WATCH_CHANGE_TYPE_ALTER = 2; |
| } |
| ``` |
| |
| **Java Example**: |
| ```java |
| import org.apache.hugegraph.pd.grpc.watch.HgPdWatchGrpc; |
| import org.apache.hugegraph.pd.grpc.watch.HgPdWatch; |
| |
| HgPdWatchGrpc.HgPdWatchStub watchStub = HgPdWatchGrpc.newStub(channel); |
| |
| // Watch partition changes |
| HgPdWatch.WatchPartitionRequest request = HgPdWatch.WatchPartitionRequest.newBuilder() |
| .setGraphName("social_network") |
| .setWatchType(HgPdWatch.WatchType.WATCH_TYPE_PARTITION_CHANGE) |
| .build(); |
| |
| StreamObserver<HgPdWatch.WatchPartitionResponse> responseObserver = new StreamObserver<>() { |
| @Override |
| public void onNext(HgPdWatch.WatchPartitionResponse response) { |
| WatchChangeType changeType = response.getChangeType(); |
| Metapb.Partition partition = response.getPartition(); |
| |
| switch (changeType) { |
| case WATCH_CHANGE_TYPE_ADD: |
| System.out.println("Partition added: " + partition.getId()); |
| break; |
| case WATCH_CHANGE_TYPE_DEL: |
| System.out.println("Partition deleted: " + partition.getId()); |
| break; |
| case WATCH_CHANGE_TYPE_ALTER: |
| System.out.println("Partition changed: " + partition.getId()); |
| // Refresh local cache |
| break; |
| } |
| } |
| |
| @Override |
| public void onError(Throwable t) { |
| System.err.println("Watch error: " + t.getMessage()); |
| } |
| |
| @Override |
| public void onCompleted() { |
| System.out.println("Watch completed"); |
| } |
| }; |
| |
| watchStub.watchPartition(request, responseObserver); |
| ``` |
| |
| ## Java Client Library |
| |
| HugeGraph PD provides a high-level Java client library (`hg-pd-client`) that simplifies interaction with PD. |
| |
| ### PDClient |
| |
| Main client class for PD operations. |
| |
| **Initialization**: |
| ```java |
| import org.apache.hugegraph.pd.client.PDClient; |
| import org.apache.hugegraph.pd.client.PDConfig; |
| |
| // Configure PD client |
| PDConfig config = PDConfig.builder() |
| .pdServers("192.168.1.10:8686,192.168.1.11:8686,192.168.1.12:8686") |
| .connectTimeout(5000) // 5 seconds |
| .requestTimeout(10000) // 10 seconds |
| .enableCache(true) // Enable partition cache |
| .build(); |
| |
| // Create client |
| PDClient client = new PDClient(config); |
| |
| // Use client... |
| |
| // Clean up |
| client.close(); |
| ``` |
| |
| ### Partition Operations |
| |
| ```java |
| import org.apache.hugegraph.pd.common.PartitionEngine; |
| |
| // Get partition by key |
| String graphName = "social_network"; |
| long vertexId = 12345L; |
| long partitionKey = PartitionEngine.calcHashcode(vertexId); |
| |
| Metapb.Partition partition = client.getPartitionByKey(graphName, partitionKey); |
| System.out.println("Partition ID: " + partition.getId()); |
| |
| // Get all partitions for a graph |
| List<Metapb.Partition> partitions = client.getPartitionsByGraphName(graphName); |
| System.out.println("Total partitions: " + partitions.size()); |
| |
| // Get partition leader |
| Metapb.Shard leader = client.getPartitionLeader(graphName, partition.getId()); |
| Metapb.Store leaderStore = client.getStore(leader.getStoreId()); |
| System.out.println("Leader at: " + leaderStore.getAddress()); |
| ``` |
| |
| ### Store Operations |
| |
| ```java |
| // Get all stores |
| List<Metapb.Store> stores = client.getStores(); |
| for (Metapb.Store store : stores) { |
| System.out.println("Store " + store.getId() + ": " + store.getAddress() + |
| " (" + store.getState() + ")"); |
| } |
| |
| // Get active stores |
| List<Metapb.Store> activeStores = client.getActiveStores(); |
| System.out.println("Active stores: " + activeStores.size()); |
| |
| // Get stores by graph |
| List<Metapb.Store> graphStores = client.getStoresByGraphName(graphName); |
| ``` |
| |
| ### Watch Operations |
| |
| ```java |
| import org.apache.hugegraph.pd.client.PDWatch; |
| |
| // Create watch listener |
| PDWatch.Listener<Metapb.Partition> listener = new PDWatch.Listener<>() { |
| @Override |
| public void onNext(PDWatch.WatchEvent<Metapb.Partition> event) { |
| System.out.println("Partition " + event.getTarget().getId() + |
| " " + event.getType()); |
| } |
| |
| @Override |
| public void onError(Throwable error) { |
| System.err.println("Watch error: " + error.getMessage()); |
| } |
| }; |
| |
| // Watch partition changes |
| PDWatch watch = client.watchPartition(graphName, listener); |
| |
| // Stop watching |
| watch.close(); |
| ``` |
| |
| ### KV Operations |
| |
| ```java |
| // Put key-value |
| client.put("config/setting1", "value1".getBytes()); |
| |
| // Get value |
| byte[] value = client.get("config/setting1"); |
| System.out.println("Value: " + new String(value)); |
| |
| // Delete key |
| client.delete("config/setting1"); |
| |
| // Scan with prefix |
| Map<String, byte[]> results = client.scan("config/", "config/\uffff", 100); |
| for (Map.Entry<String, byte[]> entry : results.entrySet()) { |
| System.out.println(entry.getKey() + " = " + new String(entry.getValue())); |
| } |
| ``` |
| |
| ## REST API |
| |
| PD exposes a REST API for management and monitoring (default port: 8620). |
| |
| ### Health Check |
| |
| ```bash |
| curl http://localhost:8620/actuator/health |
| ``` |
| |
| **Response**: |
| ```json |
| { |
| "status": "UP", |
| "groups": ["liveness", "readiness"] |
| } |
| ``` |
| |
| ### Metrics |
| |
| ```bash |
| curl http://localhost:8620/actuator/metrics |
| ``` |
| |
| **Response** (Prometheus format): |
| ``` |
| # HELP pd_raft_state Raft state (0=Follower, 1=Candidate, 2=Leader) |
| # TYPE pd_raft_state gauge |
| pd_raft_state 2.0 |
| |
| # HELP pd_store_count Number of stores |
| # TYPE pd_store_count gauge |
| pd_store_count{state="Up"} 3.0 |
| pd_store_count{state="Offline"} 0.0 |
| |
| # HELP pd_partition_count Number of partitions |
| # TYPE pd_partition_count gauge |
| pd_partition_count 36.0 |
| ``` |
| |
| ### Partition API |
| |
| #### List Partitions |
| |
| ```bash |
| curl http://localhost:8620/v1/partitions?graph_name=social_network |
| ``` |
| |
| **Response**: |
| ```json |
| { |
| "partitions": [ |
| { |
| "id": 1, |
| "graph_name": "social_network", |
| "start_key": 0, |
| "end_key": 1000, |
| "shards": [ |
| {"store_id": 1, "role": "Leader"}, |
| {"store_id": 2, "role": "Follower"}, |
| {"store_id": 3, "role": "Follower"} |
| ], |
| "state": "PState_Normal" |
| } |
| ] |
| } |
| ``` |
| |
| ### Store API |
| |
| #### List Stores |
| |
| ```bash |
| curl http://localhost:8620/v1/stores |
| ``` |
| |
| **Response**: |
| ```json |
| { |
| "stores": [ |
| { |
| "id": 1, |
| "address": "192.168.1.100:8500", |
| "raft_address": "192.168.1.100:8501", |
| "state": "Up", |
| "labels": { |
| "zone": "zone-1", |
| "rack": "rack-a" |
| }, |
| "stats": { |
| "capacity": 107374182400, |
| "available": 53687091200, |
| "partition_count": 12, |
| "leader_count": 8 |
| }, |
| "last_heartbeat": 1620000000 |
| } |
| ] |
| } |
| ``` |
| |
| ## Error Handling |
| |
| ### gRPC Status Codes |
| |
| PD uses standard gRPC status codes: |
| |
| | Code | Name | Description | |
| |------|------|-------------| |
| | 0 | OK | Success | |
| | 1 | CANCELLED | Operation cancelled | |
| | 2 | UNKNOWN | Unknown error | |
| | 3 | INVALID_ARGUMENT | Invalid request parameters | |
| | 4 | DEADLINE_EXCEEDED | Timeout | |
| | 5 | NOT_FOUND | Resource not found (store, partition, etc.) | |
| | 6 | ALREADY_EXISTS | Resource already exists | |
| | 7 | PERMISSION_DENIED | Insufficient permissions | |
| | 8 | RESOURCE_EXHAUSTED | Quota exceeded | |
| | 14 | UNAVAILABLE | Service unavailable (not leader, Raft not ready) | |
| |
| ### Response Header |
| |
| All responses include a `ResponseHeader` with error information: |
| |
| ```protobuf |
| message ResponseHeader { |
| uint64 cluster_id = 1; |
| Error error = 2; |
| } |
| |
| message Error { |
| ErrorType type = 1; |
| string message = 2; |
| } |
| |
| enum ErrorType { |
| OK = 0; |
| NOT_LEADER = 1; // Current node is not Raft leader |
| STORE_NOT_FOUND = 2; |
| PARTITION_NOT_FOUND = 3; |
| STORE_TOMBSTONE = 4; // Store is permanently removed |
| RAFT_ERROR = 5; |
| } |
| ``` |
| |
| **Error Handling Example**: |
| ```java |
| Pdpb.GetStoreInfoResponse response = stub.getStoreInfo(request); |
| |
| if (response.getHeader().hasError()) { |
| Error error = response.getHeader().getError(); |
| |
| if (error.getType() == ErrorType.NOT_LEADER) { |
| // Retry with leader node |
| String leaderUrl = getLeaderFromMembers(); |
| // Reconnect and retry... |
| } else { |
| System.err.println("Error: " + error.getMessage()); |
| } |
| } else { |
| Metapb.Store store = response.getStore(); |
| // Process store... |
| } |
| ``` |
| |
| ## Best Practices |
| |
| ### 1. Connection Management |
| |
| - **Reuse gRPC channels**: Creating channels is expensive |
| - **Connection pooling**: Use multiple channels for high throughput |
| - **Automatic reconnection**: Handle disconnections gracefully |
| |
| ```java |
| // Good: Reuse channel |
| ManagedChannel channel = ManagedChannelBuilder |
| .forAddress("pd-host", 8686) |
| .usePlaintext() |
| .keepAliveTime(30, TimeUnit.SECONDS) |
| .idleTimeout(60, TimeUnit.SECONDS) |
| .build(); |
| |
| // Bad: Create new channel per request |
| // ManagedChannel channel = ... |
| // channel.shutdown() // Don't do this after every request |
| ``` |
| |
| ### 2. Leader Detection |
| |
| - Always check `ResponseHeader.error.type` for `NOT_LEADER` |
| - Use `GetMembers()` to find current leader |
| - Cache leader information but refresh on errors |
| |
| ### 3. Partition Caching |
| |
| - Cache partition routing information locally |
| - Use `WatchPartition` to invalidate cache on changes |
| - Set reasonable cache TTL (e.g., 5 minutes) |
| |
| ### 4. Retry Strategy |
| |
| - Implement exponential backoff for retries |
| - Retry on transient errors (UNAVAILABLE, DEADLINE_EXCEEDED) |
| - Don't retry on permanent errors (NOT_FOUND, INVALID_ARGUMENT) |
| |
| ```java |
| int maxRetries = 3; |
| int retryDelay = 1000; // milliseconds |
| |
| for (int i = 0; i < maxRetries; i++) { |
| try { |
| response = stub.getPartition(request); |
| break; // Success |
| } catch (StatusRuntimeException e) { |
| if (e.getStatus().getCode() == Status.Code.UNAVAILABLE && i < maxRetries - 1) { |
| Thread.sleep(retryDelay * (1 << i)); // Exponential backoff |
| } else { |
| throw e; |
| } |
| } |
| } |
| ``` |
| |
| ### 5. Timeout Configuration |
| |
| - Set appropriate timeouts for all RPCs |
| - Use shorter timeouts for read operations |
| - Use longer timeouts for write operations |
| |
| ```java |
| PDGrpc.PDBlockingStub stub = PDGrpc.newBlockingStub(channel) |
| .withDeadlineAfter(5, TimeUnit.SECONDS); |
| ``` |
| |
| ## Summary |
| |
| HugeGraph PD provides comprehensive gRPC APIs for: |
| - Cluster membership and leadership management |
| - Store registration and monitoring |
| - Partition routing and querying |
| - Distributed key-value operations |
| - Real-time change notifications |
| |
| Use the high-level `PDClient` library for simplified integration, or use raw gRPC stubs for fine-grained control. |
| |
| For architecture details, see [Architecture Documentation](architecture.md). |
| |
| For configuration, see [Configuration Guide](configuration.md). |