oxirs_vec/tiering/
config.rs1use super::policies::TieringPolicy;
4use super::types::{GradualTransitionConfig, TierCostModel};
5use serde::{Deserialize, Serialize};
6use std::path::PathBuf;
7use std::time::Duration;
8
9#[derive(Debug, Clone, Serialize, Deserialize)]
11pub struct TieringConfig {
12 pub hot_tier_capacity_gb: f64,
14 pub warm_tier_capacity_gb: f64,
16 pub cold_tier_capacity_gb: f64,
18 pub policy: TieringPolicy,
20 pub storage_base_path: PathBuf,
22 pub auto_tier_management: bool,
24 pub evaluation_interval: Duration,
26 pub hot_tier_utilization_threshold: f64,
28 pub warm_tier_utilization_threshold: f64,
30 pub hot_tier_qps_threshold: f64,
32 pub warm_tier_qps_threshold: f64,
34 pub min_time_in_tier: Duration,
36 pub gradual_transition: GradualTransitionConfig,
38 pub cost_model: TierCostModel,
40 pub enable_predictive_management: bool,
42 pub enable_multi_tenancy: bool,
44 pub max_concurrent_transitions: usize,
46 pub enable_metrics: bool,
48 pub metrics_retention: Duration,
50 pub warm_tier_compression: bool,
52 pub cold_tier_compression: bool,
54 pub warm_tier_compression_level: i32,
56 pub cold_tier_compression_level: i32,
58}
59
60impl Default for TieringConfig {
61 fn default() -> Self {
62 Self {
63 hot_tier_capacity_gb: 16.0,
64 warm_tier_capacity_gb: 128.0,
65 cold_tier_capacity_gb: 1024.0,
66 policy: TieringPolicy::Adaptive,
67 storage_base_path: PathBuf::from("/var/lib/oxirs/tiered-storage"),
68 auto_tier_management: true,
69 evaluation_interval: Duration::from_secs(300), hot_tier_utilization_threshold: 0.8, warm_tier_utilization_threshold: 0.9, hot_tier_qps_threshold: 10.0, warm_tier_qps_threshold: 1.0, min_time_in_tier: Duration::from_secs(3600), gradual_transition: GradualTransitionConfig::default(),
76 cost_model: TierCostModel::default(),
77 enable_predictive_management: true,
78 enable_multi_tenancy: false,
79 max_concurrent_transitions: 4,
80 enable_metrics: true,
81 metrics_retention: Duration::from_secs(7 * 24 * 3600), warm_tier_compression: true,
83 cold_tier_compression: true,
84 warm_tier_compression_level: 6,
85 cold_tier_compression_level: 19,
86 }
87 }
88}
89
90impl TieringConfig {
91 pub fn validate(&self) -> anyhow::Result<()> {
93 if self.hot_tier_capacity_gb <= 0.0 {
94 anyhow::bail!("Hot tier capacity must be positive");
95 }
96 if self.warm_tier_capacity_gb <= 0.0 {
97 anyhow::bail!("Warm tier capacity must be positive");
98 }
99 if self.cold_tier_capacity_gb <= 0.0 {
100 anyhow::bail!("Cold tier capacity must be positive");
101 }
102 if self.hot_tier_utilization_threshold <= 0.0 || self.hot_tier_utilization_threshold > 1.0 {
103 anyhow::bail!("Hot tier utilization threshold must be in (0.0, 1.0]");
104 }
105 if self.warm_tier_utilization_threshold <= 0.0 || self.warm_tier_utilization_threshold > 1.0
106 {
107 anyhow::bail!("Warm tier utilization threshold must be in (0.0, 1.0]");
108 }
109 if self.hot_tier_qps_threshold < 0.0 {
110 anyhow::bail!("Hot tier QPS threshold must be non-negative");
111 }
112 if self.warm_tier_qps_threshold < 0.0 {
113 anyhow::bail!("Warm tier QPS threshold must be non-negative");
114 }
115 if self.max_concurrent_transitions == 0 {
116 anyhow::bail!("Max concurrent transitions must be at least 1");
117 }
118 if self.warm_tier_compression_level < 1 || self.warm_tier_compression_level > 22 {
119 anyhow::bail!("Warm tier compression level must be in [1, 22]");
120 }
121 if self.cold_tier_compression_level < 1 || self.cold_tier_compression_level > 22 {
122 anyhow::bail!("Cold tier compression level must be in [1, 22]");
123 }
124 Ok(())
125 }
126
127 pub fn development() -> Self {
129 Self {
130 hot_tier_capacity_gb: 1.0,
131 warm_tier_capacity_gb: 8.0,
132 cold_tier_capacity_gb: 64.0,
133 storage_base_path: PathBuf::from("/tmp/oxirs-tiered-storage"),
134 evaluation_interval: Duration::from_secs(60), ..Default::default()
136 }
137 }
138
139 pub fn production() -> Self {
141 Self {
142 hot_tier_capacity_gb: 64.0,
143 warm_tier_capacity_gb: 512.0,
144 cold_tier_capacity_gb: 4096.0,
145 evaluation_interval: Duration::from_secs(600), min_time_in_tier: Duration::from_secs(7200), enable_predictive_management: true,
148 ..Default::default()
149 }
150 }
151
152 pub fn total_capacity_bytes(&self) -> u64 {
154 ((self.hot_tier_capacity_gb + self.warm_tier_capacity_gb + self.cold_tier_capacity_gb)
155 * 1024.0
156 * 1024.0
157 * 1024.0) as u64
158 }
159
160 pub fn hot_tier_capacity_bytes(&self) -> u64 {
162 (self.hot_tier_capacity_gb * 1024.0 * 1024.0 * 1024.0) as u64
163 }
164
165 pub fn warm_tier_capacity_bytes(&self) -> u64 {
167 (self.warm_tier_capacity_gb * 1024.0 * 1024.0 * 1024.0) as u64
168 }
169
170 pub fn cold_tier_capacity_bytes(&self) -> u64 {
172 (self.cold_tier_capacity_gb * 1024.0 * 1024.0 * 1024.0) as u64
173 }
174}
175
176#[cfg(test)]
177mod tests {
178 use super::*;
179
180 #[test]
181 fn test_default_config_is_valid() {
182 let config = TieringConfig::default();
183 assert!(config.validate().is_ok());
184 }
185
186 #[test]
187 fn test_development_config_is_valid() {
188 let config = TieringConfig::development();
189 assert!(config.validate().is_ok());
190 }
191
192 #[test]
193 fn test_production_config_is_valid() {
194 let config = TieringConfig::production();
195 assert!(config.validate().is_ok());
196 }
197
198 #[test]
199 fn test_invalid_capacity() {
200 let config = TieringConfig {
201 hot_tier_capacity_gb: -1.0,
202 ..Default::default()
203 };
204 assert!(config.validate().is_err());
205 }
206
207 #[test]
208 fn test_invalid_threshold() {
209 let config = TieringConfig {
210 hot_tier_utilization_threshold: 1.5,
211 ..Default::default()
212 };
213 assert!(config.validate().is_err());
214 }
215
216 #[test]
217 fn test_capacity_calculations() {
218 let config = TieringConfig {
219 hot_tier_capacity_gb: 1.0,
220 warm_tier_capacity_gb: 2.0,
221 cold_tier_capacity_gb: 3.0,
222 ..Default::default()
223 };
224
225 assert_eq!(config.hot_tier_capacity_bytes(), 1073741824); assert_eq!(config.warm_tier_capacity_bytes(), 2147483648); assert_eq!(config.cold_tier_capacity_bytes(), 3221225472); assert_eq!(config.total_capacity_bytes(), 6442450944); }
230}