Manages the ra Raft cluster for FerricStore shards.
Each shard is an independent Raft group with its own leader. In single-node mode (development, testing), each group has exactly one member -- self quorum.
This module provides functions to:
- Start the ra system
- Start individual shard ra servers
- Build ra server IDs and configurations
Deployment topology (per spec section 2.6)
Single node: each shard's Raft group has one member. Writes are durable after local log append + fsync. No network round trip needed.
Three-node cluster: each shard's Raft group has three members. Writes require quorum (2 of 3) acknowledgement before commit.
Summary
Functions
Adds a node to an existing shard's Raft group.
Starts a ra server that joins an existing Raft group as a follower.
Returns the current members and leader for a shard's Raft group.
Removes a node from a shard's Raft group.
Returns the ra server ID for a shard.
Returns the ra server ID for a shard on a specific node.
Starts a ra server for a single shard.
Starts the ra system for FerricStore.
Stops and deletes the ra server for a shard.
Returns the ra system name used by FerricStore.
Transfers leadership of a shard to a specific node.
Functions
@spec add_member(non_neg_integer(), node(), atom()) :: :ok | {:error, term()}
Adds a node to an existing shard's Raft group.
The membership determines the node's role:
:voter— full quorum member (default):promotable— receives replication, can be promoted to voter:non_voter— permanent read-only, never promoted
Parameters
shard_index— zero-based shard indexnode— the Erlang node to addmembership—:voter,:promotable, or:non_voter(default::voter)
@spec join_shard_server( non_neg_integer(), binary(), non_neg_integer(), binary(), atom(), [node()], keyword() ) :: :ok | {:error, term()}
Starts a ra server that joins an existing Raft group as a follower.
Unlike start_shard_server/6 which may create a new single-node group,
this function configures initial_members with the provided cluster members
so ra knows to join the existing group. Used when a new node joins an
already-running cluster after data sync.
@spec members(non_neg_integer()) :: {:ok, list(), term()} | {:error, term()}
Returns the current members and leader for a shard's Raft group.
@spec remove_member(non_neg_integer(), node()) :: :ok | {:error, term()}
Removes a node from a shard's Raft group.
@spec shard_server_id(non_neg_integer()) :: :ra.server_id()
Returns the ra server ID for a shard.
The server ID is a {name, node()} tuple as required by ra.
Examples
iex> Ferricstore.Raft.Cluster.shard_server_id(0)
{:"ferricstore_shard_0", node()}
@spec shard_server_id_on(non_neg_integer(), node()) :: :ra.server_id()
Returns the ra server ID for a shard on a specific node.
@spec start_shard_server( non_neg_integer(), binary(), non_neg_integer(), binary(), atom(), keyword() ) :: :ok | {:error, term()}
Starts a ra server for a single shard.
In single-node mode, creates a self-quorum Raft group. In cluster mode, uses the configured cluster_nodes as initial_members so all nodes form a single Raft group per shard.
The membership option controls this node's role in the group:
:voter— full quorum member (default):promotable— receives replication, can be promoted:non_voter— permanent read-only
Parameters
shard_index-- zero-based shard indexshard_data_path-- path to shard's Bitcask data directoryactive_file_id-- current active log file IDactive_file_path-- path to current active log fileets-- ETS table name (already created)
Returns
:okon success{:error, reason}on failure
Starts the ra system for FerricStore.
Must be called before any ra servers are started. The data directory
for ra's WAL and segment files is placed under data_dir/ra.
Parameters
data_dir-- base data directory for FerricStore
@spec stop_shard_server(non_neg_integer()) :: :ok | {:error, term()}
Stops and deletes the ra server for a shard.
Used during shard restarts and in test cleanup.
Parameters
shard_index-- zero-based shard index
@spec system_name() :: atom()
Returns the ra system name used by FerricStore.
@spec transfer_leadership(non_neg_integer(), node()) :: :ok | {:error, term()}
Transfers leadership of a shard to a specific node.