Skip to main content

llm_optimizer_processor/storage/
config.rs

1//! Storage configuration
2
3use serde::{Deserialize, Serialize};
4use std::path::PathBuf;
5use std::time::Duration;
6
7/// Storage manager configuration
8#[derive(Debug, Clone, Serialize, Deserialize)]
9pub struct StorageConfig {
10    /// PostgreSQL configuration
11    pub postgresql: Option<PostgreSQLConfig>,
12
13    /// Redis configuration
14    pub redis: Option<RedisConfig>,
15
16    /// Sled configuration
17    pub sled: Option<SledConfig>,
18
19    /// Connection pool settings
20    pub pool: PoolConfig,
21
22    /// Retry settings
23    pub retry: RetryConfig,
24
25    /// Monitoring settings
26    pub monitoring: MonitoringConfig,
27}
28
29impl Default for StorageConfig {
30    fn default() -> Self {
31        Self {
32            postgresql: None,
33            redis: None,
34            sled: None,
35            pool: PoolConfig::default(),
36            retry: RetryConfig::default(),
37            monitoring: MonitoringConfig::default(),
38        }
39    }
40}
41
42/// PostgreSQL configuration
43#[derive(Debug, Clone, Serialize, Deserialize)]
44pub struct PostgreSQLConfig {
45    /// Database host
46    pub host: String,
47
48    /// Database port
49    pub port: u16,
50
51    /// Database name
52    pub database: String,
53
54    /// Username
55    pub username: String,
56
57    /// Password
58    pub password: String,
59
60    /// SSL mode
61    pub ssl_mode: SSLMode,
62
63    /// Connection timeout
64    pub connect_timeout: Duration,
65
66    /// Query timeout
67    pub query_timeout: Duration,
68
69    /// Enable migrations
70    pub enable_migrations: bool,
71
72    /// Migrations directory
73    pub migrations_dir: Option<PathBuf>,
74
75    /// Schema name
76    pub schema: String,
77
78    /// Application name
79    pub application_name: String,
80}
81
82impl Default for PostgreSQLConfig {
83    fn default() -> Self {
84        Self {
85            host: "localhost".to_string(),
86            port: 5432,
87            database: "llm_optimizer".to_string(),
88            username: "postgres".to_string(),
89            password: String::new(),
90            ssl_mode: SSLMode::Prefer,
91            connect_timeout: Duration::from_secs(10),
92            query_timeout: Duration::from_secs(30),
93            enable_migrations: true,
94            migrations_dir: None,
95            schema: "public".to_string(),
96            application_name: "llm-auto-optimizer".to_string(),
97        }
98    }
99}
100
101impl PostgreSQLConfig {
102    /// Build connection URL
103    pub fn connection_url(&self) -> String {
104        format!(
105            "postgresql://{}:{}@{}:{}/{}?application_name={}",
106            self.username, self.password, self.host, self.port, self.database, self.application_name
107        )
108    }
109}
110
111/// SSL mode for PostgreSQL
112#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
113pub enum SSLMode {
114    Disable,
115    Prefer,
116    Require,
117    VerifyCA,
118    VerifyFull,
119}
120
121/// Redis configuration
122#[derive(Debug, Clone, Serialize, Deserialize)]
123pub struct RedisConfig {
124    /// Redis host
125    pub host: String,
126
127    /// Redis port
128    pub port: u16,
129
130    /// Database number (0-15)
131    pub database: u8,
132
133    /// Password (if required)
134    pub password: Option<String>,
135
136    /// Username (Redis 6+)
137    pub username: Option<String>,
138
139    /// Connection timeout
140    pub connect_timeout: Duration,
141
142    /// Command timeout
143    pub command_timeout: Duration,
144
145    /// Enable cluster mode
146    pub cluster_mode: bool,
147
148    /// Cluster nodes (if cluster_mode = true)
149    pub cluster_nodes: Vec<String>,
150
151    /// Key prefix for namespacing
152    pub key_prefix: String,
153
154    /// Default TTL for entries (seconds)
155    pub default_ttl: Option<i64>,
156
157    /// Enable pub/sub
158    pub enable_pubsub: bool,
159}
160
161impl Default for RedisConfig {
162    fn default() -> Self {
163        Self {
164            host: "localhost".to_string(),
165            port: 6379,
166            database: 0,
167            password: None,
168            username: None,
169            connect_timeout: Duration::from_secs(5),
170            command_timeout: Duration::from_secs(10),
171            cluster_mode: false,
172            cluster_nodes: Vec::new(),
173            key_prefix: "llm_optimizer:".to_string(),
174            default_ttl: None,
175            enable_pubsub: false,
176        }
177    }
178}
179
180impl RedisConfig {
181    /// Build connection URL
182    pub fn connection_url(&self) -> String {
183        let auth = if let Some(ref username) = self.username {
184            if let Some(ref password) = self.password {
185                format!("{}:{}@", username, password)
186            } else {
187                format!("{}@", username)
188            }
189        } else if let Some(ref password) = self.password {
190            format!(":{}@", password)
191        } else {
192            String::new()
193        };
194
195        format!(
196            "redis://{}{}:{}/{}",
197            auth, self.host, self.port, self.database
198        )
199    }
200}
201
202/// Sled configuration
203#[derive(Debug, Clone, Serialize, Deserialize)]
204pub struct SledConfig {
205    /// Database path
206    pub path: PathBuf,
207
208    /// Cache size in bytes
209    pub cache_capacity_bytes: u64,
210
211    /// Enable compression
212    pub use_compression: bool,
213
214    /// Flush interval
215    pub flush_every_ms: Option<u64>,
216
217    /// Mode (high throughput or low space)
218    pub mode: SledMode,
219
220    /// Enable temporary mode (no durability)
221    pub temporary: bool,
222
223    /// Create directory if missing
224    pub create_dir: bool,
225}
226
227impl Default for SledConfig {
228    fn default() -> Self {
229        Self {
230            path: PathBuf::from("./data/sled"),
231            cache_capacity_bytes: 1024 * 1024 * 1024, // 1 GB
232            use_compression: true,
233            flush_every_ms: Some(1000),
234            mode: SledMode::HighThroughput,
235            temporary: false,
236            create_dir: true,
237        }
238    }
239}
240
241/// Sled operation mode
242#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
243pub enum SledMode {
244    /// Optimize for throughput
245    HighThroughput,
246    /// Optimize for low space usage
247    LowSpace,
248}
249
250/// Connection pool configuration
251#[derive(Debug, Clone, Serialize, Deserialize)]
252pub struct PoolConfig {
253    /// Minimum connections
254    pub min_connections: u32,
255
256    /// Maximum connections
257    pub max_connections: u32,
258
259    /// Connection idle timeout
260    pub idle_timeout: Duration,
261
262    /// Maximum connection lifetime
263    pub max_lifetime: Duration,
264
265    /// Connection acquire timeout
266    pub acquire_timeout: Duration,
267}
268
269impl Default for PoolConfig {
270    fn default() -> Self {
271        Self {
272            min_connections: 2,
273            max_connections: 10,
274            idle_timeout: Duration::from_secs(600), // 10 minutes
275            max_lifetime: Duration::from_secs(1800), // 30 minutes
276            acquire_timeout: Duration::from_secs(30),
277        }
278    }
279}
280
281/// Retry configuration
282#[derive(Debug, Clone, Serialize, Deserialize)]
283pub struct RetryConfig {
284    /// Enable retries
285    pub enabled: bool,
286
287    /// Maximum retry attempts
288    pub max_attempts: usize,
289
290    /// Initial retry delay
291    pub initial_delay: Duration,
292
293    /// Maximum retry delay
294    pub max_delay: Duration,
295
296    /// Exponential backoff multiplier
297    pub backoff_multiplier: f64,
298
299    /// Jitter factor (0.0-1.0)
300    pub jitter_factor: f64,
301}
302
303impl Default for RetryConfig {
304    fn default() -> Self {
305        Self {
306            enabled: true,
307            max_attempts: 3,
308            initial_delay: Duration::from_millis(100),
309            max_delay: Duration::from_secs(10),
310            backoff_multiplier: 2.0,
311            jitter_factor: 0.2,
312        }
313    }
314}
315
316impl RetryConfig {
317    /// Calculate delay for retry attempt
318    pub fn delay_for_attempt(&self, attempt: usize) -> Duration {
319        if attempt == 0 || !self.enabled {
320            return Duration::from_secs(0);
321        }
322
323        // Exponential backoff
324        let delay_ms = self.initial_delay.as_millis() as f64
325            * self.backoff_multiplier.powi((attempt - 1) as i32);
326
327        let delay_ms = delay_ms.min(self.max_delay.as_millis() as f64);
328
329        // Add jitter
330        let jitter = delay_ms * self.jitter_factor * (rand::random::<f64>() - 0.5);
331        let final_delay_ms = (delay_ms + jitter).max(0.0);
332
333        Duration::from_millis(final_delay_ms as u64)
334    }
335}
336
337/// Monitoring configuration
338#[derive(Debug, Clone, Serialize, Deserialize)]
339pub struct MonitoringConfig {
340    /// Enable metrics collection
341    pub enable_metrics: bool,
342
343    /// Metrics collection interval
344    pub metrics_interval: Duration,
345
346    /// Enable health checks
347    pub enable_health_checks: bool,
348
349    /// Health check interval
350    pub health_check_interval: Duration,
351
352    /// Enable query logging
353    pub enable_query_logging: bool,
354
355    /// Slow query threshold
356    pub slow_query_threshold: Duration,
357
358    /// Enable connection pool monitoring
359    pub enable_pool_monitoring: bool,
360}
361
362impl Default for MonitoringConfig {
363    fn default() -> Self {
364        Self {
365            enable_metrics: true,
366            metrics_interval: Duration::from_secs(60),
367            enable_health_checks: true,
368            health_check_interval: Duration::from_secs(30),
369            enable_query_logging: true,
370            slow_query_threshold: Duration::from_millis(1000),
371            enable_pool_monitoring: true,
372        }
373    }
374}