feox_server/
config.rs

1use serde::{Deserialize, Serialize};
2use std::fs;
3use std::path::Path;
4
5/// Server configuration
6#[derive(Debug, Clone, Serialize, Deserialize)]
7pub struct Config {
8    /// Bind address
9    pub bind_addr: String,
10
11    /// Port to listen on
12    pub port: u16,
13
14    /// Number of worker threads
15    pub threads: usize,
16
17    /// Path to FeOx data file (None for memory-only)
18    pub data_path: Option<String>,
19
20    /// Maximum connections per thread
21    pub max_connections_per_thread: usize,
22
23    /// Connection buffer size (per connection)
24    pub connection_buffer_size: usize,
25
26    /// TCP nodelay
27    pub tcp_nodelay: bool,
28
29    /// Pipeline queue depth
30    pub max_pipeline_depth: usize,
31
32    /// Enable NUMA awareness
33    pub numa_aware: bool,
34
35    /// Maximum memory for FeOx store (per shard)
36    pub max_memory_per_shard: Option<usize>,
37
38    /// Enable TTL support
39    pub enable_ttl: bool,
40
41    /// File size for persistent storage (in bytes)
42    /// Only used when data_path is set
43    pub file_size: Option<u64>,
44
45    /// Log level
46    pub log_level: String,
47}
48
49impl Default for Config {
50    fn default() -> Self {
51        Self {
52            bind_addr: "127.0.0.1".to_string(),
53            port: 6379,
54            threads: num_cpus::get(),
55            data_path: None,
56            max_connections_per_thread: 10000,
57            connection_buffer_size: 16 * 1024, // 16KB
58            tcp_nodelay: true,
59            max_pipeline_depth: 1000,
60            numa_aware: false,
61            max_memory_per_shard: Some(1024 * 1024 * 1024), // 1GB per shard
62            enable_ttl: true,
63            file_size: Some(10 * 1024 * 1024 * 1024), // 10GB default for persistent storage
64            log_level: "info".to_string(),
65        }
66    }
67}
68
69impl Config {
70    /// Load configuration from a TOML file
71    ///
72    /// # Example
73    ///
74    /// ```no_run
75    /// use feox_server::Config;
76    ///
77    /// # fn main() -> anyhow::Result<()> {
78    /// let config = Config::from_file("config.toml")?;
79    /// # Ok(())
80    /// # }
81    /// ```
82    pub fn from_file<P: AsRef<Path>>(path: P) -> anyhow::Result<Self> {
83        let contents = fs::read_to_string(path)?;
84        let config = toml::from_str(&contents)?;
85        Ok(config)
86    }
87
88    /// Save configuration to a TOML file
89    pub fn to_file<P: AsRef<Path>>(&self, path: P) -> anyhow::Result<()> {
90        let contents = toml::to_string_pretty(self)?;
91        fs::write(path, contents)?;
92        Ok(())
93    }
94
95    /// Validate configuration
96    pub fn validate(&self) -> anyhow::Result<()> {
97        if self.threads == 0 {
98            anyhow::bail!("threads must be > 0");
99        }
100
101        if self.port == 0 {
102            anyhow::bail!("port must be > 0");
103        }
104
105        if self.connection_buffer_size < 1024 {
106            anyhow::bail!("connection_buffer_size must be >= 1024");
107        }
108
109        Ok(())
110    }
111}