### Start Local Docs.rs Server Source: https://github.com/akiradeveloper/lolraft/blob/master/book/src/development.md Start a local server to preview documentation generated in the docs.rs format. ```bash rake doc ``` -------------------------------- ### Start Local mdBook Server Source: https://github.com/akiradeveloper/lolraft/blob/master/book/src/development.md Start a local server to preview the project's book documentation built with mdBook. ```bash rake book ``` -------------------------------- ### Run Sorock Benchmark Source: https://github.com/akiradeveloper/lolraft/blob/master/testing/sorock-bench/README.md Example command to run the sorock benchmark with specific configurations for nodes, shards, duration, I/O operations, and console logging. ```bash benchmark -n 3 -p 10 -t 10s -w 10 -r 90 --io-size=1024 --enable-console ``` -------------------------------- ### Implement RaftApp Trait for a Key-Value Store Source: https://context7.com/akiradeveloper/lolraft/llms.txt This example shows a minimal in-memory key-value store implementing the `RaftApp` trait. It handles read-only queries, write commands, and snapshot installation/saving. Ensure your implementation correctly handles state mutation and persistence. ```rust use sorock::process::{RaftApp, LogIndex, SnapshotStream}; use anyhow::Result; use bytes::Bytes; /// Minimal in-memory key-value store implementing RaftApp. #[derive(Default)] struct KvApp { store: tokio::sync::RwLock>, } #[async_trait::async_trait] impl RaftApp for KvApp { /// Read-only query — must NOT mutate state. async fn process_read(&self, request: &[u8]) -> Result { let key = std::str::from_utf8(request)?; let val = self.store.read().await .get(key) .cloned() .unwrap_or_default(); Ok(Bytes::from(val)) } /// Write command — applied in log order, `entry_index` is the Raft log index. async fn process_write(&self, request: &[u8], entry_index: LogIndex) -> Result { // request is caller-defined bytes; here "key=value" let kv = std::str::from_utf8(request)?; if let Some((k, v)) = kv.split_once('=') { self.store.write().await.insert(k.to_string(), v.to_string()); } Ok(Bytes::new()) } /// Replace state with snapshot at `snapshot_index` (previously saved via save_snapshot). async fn install_snapshot(&self, snapshot_index: LogIndex) -> Result<()> { // Load snapshot file from disk and deserialize into self.store Ok(()) } /// Persist an incoming snapshot stream from the leader. async fn save_snapshot(&self, st: SnapshotStream, snapshot_index: LogIndex) -> Result<()> { // Write stream bytes to a local snapshot file keyed by snapshot_index Ok(()) } /// Stream a previously saved snapshot to a lagging follower. async fn open_snapshot(&self, snapshot_index: LogIndex) -> Result> { // Return None if snapshot doesn't exist locally Ok(None) } /// GC: delete snapshots with index < i. async fn delete_snapshots_before(&self, i: LogIndex) -> Result<()> { Ok(()) } /// Report the highest snapshot index currently stored locally. async fn get_latest_snapshot(&self) -> Result { Ok(1) // 1 = initial implicit snapshot } } ``` -------------------------------- ### Remap Shard Configurations with Sorock-CLI Source: https://github.com/akiradeveloper/lolraft/blob/master/sorock-cli/README.md Change shard configurations by piping new configurations to the remap command. This example sets node1, node2, and node4 as the cluster for shard 14, with node2 as the leader. Supports multiline input for multiple shards. ```bash echo "14 [1] [2]* [4]" | sorock-cli remap --node-list http://node1:50000 http://node2:50000 http://node3:50000 http://node4:50000 ``` -------------------------------- ### Get Shard Mapping Source: https://context7.com/akiradeveloper/lolraft/llms.txt Reads the shard list hosted by a specific node. This is part of managing the per-node shard routing table. ```bash grpcurl -plaintext node1:50051 sorock.Raft/GetShardMapping ``` -------------------------------- ### Get Shard Mapping Source: https://context7.com/akiradeveloper/lolraft/llms.txt Reads the shard routing table hosted by a specific node, indicating which shards that node is responsible for. ```APIDOC ## Get Shard Mapping ### Description Reads the shard routing table hosted by a specific node, indicating which shards that node is responsible for. ### Method `grpcurl` (gRPC client) ### Endpoint `sorock.Raft/GetShardMapping` ### Request Example ```bash grpcurl -plaintext node1:50051 sorock.Raft/GetShardMapping ``` ### Response #### Success Response (200) - **server_id** (string) - The address of the node. - **shard_indices** (array[int]) - A list of shard IDs hosted by this node. #### Response Example ```json { "server_id": "http://node1:50051", "shard_indices": [0, 1, 2] } ``` ``` -------------------------------- ### Send TimeoutNow RPC for Leadership Transfer Source: https://context7.com/akiradeveloper/lolraft/llms.txt Instructs a target Raft process to immediately start a new election, bypassing the normal election timeout. This is used for leadership transfer during rebalancing to avoid downtime. ```bash # Transfer leadership of shard 0 from node1 to another node # (send TimeoutNow to the desired new leader) grpcurl -plaintext \ -d '{"shard_id": 0}' \ node2:50051 sorock.Raft/SendTimeoutNow ``` -------------------------------- ### Send TimeoutNow RPC for Leadership Transfer Source: https://context7.com/akiradeveloper/lolraft/llms.txt Instructs a Raft process to immediately start a new election, bypassing the normal election timeout. This is used to transfer leadership away from a node before removing it, minimizing downtime. ```APIDOC ## Send TimeoutNow RPC for Leadership Transfer ### Description Instructs a Raft process to immediately start a new election, bypassing the normal election timeout. This is used to transfer leadership away from a node before removing it, minimizing downtime. ### Method `grpcurl` (gRPC client) ### Endpoint `sorock.Raft/SendTimeoutNow` ### Parameters #### Request Body - **shard_id** (int) - Required - The ID of the shard for which to initiate a leadership transfer. ### Request Example ```bash # Transfer leadership of shard 0 from node1 to another node (send TimeoutNow to the desired new leader) grpcurl -plaintext \ -d '{"shard_id": 0}' \ node2:50051 sorock.Raft/SendTimeoutNow ``` ``` -------------------------------- ### Get Raft Cluster Membership Source: https://context7.com/akiradeveloper/lolraft/llms.txt Retrieves the current membership map (server address to voter status) and the leader address for a given shard. Non-leader nodes automatically proxy this request to the leader. ```APIDOC ## Get Raft Cluster Membership ### Description Retrieves the current membership map (server address to voter status) and the leader address for a given shard. Non-leader nodes automatically proxy this request to the leader. ### Method `grpcurl` (gRPC client) ### Endpoint `sorock.Raft/GetMembership` ### Parameters #### Request Body - **shard_id** (int) - Required - The ID of the shard for which to get membership information. ### Request Example ```bash grpcurl -plaintext \ -d '{"shard_id": 0}' \ node1:50051 sorock.Raft/GetMembership ``` ### Response #### Success Response (200) - **members** (map[string]bool) - A map where keys are server addresses and values indicate if the server is a voter. - **leader_id** (string) - The address of the current leader for the shard. #### Response Example ```json { "members": { "http://node1:50051": true, "http://node2:50051": true, "http://node3:50051": true }, "leader_id": "http://node1:50051" } ``` ``` -------------------------------- ### Get Raft Cluster Membership Source: https://context7.com/akiradeveloper/lolraft/llms.txt Retrieves the current membership map (server ID to voter status) and the leader ID for a given shard. Non-leader nodes will proxy the request to the current leader. ```bash grpcurl -plaintext \ -d '{"shard_id": 0}' \ node1:50051 sorock.Raft/GetMembership ``` -------------------------------- ### Create and Manage RaftNode and RaftProcess Source: https://context7.com/akiradeveloper/lolraft/llms.txt Demonstrates initializing a RaftNode, attaching RaftProcesses for specific shards, and managing active shards. ```rust use sorock::node::RaftNode; use sorock::ServerAddress; // Create the node with its own gRPC address. let self_addr: ServerAddress = "http://127.0.0.1:50051".parse()?; let node = std::sync::Arc::new(RaftNode::new(self_addr)); // Attach a Raft process for shard 0. let io = node.get_io_capability(/* shard_id */ 0); let process = sorock::process::RaftProcess::new(KvApp::default(), &storage, io).await?; node.attach_process(0, process); // List all active shards. let shards: Vec = node.list_processes(); // => [0] // Detach when a shard is migrated away. node.detach_process(0); ``` -------------------------------- ### Initialize RaftProcess Source: https://github.com/akiradeveloper/lolraft/blob/master/book/src/raft-process.md Constructor for `RaftProcess`. Requires an implementation of `RaftApp`, a `RaftStorage` reference, and a `RaftIO` instance for network communication. ```rust impl RaftProcess { pub async fn new( app: impl RaftApp, storage: &RaftStorage, io: RaftIO, ) -> Result { ``` -------------------------------- ### Initialize RaftStorage with redb Backend Source: https://context7.com/akiradeveloper/lolraft/llms.txt This snippet demonstrates how to initialize `RaftStorage` using an in-memory backend for testing. For production, replace `InMemoryBackend` with `redb::Database::create("path")` to use persistent storage. ```rust use sorock::process::RaftStorage; // In-memory backend for tests; use redb::Database::create("path") for production. let mem = redb::backends::InMemoryBackend::new(); let redb = redb::Database::builder().create_with_backend(mem)?; let storage = RaftStorage::new(redb); // storage.get(shard_id) is called internally by RaftProcess::new — users only // construct RaftStorage and pass it to the node setup code. ``` -------------------------------- ### Build gRPC Service with service::raft::new Source: https://context7.com/akiradeveloper/lolraft/llms.txt Wraps a RaftNode in a Tonic RaftServer to expose the Raft gRPC service. Mount this in a Tonic router. ```rust use sorock::{node::RaftNode, service}; use tonic::transport::Server; use std::sync::Arc; #[tokio::main] async fn main() -> anyhow::Result<()> { let node = Arc::new(RaftNode::new("http://0.0.0.0:50051".parse()?)); // ... attach RaftProcess instances to node ... let raft_svc = service::raft::new(node.clone()); Server::builder() .add_service(raft_svc) .serve("0.0.0.0:50051".parse()?) .await?; Ok(()) } ``` -------------------------------- ### Run Raft-Level Benchmark Source: https://github.com/akiradeveloper/lolraft/blob/master/book/src/development.md Execute the Raft-level benchmark program in release mode for performance measurement. ```bash cargo run -p sorock-bench --release ``` -------------------------------- ### Connect to Monitor Cluster with Sorock-CLI Source: https://github.com/akiradeveloper/lolraft/blob/master/sorock-cli/README.md Use this command to connect to a specific node for visualizing the cluster and log progress. Ensure the node URL is correct. ```bash sorock-cli monitor connect http://node2:50000 ``` -------------------------------- ### Sorock Benchmark Pseudo-Code Source: https://github.com/akiradeveloper/lolraft/blob/master/testing/sorock-bench/README.md Illustrates the core logic of the sorock benchmark, showing cluster creation, iterative I/O operations, and parallel execution. ```python cluster = create_cluster(num_nodes, num_shards) while elapsed < du: io_batch = [] for shard_id in [0, num_shards) io_batch <- num_batch_writes * cluster[0].shard[shard_id].write(io_size) io_batch <- num_batch_reads * cluster[0].shard[shard_id].read() par_execute(io_batch) ``` -------------------------------- ### Connect to sorock-cli Monitor Source: https://context7.com/akiradeveloper/lolraft/llms.txt Opens a live terminal dashboard for monitoring cluster and log progress. Connects to the specified node's endpoint. ```bash # Open live monitor connecting to node2 sorock-cli monitor connect http://node2:50000 ``` -------------------------------- ### Sync Shard Mapping with Sorock-CLI Source: https://github.com/akiradeveloper/lolraft/blob/master/sorock-cli/README.md Use this command to synchronize shard mapping configurations among multiple nodes. Ensure all node URLs are correctly specified. ```bash sorock-cli sync http://node1:50000 http://node2:50000 http://node3:50000 http://node4:50000 ``` -------------------------------- ### sorock-bench Benchmark Tool Source: https://context7.com/akiradeveloper/lolraft/llms.txt Runs a Raft-level throughput benchmark by spinning up an in-process cluster and driving parallel reads and writes. ```APIDOC ## sorock-bench Benchmark Tool ### Description Runs a Raft-level throughput benchmark by spinning up an in-process cluster and driving parallel reads and writes across all shards for a configurable duration. ### Usage `cargo run -p sorock-bench --release -- [OPTIONS]` ### Options - **-n num-nodes** (int, default 1) - Number of nodes in the in-process cluster. - **-p num-shards** (int, default 1) - Number of shards per node. - **-t du** (duration, default 1s) - IO duration for the benchmark. - **-w n-batch-writes** (int, default 1) - Number of write operations per IO batch. - **-r n-batch-reads** (int, default 0) - Number of read operations per IO batch. - **--io-size** (int, default 1) - Write payload size in bytes. - **--compaction-cycle** (int, default 1) - Log compaction frequency. - **--enable-console** - Enables console output for the benchmark. ### Example ```bash # 3-node cluster, 10 shards, 10-second run, 10% writes / 90% reads, 1 KB payload cargo run -p sorock-bench --release -- \ -n 3 -p 10 -t 10s -w 10 -r 90 --io-size=1024 --enable-console ``` ``` -------------------------------- ### Multi-Raft Batched Write Flow Source: https://github.com/akiradeveloper/lolraft/blob/master/book/src/batched-write.md Illustrates the data flow for batched writes in Multi-Raft, showing how client requests are directed to shard tables, then to a shared queue, and finally processed as a single transaction against the database. ```mermaid graph LR CLI(Client) subgraph P1 T1(redb::Table) end subgraph P2 T2(redb::Table) end subgraph P3 T3(redb::Table) end subgraph Reaper Q(Queue) end DB[(redb::Database)] CLI -->|entry| T1 CLI --> T2 CLI --> T3 T1 -->|lazy entry| Q T2 --> Q T3 --> Q Q -->|transaction| DB ``` -------------------------------- ### Bind RaftIO to a Shard using RaftNode::get_io_capability Source: https://context7.com/akiradeveloper/lolraft/llms.txt Shows how to create RaftIO handles for specific shards, which are then used to initialize RaftProcess instances. ```rust use sorock::node::{RaftNode, RaftIO}; let node = std::sync::Arc::new(RaftNode::new("http://node1:50051".parse()?)); let storage = RaftStorage::new(redb::Database::builder() .create_with_backend(redb::backends::InMemoryBackend::new())?); // One RaftIO per shard — binds shard_id + local address + shared connection cache. let io_shard_0: RaftIO = node.get_io_capability(0); let io_shard_1: RaftIO = node.get_io_capability(1); let p0 = sorock::process::RaftProcess::new(KvApp::default(), &storage, io_shard_0).await?; let p1 = sorock::process::RaftProcess::new(KvApp::default(), &storage, io_shard_1).await?; node.attach_process(0, p0); node.attach_process(1, p1); ``` -------------------------------- ### Run Raft Benchmark with sorock-bench Source: https://context7.com/akiradeveloper/lolraft/llms.txt Executes a Raft-level throughput benchmark by spinning up an in-process cluster. Configure the number of nodes, shards, duration, write/read ratio, and payload size. ```bash # 3-node cluster, 10 shards, 10-second run, 10% writes / 90% reads, 1 KB payload cargo run -p sorock-bench --release -- \ -n 3 -p 10 -t 10s -w 10 -r 90 --io-size=1024 --enable-console ``` -------------------------------- ### Sync Shard Mapping with sorock-cli Source: https://context7.com/akiradeveloper/lolraft/llms.txt Propagates shard mapping information across all specified nodes in the cluster. Run this command after topology changes. ```bash # Sync shard mapping across all 4 nodes (run after topology changes) sorock-cli sync \ http://node1:50000 http://node2:50000 http://node3:50000 http://node4:50000 ``` -------------------------------- ### Run Unit Tests Source: https://github.com/akiradeveloper/lolraft/blob/master/book/src/development.md Execute unit tests with a single thread to ensure deterministic behavior. ```bash cargo test -- --test-threads=1 ``` -------------------------------- ### service::raft::new Source: https://context7.com/akiradeveloper/lolraft/llms.txt `service::raft::new` wraps a `RaftNode` in a Tonic `RaftServer` that implements the full `sorock.Raft` gRPC service. Mount it in a Tonic router to expose the cluster endpoint. ```APIDOC ## `service::raft::new` — Build the gRPC Service `service::raft::new` wraps a `RaftNode` in a Tonic `RaftServer` that implements the full `sorock.Raft` gRPC service. Mount it in a Tonic router to expose the cluster endpoint. ```rust use sorock::{node::RaftNode, service}; use tonic::transport::Server; use std::sync::Arc; #[tokio::main] async fn main() -> anyhow::Result<()> { let node = Arc::new(RaftNode::new("http://0.0.0.0:50051".parse()?)); // ... attach RaftProcess instances to node ... let raft_svc = service::raft::new(node.clone()); Server::builder() .add_service(raft_svc) .serve("0.0.0.0:50051".parse()?) .await?; Ok(()) } ``` ``` -------------------------------- ### Submit Replicated Write Command via Rust Client Source: https://context7.com/akiradeveloper/lolraft/llms.txt Rust client-side equivalent for the gRPC Write RPC using the generated tonic client. Ensure request_id is unique for idempotency. ```rust // Rust client-side equivalent using the generated tonic client use sorock::service::raft::client::RaftClient; let mut client = RaftClient::connect("http://127.0.0.1:50051").await?; let resp = client.write(sorock_proto::WriteRequest { shard_id: 0, message: b"key1=value1".to_vec().into(), request_id: "req-uuid-1234".to_string(), }).await?; ``` -------------------------------- ### Define AddServer and RemoveServer Requests Source: https://github.com/akiradeveloper/lolraft/blob/master/book/src/cluster-management.md These Protocol Buffer messages define the structure for adding or removing a Raft server from a cluster, specifying the shard and server IDs. ```proto message AddServerRequest { uint32 shard_id = 1; string server_id = 2; } message RemoveServerRequest { uint32 shard_id = 1; string server_id = 2; } ``` -------------------------------- ### sorock-cli monitor Source: https://context7.com/akiradeveloper/lolraft/llms.txt Opens a live terminal dashboard to monitor the status of the Sorock cluster and log progress. ```APIDOC ## sorock-cli monitor ### Description Opens a live terminal dashboard to monitor the status of the Sorock cluster and log progress. ### Usage `sorock-cli monitor connect [NODE_ADDRESS]` ### Parameters - **NODE_ADDRESS** (string) - The address of a node in the cluster to connect to. ### Example ```bash # Open live monitor connecting to node2 sorock-cli monitor connect http://node2:50000 ``` ``` -------------------------------- ### Query Data with gRPC Read RPC (Read Index Optimization) Source: https://context7.com/akiradeveloper/lolraft/llms.txt Submits a read-only query using the Read RPC. Utilizes the read_index optimization to achieve linearizable reads without log entries. ```bash grpcurl -plaintext \ -d '{ "shard_id": 0, "message": "a2V5MQ==" }' \ 127.0.0.1:50051 sorock.Raft/Read # Expected response: # { "message": "" } ``` -------------------------------- ### gRPC AddServer / RemoveServer RPCs Source: https://context7.com/akiradeveloper/lolraft/llms.txt These RPCs implement the *single server change* approach from the Raft thesis. Membership changes are replicated as log entries. The first `AddServer` call to an empty shard triggers **cluster bootstrapping**: the node forms a one-member cluster and immediately wins a self-election to become leader. ```APIDOC ## gRPC `AddServer` / `RemoveServer` RPCs — Cluster Membership Change These RPCs implement the *single server change* approach from the Raft thesis. Membership changes are replicated as log entries. The first `AddServer` call to an empty shard triggers **cluster bootstrapping**: the node forms a one-member cluster and immediately wins a self-election to become leader. ```bash # Bootstrap shard 0 on node1 (first AddServer to empty cluster) grpcurl -plaintext \ -d '{"shard_id": 0, "server_id": "http://node1:50051", "as_voter": true}' \ node1:50051 sorock.Raft/AddServer # Add node2 as a voter to shard 0 (send to any node in the cluster) grpcurl -plaintext \ -d '{"shard_id": 0, "server_id": "http://node2:50051", "as_voter": true}' \ node1:50051 sorock.Raft/AddServer ``` ``` -------------------------------- ### sorock-cli sync Source: https://context7.com/akiradeveloper/lolraft/llms.txt Synchronizes the shard mapping information across all nodes in the cluster. This command should be run after any topology changes. ```APIDOC ## sorock-cli sync ### Description Synchronizes the shard mapping information across all nodes in the cluster. This command should be run after any topology changes. ### Usage `sorock-cli sync [NODE_ADDRESSES...]` ### Parameters - **NODE_ADDRESSES** (string) - A list of addresses for all nodes in the cluster (e.g., `http://node1:50000`). ### Example ```bash # Sync shard mapping across all 4 nodes sorock-cli sync \ http://node1:50000 http://node2:50000 http://node3:50000 http://node4:50000 ``` ``` -------------------------------- ### Watch Raft Log Metrics Source: https://context7.com/akiradeveloper/lolraft/llms.txt A server-streaming RPC that emits LogMetrics once per second for a given shard. Useful for monitoring replication lag, snapshot advancement, and commit progress. ```bash grpcurl -plaintext \ -d '{"shard_id": 0}' \ node1:50051 sorock.Raft/WatchLogMetrics ``` -------------------------------- ### Submit Replicated Write Command via gRPC Write RPC Source: https://context7.com/akiradeveloper/lolraft/llms.txt Submits a write command for a shard. Use a unique request_id for exactly-once execution. The server redirects to the leader if necessary. ```bash # Using grpcurl against a running sorock node grpcurl -plaintext \ -d '{ "shard_id": 0, "message": "a2V5MT12YWx1ZTE=", "request_id": "req-uuid-1234" }' \ 127.0.0.1:50051 sorock.Raft/Write # Expected response: # { "message": "" } ``` -------------------------------- ### Cluster Membership Change via gRPC AddServer/RemoveServer RPCs Source: https://context7.com/akiradeveloper/lolraft/llms.txt Implements single server changes for cluster membership. Membership changes are replicated as log entries. The first AddServer call bootstraps the cluster. ```bash # Bootstrap shard 0 on node1 (first AddServer to empty cluster) grpcurl -plaintext \ -d '{"shard_id": 0, "server_id": "http://node1:50051", "as_voter": true}' \ node1:50051 sorock.Raft/AddServer # Add node2 as a voter to shard 0 (send to any node in the cluster) grpcurl -plaintext \ -d '{"shard_id": 0, "server_id": "http://node2:50051", "as_voter": true}' \ node1:50051 sorock.Raft/AddServer ``` -------------------------------- ### RaftNode::get_io_capability Source: https://context7.com/akiradeveloper/lolraft/llms.txt `get_io_capability` creates a `RaftIO` handle that encapsulates all network I/O for a specific shard on this node. It must be called before constructing `RaftProcess`, and the resulting `RaftIO` is passed into `RaftProcess::new`. ```APIDOC ## `RaftNode::get_io_capability` — Bind I/O to a Shard `get_io_capability` creates a `RaftIO` handle that encapsulates all network I/O for a specific shard on this node. It must be called before constructing `RaftProcess`, and the resulting `RaftIO` is passed into `RaftProcess::new`. ```rust use sorock::node::{RaftNode, RaftIO}; let node = std::sync::Arc::new(RaftNode::new("http://node1:50051".parse()?)); let storage = RaftStorage::new(redb::Database::builder() .create_with_backend(redb::backends::InMemoryBackend::new())?); // One RaftIO per shard — binds shard_id + local address + shared connection cache. let io_shard_0: RaftIO = node.get_io_capability(0); let io_shard_1: RaftIO = node.get_io_capability(1); let p0 = sorock::process::RaftProcess::new(KvApp::default(), &storage, io_shard_0).await?; let p1 = sorock::process::RaftProcess::new(KvApp::default(), &storage, io_shard_1).await?; node.attach_process(0, p0); node.attach_process(1, p1); ``` ``` -------------------------------- ### R/O Command Structure Source: https://github.com/akiradeveloper/lolraft/blob/master/book/src/client-interaction.md Defines the structure for sending a read-only command (query) to the Raft cluster. Setting `read_locally` to true allows the request to be processed by the local node without proxying to the leader. ```proto message ReadRequest { uint32 shard_id = 1; bytes message = 2; bool read_locally = 3; } ``` -------------------------------- ### R/W Command Structure Source: https://github.com/akiradeveloper/lolraft/blob/master/book/src/client-interaction.md Defines the structure for sending a read-write command to the Raft cluster. The `request_id` is crucial for idempotency to prevent duplicate command applications. ```proto message WriteRequest { uint32 shard_id = 1; bytes message = 2; string request_id = 3; } ``` -------------------------------- ### Watch Log Metrics Source: https://context7.com/akiradeveloper/lolraft/llms.txt A server-streaming RPC that emits `LogMetrics` once per second for a given shard. It is useful for monitoring replication lag, snapshot advancement, and commit progress. ```APIDOC ## Watch Log Metrics ### Description A server-streaming RPC that emits `LogMetrics` once per second for a given shard. It is useful for monitoring replication lag, snapshot advancement, and commit progress. ### Method `grpcurl` (gRPC client) ### Endpoint `sorock.Raft/WatchLogMetrics` ### Parameters #### Request Body - **shard_id** (int) - Required - The ID of the shard for which to watch log metrics. ### Request Example ```bash grpcurl -plaintext \ -d '{"shard_id": 0}' \ node1:50051 sorock.Raft/WatchLogMetrics ``` ### Response Streams `LogMetrics` objects, which may include: - **snapshot_index** (int) - The index of the last snapshot. - **app_index** (int) - The index of the last applied entry. - **commit_index** (int) - The index of the last committed entry. - **last_index** (int) - The index of the last entry in the log. ### Response Example ```json { "snapshot_index": 1000, "app_index": 1250, "commit_index": 1260, "last_index": 1260 } { "snapshot_index": 1000, "app_index": 1270, "commit_index": 1280, "last_index": 1280 } ``` ``` -------------------------------- ### gRPC Write RPC Source: https://context7.com/akiradeveloper/lolraft/llms.txt The `Write` RPC submits an application write command for a given shard. If the receiving node is not the leader, Sorock automatically redirects the request to the known leader. `request_id` must be unique per logical operation to guarantee exactly-once execution (idempotent retry semantics). ```APIDOC ## gRPC `Write` RPC — Submit a Replicated Write Command The `Write` RPC submits an application write command for a given shard. If the receiving node is not the leader, Sorock automatically redirects the request to the known leader. `request_id` must be unique per logical operation to guarantee exactly-once execution (idempotent retry semantics). ```bash # Using grpcurl against a running sorock node grpcurl -plaintext \ -d '{ "shard_id": 0, "message": "a2V5MT12YWx1ZTE=", "request_id": "req-uuid-1234" }' \ 127.0.0.1:50051 sorock.Raft/Write # Expected response: # { "message": "" } ``` ```rust // Rust client-side equivalent using the generated tonic client use sorock::service::raft::client::RaftClient; let mut client = RaftClient::connect("http://127.0.0.1:50051").await?; let resp = client.write(sorock_proto::WriteRequest { shard_id: 0, message: b"key1=value1".to_vec().into(), request_id: "req-uuid-1234".to_string(), }).await?; ``` ``` -------------------------------- ### sorock-cli remap Source: https://context7.com/akiradeveloper/lolraft/llms.txt Reconfigures the shard membership for a given shard. This command allows specifying which nodes should host a shard and designating a leader. ```APIDOC ## sorock-cli remap ### Description Reconfigures the shard membership for a given shard. This command allows specifying which nodes should host a shard and designating a leader. ### Usage `echo "[SHARD_ID] [VOTER_LIST]" | sorock-cli remap --node-list [NODE_ADDRESSES...]` ### Parameters - **SHARD_ID** (int) - The ID of the shard to reconfigure. - **VOTER_LIST** (string) - A list of node indices that will host the shard. An asterisk `*` denotes the leader. - **--node-list** (string) - A list of addresses for all nodes in the cluster. ### Example ```bash # Reconfigure shard 14: cluster = node1+node2+node4, node2 as leader (*) echo "14 [1] [2]* [4]" | sorock-cli remap \ --node-list http://node1:50000 http://node2:50000 http://node3:50000 http://node4:50000 ``` ``` -------------------------------- ### gRPC Read RPC Source: https://context7.com/akiradeveloper/lolraft/llms.txt The `Read` RPC submits a read-only query. Sorock applies the *read_index* optimization: instead of writing to the log, it records the current commit index at query time and waits until that index is applied before invoking `RaftApp::process_read`. This delivers linearizable reads with no log entries generated. ```APIDOC ## gRPC `Read` RPC — Query Without Log Overhead The `Read` RPC submits a read-only query. Sorock applies the *read_index* optimization: instead of writing to the log, it records the current commit index at query time and waits until that index is applied before invoking `RaftApp::process_read`. This delivers linearizable reads with no log entries generated. ```bash grpcurl -plaintext \ -d '{ "shard_id": 0, "message": "a2V5MQ==" }' \ 127.0.0.1:50051 sorock.Raft/Read # Expected response: # { "message": "" } ``` ``` -------------------------------- ### Remap Shard Membership with sorock-cli Source: https://context7.com/akiradeveloper/lolraft/llms.txt Reconfigures the membership for a specific shard. The format specifies the shard ID, followed by node indices, with an asterisk indicating the leader. ```bash # Reconfigure shard 14: cluster = node1+node2+node4, node2 as leader (*) echo "14 [1] [2]* [4]" | sorock-cli remap \ --node-list http://node1:50000 http://node2:50000 http://node3:50000 http://node4:50000 ``` -------------------------------- ### Add Node to Raft Cluster Source: https://context7.com/akiradeveloper/lolraft/llms.txt Adds a new server as a voter to a specified shard. Ensure the server is running and accessible. ```bash grpcurl -plaintext \ -d '{"shard_id": 0, "server_id": "http://node3:50051", "as_voter": true}' \ node1:50051 sorock.Raft/AddServer ``` -------------------------------- ### Update Shard Mapping Source: https://context7.com/akiradeveloper/lolraft/llms.txt Informs a node about which shards are hosted by another server. This RPC is used to propagate shard mapping state across the cluster. ```bash # Tell node1 that node2 hosts shards 3, 4, 5 grpcurl -plaintext \ -d '{"server_id": "http://node2:50051", "shard_indices": [3, 4, 5]}' \ node1:50051 sorock.Raft/UpdateShardMapping ``` -------------------------------- ### TimeoutNow Message Definition Source: https://github.com/akiradeveloper/lolraft/blob/master/book/src/leadership.md Defines the TimeoutNow message used to forcibly initiate a new election in a Raft cluster. This is useful for leadership transfer to avoid downtime. ```proto message TimeoutNow { uint32 shard_id = 1; } ``` -------------------------------- ### Remove Node from Raft Cluster Source: https://context7.com/akiradeveloper/lolraft/llms.txt Gracefully removes a server from a specified shard. This should be done before decommissioning the node. ```bash grpcurl -plaintext \ -d '{"shard_id": 0, "server_id": "http://node3:50051"}' \ node1:50051 sorock.Raft/RemoveServer ``` -------------------------------- ### Add Server to Raft Cluster Source: https://context7.com/akiradeveloper/lolraft/llms.txt Adds a new server to a specified shard as a voter. This operation is crucial for scaling the cluster or replacing nodes. ```APIDOC ## Add Server to Raft Cluster ### Description Adds a new server to a specified shard as a voter. This operation is crucial for scaling the cluster or replacing nodes. ### Method `grpcurl` (gRPC client) ### Endpoint `sorock.Raft/AddServer` ### Parameters #### Request Body - **shard_id** (int) - Required - The ID of the shard to which the server will be added. - **server_id** (string) - Required - The address of the server to add (e.g., "http://node3:50051"). - **as_voter** (bool) - Required - Specifies if the added server should be a voter. ### Request Example ```bash grpcurl -plaintext \ -d '{"shard_id": 0, "server_id": "http://node3:50051", "as_voter": true}' \ node1:50051 sorock.Raft/AddServer ``` ``` -------------------------------- ### Update Shard Mapping Source: https://context7.com/akiradeveloper/lolraft/llms.txt Updates the shard routing table on a node, informing it which shards are hosted by another specified server. This is used to propagate shard mapping state across the cluster. ```APIDOC ## Update Shard Mapping ### Description Updates the shard routing table on a node, informing it which shards are hosted by another specified server. This is used to propagate shard mapping state across the cluster. ### Method `grpcurl` (gRPC client) ### Endpoint `sorock.Raft/UpdateShardMapping` ### Parameters #### Request Body - **server_id** (string) - Required - The address of the server that hosts the specified shards. - **shard_indices** (array[int]) - Required - A list of shard IDs hosted by the `server_id`. ### Request Example ```bash grpcurl -plaintext \ -d '{"server_id": "http://node2:50051", "shard_indices": [3, 4, 5]}' \ node1:50051 sorock.Raft/UpdateShardMapping ``` ``` -------------------------------- ### Remove Server from Raft Cluster Source: https://context7.com/akiradeveloper/lolraft/llms.txt Gracefully removes a server from a specified shard. This is used for decommissioning nodes. ```APIDOC ## Remove Server from Raft Cluster ### Description Gracefully removes a server from a specified shard. This is used for decommissioning nodes. ### Method `grpcurl` (gRPC client) ### Endpoint `sorock.Raft/RemoveServer` ### Parameters #### Request Body - **shard_id** (int) - Required - The ID of the shard from which the server will be removed. - **server_id** (string) - Required - The address of the server to remove (e.g., "http://node3:50051"). ### Request Example ```bash grpcurl -plaintext \ -d '{"shard_id": 0, "server_id": "http://node3:50051"}' \ node1:50051 sorock.Raft/RemoveServer ``` ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.