use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DistributedCoherenceConfig {
pub node_id: String,
pub cluster_members: Vec<String>,
pub dimension: usize,
pub election_timeout_min: u64,
pub election_timeout_max: u64,
pub heartbeat_interval: u64,
pub max_entries_per_message: usize,
pub snapshot_chunk_size: usize,
pub coherence_threshold: f32,
pub sync_interval: u64,
pub enable_checkpoints: bool,
pub checkpoint_interval: usize,
pub replication_factor: usize,
}
impl Default for DistributedCoherenceConfig {
fn default() -> Self {
Self {
node_id: "node0".to_string(),
cluster_members: vec!["node0".to_string()],
dimension: 64,
election_timeout_min: 150,
election_timeout_max: 300,
heartbeat_interval: 50,
max_entries_per_message: 100,
snapshot_chunk_size: 64 * 1024,
coherence_threshold: 0.01,
sync_interval: 100,
enable_checkpoints: true,
checkpoint_interval: 1000,
replication_factor: 3,
}
}
}
impl DistributedCoherenceConfig {
pub fn single_node(node_id: &str) -> Self {
Self {
node_id: node_id.to_string(),
cluster_members: vec![node_id.to_string()],
replication_factor: 1,
..Default::default()
}
}
pub fn three_node_cluster(node_id: &str, members: Vec<String>) -> Self {
assert!(members.len() >= 3, "Need at least 3 members for 3-node cluster");
Self {
node_id: node_id.to_string(),
cluster_members: members,
replication_factor: 3,
..Default::default()
}
}
pub fn five_node_cluster(node_id: &str, members: Vec<String>) -> Self {
assert!(members.len() >= 5, "Need at least 5 members for 5-node cluster");
Self {
node_id: node_id.to_string(),
cluster_members: members,
replication_factor: 5,
..Default::default()
}
}
pub fn validate(&self) -> Result<(), String> {
if self.node_id.is_empty() {
return Err("node_id cannot be empty".to_string());
}
if self.cluster_members.is_empty() {
return Err("cluster_members cannot be empty".to_string());
}
if !self.cluster_members.contains(&self.node_id) {
return Err("node_id must be in cluster_members".to_string());
}
if self.election_timeout_min >= self.election_timeout_max {
return Err("election_timeout_min must be less than election_timeout_max".to_string());
}
if self.heartbeat_interval >= self.election_timeout_min {
return Err("heartbeat_interval must be less than election_timeout_min".to_string());
}
if self.replication_factor > self.cluster_members.len() {
return Err("replication_factor cannot exceed cluster size".to_string());
}
Ok(())
}
pub fn quorum_size(&self) -> usize {
self.cluster_members.len() / 2 + 1
}
pub fn is_single_node(&self) -> bool {
self.cluster_members.len() == 1
}
pub fn max_failures(&self) -> usize {
self.cluster_members.len().saturating_sub(self.quorum_size())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum NodeRole {
Follower,
Candidate,
Leader,
}
impl NodeRole {
pub fn is_leader(&self) -> bool {
matches!(self, Self::Leader)
}
pub fn can_write(&self) -> bool {
matches!(self, Self::Leader)
}
pub fn name(&self) -> &'static str {
match self {
Self::Follower => "follower",
Self::Candidate => "candidate",
Self::Leader => "leader",
}
}
}
impl std::fmt::Display for NodeRole {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.name())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_default_config() {
let config = DistributedCoherenceConfig::default();
assert!(config.validate().is_ok());
}
#[test]
fn test_single_node_config() {
let config = DistributedCoherenceConfig::single_node("node1");
assert!(config.validate().is_ok());
assert!(config.is_single_node());
assert_eq!(config.quorum_size(), 1);
}
#[test]
fn test_three_node_config() {
let members = vec!["n1".to_string(), "n2".to_string(), "n3".to_string()];
let config = DistributedCoherenceConfig::three_node_cluster("n1", members);
assert!(config.validate().is_ok());
assert_eq!(config.quorum_size(), 2);
assert_eq!(config.max_failures(), 1);
}
#[test]
fn test_invalid_config() {
let config = DistributedCoherenceConfig {
node_id: "node1".to_string(),
cluster_members: vec!["node2".to_string()], ..Default::default()
};
assert!(config.validate().is_err());
}
#[test]
fn test_node_role() {
assert!(NodeRole::Leader.is_leader());
assert!(NodeRole::Leader.can_write());
assert!(!NodeRole::Follower.is_leader());
assert!(!NodeRole::Follower.can_write());
}
}