d_engine/config/
cluster.rs1use std::net::SocketAddr;
2use std::path::PathBuf;
3
4use config::ConfigError;
5use serde::Deserialize;
6use serde::Serialize;
7
8use super::validate_directory;
9use crate::proto::cluster::NodeMeta;
10use crate::proto::common::NodeStatus;
11use crate::Error;
12use crate::Result;
13use crate::FOLLOWER;
14
15#[derive(Debug, Serialize, Deserialize, Clone)]
25pub struct ClusterConfig {
26 #[serde(default = "default_node_id")]
30 pub node_id: u32,
31
32 #[serde(default = "default_listen_addr")]
36 pub listen_address: SocketAddr,
37
38 #[serde(default = "default_initial_cluster")]
45 pub initial_cluster: Vec<NodeMeta>,
46
47 #[serde(default = "default_db_dir")]
51 pub db_root_dir: PathBuf,
52
53 #[serde(default = "default_log_dir")]
57 pub log_dir: PathBuf,
58}
59impl Default for ClusterConfig {
60 fn default() -> Self {
61 Self {
62 node_id: default_node_id(),
63 listen_address: default_listen_addr(),
64 initial_cluster: vec![],
65 db_root_dir: default_db_dir(),
66 log_dir: default_log_dir(),
67 }
68 }
69}
70
71impl ClusterConfig {
72 pub fn validate(&self) -> Result<()> {
76 if self.node_id == 0 {
78 return Err(Error::Config(ConfigError::Message(
79 "node_id cannot be 0 (reserved for invalid nodes)".into(),
80 )));
81 }
82
83 if self.initial_cluster.is_empty() {
85 return Err(Error::Config(ConfigError::Message(
86 "initial_cluster must contain at least one node".into(),
87 )));
88 }
89
90 let self_in_cluster = self.initial_cluster.iter().any(|n| n.id == self.node_id);
92 if !self_in_cluster {
93 return Err(Error::Config(ConfigError::Message(format!(
94 "Current node {} not found in initial_cluster",
95 self.node_id
96 ))));
97 }
98
99 let mut ids = std::collections::HashSet::new();
101 for node in &self.initial_cluster {
102 if !ids.insert(node.id) {
103 return Err(Error::Config(ConfigError::Message(format!(
104 "Duplicate node_id {} in initial_cluster",
105 node.id
106 ))));
107 }
108 }
109
110 if self.listen_address.port() == 0 {
112 return Err(Error::Config(ConfigError::Message(
113 "listen_address must specify a non-zero port".into(),
114 )));
115 }
116
117 validate_directory(&self.db_root_dir, "db_root_dir")?;
119 validate_directory(&self.log_dir, "log_dir")?;
120
121 Ok(())
122 }
123}
124
125fn default_node_id() -> u32 {
126 1
127}
128fn default_initial_cluster() -> Vec<NodeMeta> {
129 vec![NodeMeta {
130 id: 1,
131 address: "127.0.0.1:8080".to_string(),
132 role: FOLLOWER,
133 status: NodeStatus::Active.into(),
134 }]
135}
136fn default_listen_addr() -> SocketAddr {
137 "127.0.0.1:9081".parse().unwrap()
138}
139fn default_db_dir() -> PathBuf {
140 PathBuf::from("/tmp/db")
141}
142fn default_log_dir() -> PathBuf {
143 PathBuf::from("/tmp/logs")
144}